Skip to content

Commit 5dac279

Browse files
wavefunction91Maximilian MorchenmmoerchenCopilotRushiGong
authored
Version 1.1 (#422)
Co-authored-by: Maximilian Morchen <v-mmorchen@microsoft.com> Co-authored-by: Maximilian Mörchen <111281642+mmoerchen@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Rushi Gong <rushigong@microsoft.com>
1 parent 9d2a41c commit 5dac279

47 files changed

Lines changed: 2578 additions & 221 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

INSTALL.md

Lines changed: 172 additions & 144 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ Designed as both a **development platform** and a **composable framework**, QDK/
88

99
QDK/Chemistry bridges classical computational chemistry with quantum computing by providing every stage of the quantum applications pipeline in a single, modular toolkit:
1010

11-
- **Quantum algorithms** a growing collection of chemistry-aware quantum algorithms, with composable building blocks for constructing higher-level quantum workflows
12-
- **Classical electronic structure** production-quality classical methods that generate the high-quality inputs quantum algorithms require
13-
- **Composable architecture** a plugin system that lets users assemble custom pipelines from interchangeable components, mixing native high-performance C++ backends with established community packages
14-
- **Multiple quantum backends** execute circuits on a variety of simulators through a unified interface that decouples algorithm development from backend selection
11+
- **Quantum algorithms**: a growing collection of chemistry-aware quantum algorithms, with composable building blocks for constructing higher-level quantum workflows
12+
- **Classical electronic structure**: production-quality classical methods that generate the high-quality inputs quantum algorithms require
13+
- **Composable architecture**: a plugin system that lets users assemble custom pipelines from interchangeable components, mixing native high-performance C++ backends with established community packages
14+
- **Multiple quantum backends**: execute circuits on a variety of simulators through a unified interface that decouples algorithm development from backend selection
1515

1616
## Documentation
1717

@@ -39,7 +39,12 @@ qdk-chemistry/
3939

4040
## Installing
4141

42-
Detailed instructions for installing QDK/Chemistry can be found in [INSTALL.md](./INSTALL.md)
42+
```bash
43+
python3 -m venv venv && source venv/bin/activate
44+
python3 -m pip install 'qdk-chemistry[all]'
45+
```
46+
47+
The `[all]` extra pulls in all optional dependencies so that examples and tests work without chasing missing packages. For other installation methods (Dev Container, building from source) and platform-specific notes, see [INSTALL.md](./INSTALL.md).
4348

4449
## Telemetry
4550

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.2
1+
1.1.0

docs/source/_static/examples/python/active_space_selector.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@
2626

2727
################################################################################
2828
# start-cell-run
29-
from pathlib import Path # noqa: E402
30-
from qdk_chemistry.data import Structure # noqa: E402
29+
from pathlib import Path
30+
from qdk_chemistry.data import Structure
3131

3232
# Load a molecular structure (water molecule) from XYZ file
3333
structure = Structure.from_xyz_file(
@@ -52,7 +52,7 @@
5252

5353
################################################################################
5454
# start-cell-list-implementations
55-
from qdk_chemistry.algorithms import registry # noqa: E402
55+
from qdk_chemistry.algorithms import registry
5656

5757
print(registry.available("active_space_selector"))
5858
# ['pyscf_avas', 'qdk_occupation', 'qdk_autocas_eos', 'qdk_autocas', 'qdk_valence']
@@ -61,7 +61,7 @@
6161

6262
################################################################################
6363
# start-cell-autocas
64-
from qdk_chemistry.utils import compute_valence_space_parameters # noqa: E402
64+
from qdk_chemistry.utils import compute_valence_space_parameters
6565

6666
# Create a valence space active space selector
6767
valence_selector = create("active_space_selector", "qdk_valence")
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
"""Circuit data class usage examples."""
2+
3+
# --------------------------------------------------------------------------------------------
4+
# Copyright (c) Microsoft Corporation. All rights reserved.
5+
# Licensed under the MIT License. See LICENSE.txt in the project root for license information.
6+
# --------------------------------------------------------------------------------------------
7+
8+
################################################################################
9+
# start-cell-qsharp-workflow
10+
import json
11+
12+
import qdk
13+
import qsharp
14+
from qdk_chemistry.data import Circuit
15+
from qdk_chemistry.data.circuit import QsharpFactoryData
16+
17+
# 1. Define a Q# operation from string
18+
qsharp.eval(
19+
"""
20+
operation GHZSample(n: Int) : Result[] {
21+
use qs = Qubit[n];
22+
23+
H(qs[0]);
24+
ApplyToEach(CNOT(qs[0], _), qs[1...]);
25+
26+
let results = MeasureEachZ(qs);
27+
ResetAll(qs);
28+
return results;
29+
}
30+
"""
31+
)
32+
33+
# 2. Get a Q# circuit object and wrap it
34+
qsharp_factory = QsharpFactoryData(
35+
program=qdk.code.GHZSample,
36+
parameter={"n": 3},
37+
)
38+
circuit = Circuit(qsharp_factory=qsharp_factory)
39+
40+
# 3. Inspect the circuit
41+
qsharp_circuit = circuit.get_qsharp_circuit()
42+
print(qsharp_circuit)
43+
# Return an ASCII diagram of the circuit
44+
# q_0 ── H ──── ● ──── ● ──── M ──── |0〉 ──
45+
# │ │ ╘════════════
46+
# q_1 ───────── X ─────┼───── M ──── |0〉 ──
47+
# │ ╘════════════
48+
# q_2 ──────────────── X ──── M ──── |0〉 ──
49+
# ╘════════════
50+
51+
# 4. Access the gate-level JSON structure
52+
circuit_json = json.loads(qsharp_circuit.json())
53+
print(f"Qubits: {len(circuit_json['qubits'])}")
54+
55+
# 5. Resource estimation
56+
estimate_result = circuit.estimate()
57+
formatted = estimate_result["physicalCountsFormatted"]
58+
print(f"Physical qubits: {formatted['physicalQubits']}")
59+
print(f"Runtime: {formatted['runtime']}")
60+
# end-cell-qsharp-workflow
61+
################################################################################
62+
63+
################################################################################
64+
# start-cell-qsharp-harness
65+
# Prepare single-reference state with Q# factory parameters
66+
from qdk_chemistry.data import Circuit
67+
from qdk_chemistry.utils.qsharp import QSHARP_UTILS
68+
69+
# 1. Build a parameter object (a dictionary or a Q# structured parameter class)
70+
bitstring = [1, 1, 0, 0]
71+
params = QSHARP_UTILS.StatePreparation.SingleReferenceParams(
72+
bitStrings=bitstring, numQubits=len(bitstring)
73+
)
74+
75+
# 2. Create the factory — vars() converts the dataclass to a dict
76+
factory = QsharpFactoryData(
77+
program=QSHARP_UTILS.StatePreparation.MakeSingleReferenceStateCircuit,
78+
parameter=vars(params),
79+
)
80+
81+
# 3. Wrap in a Circuit — nothing is compiled yet
82+
circuit = Circuit(qsharp_factory=factory, encoding="jordan-wigner")
83+
84+
# 4. Compilation happens on demand:
85+
circuit.get_qsharp_circuit() # → qsharp.circuit(program, **params)
86+
circuit.get_qir() # → qsharp.compile(program, **params)
87+
# end-cell-qsharp-harness
88+
################################################################################
89+
90+
################################################################################
91+
# start-cell-conversion
92+
import numpy as np
93+
from qdk_chemistry.algorithms import create
94+
from qdk_chemistry.data import Circuit, Structure
95+
96+
# When algorithms produce circuits, they carry native Q# operations internally.
97+
# This enables end-to-end Q# composition without format conversions.
98+
coords = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.4]])
99+
structure = Structure(coords, symbols=["H", "H"])
100+
101+
scf = create("scf_solver")
102+
_, wfn = scf.run(structure, charge=0, spin_multiplicity=1, basis_or_guess="sto-3g")
103+
ham = create("hamiltonian_constructor").run(wfn.get_orbitals())
104+
_, wfn_cas = create("multi_configuration_calculator").run(ham, 1, 1)
105+
106+
# StatePreparation produces a Circuit with a native Q# factory
107+
state_prep = create("state_prep", "sparse_isometry_gf2x")
108+
circuit = state_prep.run(wfn_cas)
109+
110+
# Inspect the Q# circuit (prune unused qubits for clarity)
111+
pruned_qsharp_circuit = circuit.get_qsharp_circuit(prune_classical_qubits=True)
112+
print(pruned_qsharp_circuit)
113+
114+
# Get the QIR representation
115+
qir = circuit.get_qir()
116+
print(qir)
117+
118+
# Export to OpenQASM or Qiskit when needed (if qiskit is installed)
119+
try:
120+
qasm_str = circuit.get_qasm()
121+
print(qasm_str)
122+
123+
qiskit_circuit = circuit.get_qiskit_circuit()
124+
print(qiskit_circuit)
125+
except (ImportError, RuntimeError):
126+
print("Qiskit not installed — skipping OpenQASM/Qiskit export")
127+
128+
# end-cell-conversion
129+
################################################################################
130+
131+
################################################################################
132+
# start-cell-serialization
133+
# Save to JSON
134+
circuit.to_json_file("example_circuit.circuit.json")
135+
136+
# Load from JSON
137+
loaded = Circuit.from_json_file("example_circuit.circuit.json")
138+
139+
# Save to HDF5
140+
circuit.to_hdf5_file("example_circuit.circuit.h5")
141+
142+
# Load from HDF5
143+
loaded_h5 = Circuit.from_hdf5_file("example_circuit.circuit.h5")
144+
# end-cell-serialization
145+
################################################################################
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
"""Circuit executor usage examples."""
2+
3+
# --------------------------------------------------------------------------------------------
4+
# Copyright (c) Microsoft Corporation. All rights reserved.
5+
# Licensed under the MIT License. See LICENSE.txt in the project root for license information.
6+
# --------------------------------------------------------------------------------------------
7+
8+
################################################################################
9+
# start-cell-create
10+
from qdk_chemistry.algorithms import create
11+
12+
# Create the default executor (QDK sparse-state simulator)
13+
executor = create("circuit_executor")
14+
15+
# Or select a specific implementation
16+
full_state = create("circuit_executor", "qdk_full_state_simulator")
17+
sparse_state = create("circuit_executor", "qdk_sparse_state_simulator")
18+
aer = create("circuit_executor", "qiskit_aer_simulator")
19+
# end-cell-create
20+
################################################################################
21+
22+
################################################################################
23+
# start-cell-configure-qdk
24+
# Configure the QDK full-state simulator
25+
executor = create("circuit_executor", "qdk_full_state_simulator")
26+
executor.settings().set("type", "cpu")
27+
executor.settings().set("seed", 42)
28+
# end-cell-configure-qdk
29+
################################################################################
30+
31+
################################################################################
32+
# start-cell-configure-qiskit
33+
# Configure the Qiskit Aer simulator
34+
executor = create("circuit_executor", "qiskit_aer_simulator")
35+
executor.settings().set("method", "statevector")
36+
executor.settings().set("seed", 42)
37+
executor.settings().set("transpile_optimization_level", 0)
38+
# end-cell-configure-qiskit
39+
################################################################################
40+
41+
################################################################################
42+
# start-cell-run
43+
from qdk_chemistry.algorithms import create
44+
from qdk_chemistry.data import Circuit
45+
46+
# Define a circuit in OpenQASM
47+
circuit = Circuit(
48+
qasm="""
49+
include "stdgates.inc";
50+
qubit[2] q;
51+
bit[2] c;
52+
x q[0];
53+
cx q[0], q[1];
54+
c[0] = measure q[0];
55+
c[1] = measure q[1];
56+
"""
57+
)
58+
59+
# Execute with the QDK sparse-state simulator
60+
executor = create("circuit_executor", "qdk_sparse_state_simulator")
61+
result = executor.run(circuit, shots=1000)
62+
print(f"Bitstring counts: {result.bitstring_counts}")
63+
print(f"Total shots: {result.total_shots}")
64+
# end-cell-run
65+
################################################################################
66+
67+
################################################################################
68+
# start-cell-noise
69+
from qdk_chemistry.algorithms import create
70+
from qdk_chemistry.data import Circuit, QuantumErrorProfile
71+
72+
circuit = Circuit(
73+
qasm="""
74+
include "stdgates.inc";
75+
qubit[2] q;
76+
bit[2] c;
77+
x q[0];
78+
cx q[0], q[1];
79+
c[0] = measure q[0];
80+
c[1] = measure q[1];
81+
"""
82+
)
83+
84+
# Define a noise model
85+
noise_model = QuantumErrorProfile(
86+
name="depolarizing",
87+
description="Simple depolarizing noise model",
88+
errors={
89+
"x": {"type": "depolarizing_error", "rate": 0.005, "num_qubits": 1},
90+
"cx": {"type": "depolarizing_error", "rate": 0.007, "num_qubits": 2},
91+
},
92+
)
93+
94+
# Execute with noise
95+
executor = create("circuit_executor", "qdk_full_state_simulator", type="cpu")
96+
result = executor.run(circuit, shots=1000, noise=noise_model)
97+
print(f"Noisy bitstring counts: {result.bitstring_counts}")
98+
# end-cell-noise
99+
################################################################################
100+
101+
################################################################################
102+
# start-cell-list-implementations
103+
from qdk_chemistry.algorithms import registry
104+
105+
# List all registered circuit executor implementations
106+
implementations = registry.available("circuit_executor")
107+
print(
108+
implementations
109+
) # e.g. ['qdk_sparse_state_simulator', 'qdk_full_state_simulator', 'qiskit_aer_simulator']
110+
# end-cell-list-implementations
111+
################################################################################
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""Controlled evolution circuit mapper usage examples."""
2+
3+
# --------------------------------------------------------------------------------------------
4+
# Copyright (c) Microsoft Corporation. All rights reserved.
5+
# Licensed under the MIT License. See LICENSE.txt in the project root for license information.
6+
# --------------------------------------------------------------------------------------------
7+
8+
################################################################################
9+
# start-cell-create
10+
from qdk_chemistry.algorithms import create
11+
12+
# Create the default mapper (pauli_sequence)
13+
mapper = create("controlled_evolution_circuit_mapper")
14+
# end-cell-create
15+
################################################################################
16+
17+
################################################################################
18+
# start-cell-configure
19+
# Configure the power of the controlled unitary
20+
mapper = create("controlled_evolution_circuit_mapper", "pauli_sequence")
21+
mapper.settings().set("power", 4)
22+
# end-cell-configure
23+
################################################################################
24+
25+
################################################################################
26+
# start-cell-run
27+
import numpy as np
28+
from qdk_chemistry.algorithms import create
29+
from qdk_chemistry.data import Structure
30+
31+
# 1. Setup molecule
32+
coords = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.4]])
33+
symbols = ["H", "H"]
34+
structure = Structure(coords, symbols=symbols)
35+
36+
# 2. SCF
37+
scf_solver = create("scf_solver")
38+
E_scf, wfn_scf = scf_solver.run(
39+
structure, charge=0, spin_multiplicity=1, basis_or_guess="sto-3g"
40+
)
41+
42+
# 3. Hamiltonian and qubit mapping
43+
hamiltonian_constructor = create("hamiltonian_constructor")
44+
hamiltonian = hamiltonian_constructor.run(wfn_scf.get_orbitals())
45+
qubit_mapper = create("qubit_mapper", encoding="jordan-wigner")
46+
qubit_ham = qubit_mapper.run(hamiltonian)
47+
48+
# 4. Build time evolution unitary
49+
trotter = create("time_evolution_builder", "trotter", order=2)
50+
evolution = trotter.run(qubit_ham, time=0.1)
51+
52+
# 5. Create a controlled version and map to a circuit
53+
from qdk_chemistry.data import ControlledTimeEvolutionUnitary
54+
55+
controlled = ControlledTimeEvolutionUnitary(evolution, control_indices=[0])
56+
mapper = create("controlled_evolution_circuit_mapper", "pauli_sequence")
57+
circuit = mapper.run(controlled)
58+
print("Controlled evolution circuit generated")
59+
# end-cell-run
60+
################################################################################
61+
62+
################################################################################
63+
# start-cell-list-implementations
64+
from qdk_chemistry.algorithms import registry
65+
66+
# List all registered controlled evolution circuit mapper implementations
67+
implementations = registry.available("controlled_evolution_circuit_mapper")
68+
print(implementations) # e.g. ['pauli_sequence']
69+
# end-cell-list-implementations
70+
################################################################################

0 commit comments

Comments
 (0)