Skip to content

Commit 4ed2a4a

Browse files
Encapsulate qsharp.estimate into Circuit (#428)
1 parent 5bc3f37 commit 4ed2a4a

5 files changed

Lines changed: 95 additions & 11 deletions

File tree

docs/source/conf.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,7 @@
206206
(r"py:class", r"qdk::chemistry::data::SumPauliOperatorExpression"),
207207
(r"py:class", r"qdk::chemistry::algorithms::HamiltonianConstructor"),
208208
(r"py:class", r"^SumPauliOperatorExpression$"),
209-
(r"py:class", r"qsharp._native.*"),
210-
(r"py:class", r"qsharp._qsharp.*"),
209+
(r"py:class", r"qsharp\..*"), # qsharp has no intersphinx inventory
211210
]
212211

213212
# Configure output for to-dos

examples/qpe_stretched_n2.ipynb

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,6 @@
323323
"outputs": [],
324324
"source": [
325325
"import qdk_chemistry.plugins.qiskit # Enable Qiskit plugin capabilities # noqa: F401\n",
326-
"from qdk.openqasm import estimate\n",
327326
"from qdk.widgets import Circuit\n",
328327
"\n",
329328
"# Generate state preparation circuit for the sparse state using the regular isometry method (Qiskit)\n",
@@ -335,7 +334,7 @@
335334
"\n",
336335
"# Print logical qubit counts estimated from the circuit\n",
337336
"df = pd.DataFrame(\n",
338-
" estimate(regular_isometry_circuit.get_qasm()).logical_counts.items(),\n",
337+
" regular_isometry_circuit.estimate().logical_counts.items(),\n",
339338
" columns=['Logical Estimate', 'Counts']\n",
340339
")\n",
341340
"display(df)"
@@ -364,7 +363,14 @@
364363
"sparse_isometry_circuit = state_prep.run(wfn_trial)\n",
365364
"\n",
366365
"# Visualize the sparse isometry circuit, idle and classical qubits are removed\n",
367-
"display(Circuit(sparse_isometry_circuit.get_qsharp_circuit()))"
366+
"display(Circuit(sparse_isometry_circuit.get_qsharp_circuit()))\n",
367+
"\n",
368+
"# Print logical qubit counts estimated from the circuit\n",
369+
"df = pd.DataFrame(\n",
370+
" sparse_isometry_circuit.estimate().logical_counts.items(),\n",
371+
" columns=['Logical Estimate', 'Counts']\n",
372+
")\n",
373+
"display(df)"
368374
]
369375
},
370376
{

examples/state_prep_energy.ipynb

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,6 @@
304304
"outputs": [],
305305
"source": [
306306
"import pandas as pd\n",
307-
"from qdk.openqasm import estimate\n",
308307
"from qdk.widgets import Circuit\n",
309308
"\n",
310309
"# Generate state preparation circuit for the sparse state using the regular isometry method (Qiskit)\n",
@@ -315,7 +314,7 @@
315314
"display(Circuit(regular_isometry_circuit.get_qsharp_circuit()))\n",
316315
"\n",
317316
"# Print logical qubit counts estimated from the circuit\n",
318-
"df = pd.DataFrame(estimate(regular_isometry_circuit.get_qasm()).logical_counts.items(), columns=['Logical Estimate', 'Counts'])\n",
317+
"df = pd.DataFrame(regular_isometry_circuit.estimate().logical_counts.items(), columns=['Logical Estimate', 'Counts'])\n",
319318
"display(df)"
320319
]
321320
},
@@ -342,7 +341,6 @@
342341
"source": [
343342
"import pandas as pd\n",
344343
"from qdk.widgets import Circuit\n",
345-
"import qsharp\n",
346344
"\n",
347345
"# Generate state preparation circuit for the sparse state via sparse isometry (GF2 + X)\n",
348346
"state_prep = create(\"state_prep\", \"sparse_isometry_gf2x\")\n",
@@ -353,9 +351,7 @@
353351
"\n",
354352
"# Print logical qubit counts estimated from the circuit\n",
355353
"df = pd.DataFrame(\n",
356-
" qsharp.estimate(\n",
357-
" sparse_isometry_circuit._qsharp_factory.program, None, *sparse_isometry_circuit._qsharp_factory.parameter.values()\n",
358-
" ).logical_counts.items(), columns=['Logical Estimate', 'Counts'])\n",
354+
" sparse_isometry_circuit.estimate().logical_counts.items(), columns=['Logical Estimate', 'Counts'])\n",
359355
"display(df)"
360356
]
361357
},

python/src/qdk_chemistry/data/circuit.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import h5py
2121
import qsharp._native
22+
import qsharp.estimator
2223
import qsharp.openqasm
2324
from qsharp.openqasm import OutputSemantics
2425

@@ -192,6 +193,33 @@ def get_qsharp_circuit(self, prune_classical_qubits: bool = False) -> qsharp._na
192193

193194
raise RuntimeError("The quantum circuit is not set in a Q# format.")
194195

196+
def estimate(
197+
self,
198+
params: dict[str, Any] | list[Any] | qsharp.estimator.EstimatorParams | None = None,
199+
) -> qsharp.estimator.EstimatorResult:
200+
"""Estimate resources for the quantum circuit.
201+
202+
Args:
203+
params: Resource estimation parameters. Accepts a dict, list, or ``qsharp.estimator.EstimatorParams``.
204+
205+
Returns:
206+
qsharp.estimator.EstimatorResult: The estimated resources.
207+
208+
Raises:
209+
RuntimeError: If no suitable circuit representation is available for estimation.
210+
211+
"""
212+
if self._qsharp_factory is not None:
213+
return qsharp.estimate(
214+
self._qsharp_factory.program,
215+
params,
216+
*self._qsharp_factory.parameter.values(),
217+
)
218+
if self.qasm is not None:
219+
return qsharp.openqasm.estimate(self.qasm, params)
220+
221+
raise RuntimeError("Cannot estimate resources: no Q# factory data or QASM representation is available.")
222+
195223
def get_qiskit_circuit(self):
196224
"""Convert the Circuit to a Qiskit QuantumCircuit.
197225

python/tests/test_circuit.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,3 +408,58 @@ def test_cannot_add_new_attributes(self):
408408
# Attempting to add a new attribute should raise an error
409409
with pytest.raises(AttributeError):
410410
circuit.new_attr = "value"
411+
412+
413+
class TestCircuitEstimate:
414+
"""Test cases for Circuit.estimate method."""
415+
416+
def test_estimate_from_factory(self):
417+
"""Test that estimate works with Q# factory data."""
418+
state_prep_params = {
419+
"rowMap": [1, 0],
420+
"stateVector": [0.6, 0.0, 0.0, 0.8],
421+
"expansionOps": [],
422+
"numQubits": 2,
423+
}
424+
qsharp_factory = QsharpFactoryData(
425+
program=QSHARP_UTILS.StatePreparation.MakeStatePreparationCircuit,
426+
parameter=state_prep_params,
427+
)
428+
circuit = Circuit(qsharp_factory=qsharp_factory)
429+
result = circuit.estimate()
430+
assert result is not None
431+
assert hasattr(result, "logical_counts")
432+
433+
def test_estimate_from_qasm(self):
434+
"""Test that estimate works with QASM representation."""
435+
qasm_with_t = """
436+
OPENQASM 3.0;
437+
include "stdgates.inc";
438+
qubit[2] q;
439+
bit[2] c;
440+
h q[0];
441+
t q[0];
442+
cx q[0], q[1];
443+
c[0] = measure q[0];
444+
c[1] = measure q[1];
445+
"""
446+
circuit = Circuit(qasm=qasm_with_t)
447+
result = circuit.estimate()
448+
assert result is not None
449+
assert hasattr(result, "logical_counts")
450+
451+
def test_estimate_raises_with_qir_only(self):
452+
"""Test that estimate raises when only QIR representation is available."""
453+
qir = qsharp.openqasm.compile("""
454+
OPENQASM 3.0;
455+
include "stdgates.inc";
456+
qubit[2] q;
457+
bit[2] c;
458+
h q[0];
459+
cx q[0], q[1];
460+
c[0] = measure q[0];
461+
c[1] = measure q[1];
462+
""")
463+
circuit = Circuit(qir=qir)
464+
with pytest.raises(RuntimeError, match="Cannot estimate resources"):
465+
circuit.estimate()

0 commit comments

Comments
 (0)