Skip to content

Quantum Bayesian Network Sampling (`pyagrum.qBNSampling`)

Creative Commons LicenseaGrUMinteractive online versiondownload notebookopen in colab

The pyagrum.qBNSampling module encodes a Bayesian network as a quantum circuit so that measuring the circuit samples from the network’s joint distribution. It also provides a quantum rejection-sampling inference engine that computes posterior distributions conditioned on evidence using Grover-based amplitude amplification.

Dependencies: qiskit, qiskit-aer, qiskit-ibm-runtime, scipy.

References

  • Circuit encoding: Borujeni et al., Quantum circuit representation of Bayesian networks, Expert Systems with Applications, 2021. arXiv:2004.14803
  • Quantum inference: Low, Yoder, Chuang, Quantum inference on Bayesian networks, Physical Review A, 2014. arXiv:1402.7359
import pyagrum as gum
import pyagrum.lib.notebook as gnb
import pyagrum.qBNSampling as qBNS

Part 1 β€” qBNMC: encoding a Bayesian network as a quantum circuit

Section titled β€œPart 1 β€” qBNMC: encoding a Bayesian network as a quantum circuit”

Each variable in the BN is mapped to ⌈log⁑2(∣dom∣)βŒ‰\lceil \log_2(|\text{dom}|) \rceil qubits. Its CPT is encoded as multi-qubit RY rotations: root nodes get unconditional rotations; non-root nodes get controlled rotations β€” one block per parent configuration, framed by X gates to select the correct control state.

Measuring the circuit returns a sample from the joint distribution of the network.

bn = gum.fastBN("A->B<-C", 2)
gnb.showBN(bn)

svg

qbn = qBNS.qBNMC(bn)
print(f"Total qubits: {qbn.getTotNumQBits()}")
print(f"Qubit map (node id -> qubit ids): {qbn.n_qb_map}")
circuit = qbn.buildCircuit(add_measure=True)
Total qubits: 3
Qubit map (node id -> qubit ids): {0: [0], 1: [1], 2: [2]}

Running the circuit on the Aer simulator returns marginal probability vectors for each variable. Let us compare them with the exact marginals from LazyPropagation.

gnb.flow.row(gnb.getBN(bn), circuit.draw("mpl", scale=0.7))
G C C B B C->B A A A->B
PyAgrum inline image
circuit.draw("latex")

png

circuit.draw()
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β–‘ β”Œβ”€β”€β”€β”              β”Œβ”€β”€β”€β” β–‘                          β–‘ Β»
     0: ─ Ry(2.5085) β”œβ”€β–‘β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€Β»
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–‘ β””β”€β”€β”€β”˜β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”β””β”€β”€β”€β”˜ β–‘      β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”      β–‘ Β»
     1: ───────────────░─────── Ry(1.7002) β”œβ”€β”€β”€β”€β”€β”€β–‘β”€β”€β”€β”€β”€β”€β”€ Ry(1.9446) β”œβ”€β”€β”€β”€β”€β”€β–‘β”€Β»
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β–‘ β”Œβ”€β”€β”€β”β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜β”Œβ”€β”€β”€β” β–‘ β”Œβ”€β”€β”€β”β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜β”Œβ”€β”€β”€β” β–‘ Β»
     2: ─ Ry(1.6313) β”œβ”€β–‘β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β–‘β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β–‘β”€Β»
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–‘ β””β”€β”€β”€β”˜              β””β”€β”€β”€β”˜ β–‘ β””β”€β”€β”€β”˜              β””β”€β”€β”€β”˜ β–‘ Β»
meas: 3/═══════════════════════════════════════════════════════════════════════»
                                                                               Β»
Β«        β”Œβ”€β”€β”€β”              β”Œβ”€β”€β”€β” β–‘                β–‘ β”Œβ”€β”      
Β«     0: ─ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€β”€Mβ”œβ”€β”€β”€β”€β”€β”€
Β«        β””β”€β”€β”€β”˜β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”β””β”€β”€β”€β”˜ β–‘ β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β–‘ β””β•₯β”˜β”Œβ”€β”   
Β«     1: ────── Ry(2.2965) β”œβ”€β”€β”€β”€β”€β”€β–‘β”€β”€ Ry(1.3641) β”œβ”€β–‘β”€β”€β•«β”€β”€Mβ”œβ”€β”€β”€
Β«             β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜      β–‘ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β–‘  β•‘ β””β•₯β”˜β”Œβ”€β”
Β«     2: ───────────■─────────────░───────■────────░──╫──╫──Mβ”œ
Β«                                 β–‘                β–‘  β•‘  β•‘ β””β•₯β”˜
Β«meas: 3/═════════════════════════════════════════════╩══╩══╩═
Β«                                                     0  1  2 
marginals = qbn.runBN(shots=10000)
ie = gum.LazyPropagation(bn)
ie.makeInference()
for name, tensor in marginals.items():
print(f"P({name})")
print(f" qBNMC (10 000 shots) : {[round(v, 4) for v in tensor.tolist()]}")
print(f" LazyPropagation : {[round(v, 4) for v in ie.posterior(name).tolist()]}")
print()
P(A)
qBNMC (10 000 shots) : [0.0976, 0.9024]
LazyPropagation : [0.0969, 0.9031]
P(B)
qBNMC (10 000 shots) : [0.4488, 0.5512]
LazyPropagation : [0.4517, 0.5483]
P(C)
qBNMC (10 000 shots) : [0.4706, 0.5294]
LazyPropagation : [0.4698, 0.5302]

Named example: Oil Company Stock Price (Borujeni et al., 2021)

Section titled β€œNamed example: Oil Company Stock Price (Borujeni et al., 2021)”

A 4-node BN modelling the dependencies between Interest Rate (IR), Stock Market (SM), Oil Import (OI), and Stock Price (SP).

bn_oil = gum.fastBN("IR->SM->SP<-OI", 2)
bn_oil.cpt("IR")[:] = [0.75, 0.25]
bn_oil.cpt("SM")[:] = [[0.3, 0.7], [0.8, 0.2]]
bn_oil.cpt("OI")[:] = [0.6, 0.4]
bn_oil.cpt("SP")[:] = [[[0.1, 0.9], [0.3, 0.7]], [[0.4, 0.6], [0.7, 0.3]]]
gnb.showBN(bn_oil)

svg

qbn_oil = qBNS.qBNMC(bn_oil)
print(f"Total qubits: {qbn_oil.getTotNumQBits()}")
qbn_oil.buildCircuit().draw("text")
Total qubits: 4
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β–‘ β”Œβ”€β”€β”€β”              β”Œβ”€β”€β”€β” β–‘                β–‘      Β»
     0: ── Ry(Ο€/3) β”œβ”€β”€β”€β–‘β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€β”€β”€β”€β”€β”€Β»
         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β–‘ β””β”€β”€β”€β”˜β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”β””β”€β”€β”€β”˜ β–‘ β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β–‘ β”Œβ”€β”€β”€β”Β»
     1: ───────────────░─────── Ry(1.9823) β”œβ”€β”€β”€β”€β”€β”€β–‘β”€β”€ Ry(0.9273) β”œβ”€β–‘β”€β”€ X β”œΒ»
                       β–‘      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β–‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–‘ β””β”€β”€β”€β”˜Β»
     2: ───────────────░──────────────────────────░────────────────░──────»
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β–‘                          β–‘                β–‘ β”Œβ”€β”€β”€β”Β»
     3: ─ Ry(1.3694) β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€β”€ X β”œΒ»
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–‘                          β–‘                β–‘ β””β”€β”€β”€β”˜Β»
meas: 4/══════════════════════════════════════════════════════════════════»
                                                                          Β»
Β«                            β–‘                          β–‘                    Β»
Β«     0: ────────────────────░──────────────────────────░────────────────────»
Β«                      β”Œβ”€β”€β”€β” β–‘                          β–‘ β”Œβ”€β”€β”€β”              Β»
Β«     1: ──────■──────── X β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€Β»
Β«        β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”β””β”€β”€β”€β”˜ β–‘      β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”      β–‘ β””β”€β”€β”€β”˜β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”Β»
Β«     2: ─ Ry(2.4981) β”œβ”€β”€β”€β”€β”€β”€β–‘β”€β”€β”€β”€β”€β”€β”€ Ry(1.9823) β”œβ”€β”€β”€β”€β”€β”€β–‘β”€β”€β”€β”€β”€β”€β”€ Ry(1.7722) β”œΒ»
Β«        β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜β”Œβ”€β”€β”€β” β–‘ β”Œβ”€β”€β”€β”β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜β”Œβ”€β”€β”€β” β–‘      β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜Β»
Β«     3: ──────■──────── X β”œβ”€β–‘β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€Β»
Β«                      β””β”€β”€β”€β”˜ β–‘ β””β”€β”€β”€β”˜              β””β”€β”€β”€β”˜ β–‘                    Β»
Β«meas: 4/════════════════════════════════════════════════════════════════════»
Β«                                                                            Β»
Β«              β–‘                β–‘ β”Œβ”€β”         
Β«     0: ──────░────────────────░──Mβ”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€
Β«        β”Œβ”€β”€β”€β” β–‘                β–‘ β””β•₯β”˜β”Œβ”€β”      
Β«     1: ─ X β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€β”€β•«β”€β”€Mβ”œβ”€β”€β”€β”€β”€β”€
Β«        β””β”€β”€β”€β”˜ β–‘ β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β–‘  β•‘ β””β•₯β”˜β”Œβ”€β”   
Β«     2: ──────░── Ry(1.1593) β”œβ”€β–‘β”€β”€β•«β”€β”€β•«β”€β”€Mβ”œβ”€β”€β”€
Β«              β–‘ β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β–‘  β•‘  β•‘ β””β•₯β”˜β”Œβ”€β”
Β«     3: ──────░───────■────────░──╫──╫──╫──Mβ”œ
Β«              β–‘                β–‘  β•‘  β•‘  β•‘ β””β•₯β”˜
Β«meas: 4/══════════════════════════╩══╩══╩══╩═
Β«                                  0  1  2  3 
marginals_oil = qbn_oil.runBN(shots=10000)
ie_oil = gum.LazyPropagation(bn_oil)
ie_oil.makeInference()
gnb.sideBySide(
marginals_oil["SP"],
ie_oil.posterior("SP"),
captions=["qBNMC β€” 10 000 shots", "LazyPropagation β€” exact"],
)
SP
0
1
0.36100.6390

qBNMC β€” 10 000 shots
SP
0
1
0.35800.6420

LazyPropagation β€” exact

Multi-state variables: Naive Bayes Bankruptcy Prediction

Section titled β€œMulti-state variables: Naive Bayes Bankruptcy Prediction”

Variables with more than 2 states require ⌈log⁑2(∣dom∣)βŒ‰>1\lceil \log_2(|\text{dom}|) \rceil > 1 qubits. Here node B has 2 states and several children have 3 states (2 qubits each).

bn_bk = gum.fastBN("B->AU; B->IT; B->CH[3]; B->LM[3]")
bn_bk.generateCPTs()
gnb.showInference(bn_bk)

svg

qbn_bk = qBNS.qBNMC(bn_bk)
print(f"Total qubits: {qbn_bk.getTotNumQBits()}")
print(f"Qubit widths: { {bn_bk.variable(n).name(): qbn_bk.getWidth(n) for n in bn_bk.nodes()} }")
qbn_bk.buildCircuit().draw("text")
Total qubits: 7
Qubit widths: {'B': 1, 'AU': 1, 'IT': 1, 'CH': 2, 'LM': 2}
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β–‘ β”Œβ”€β”€β”€β”              β”Œβ”€β”€β”€β” β–‘                β–‘ β”Œβ”€β”€β”€β”Β»
     0: ─ Ry(1.9485) β”œβ”€β–‘β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€β”€ X β”œΒ»
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–‘ β””β”€β”€β”€β”˜      β”‚       β””β”€β”€β”€β”˜ β–‘       β”‚        β–‘ β””β”€β”€β”€β”˜Β»
     1: ───────────────░────────────┼─────────────░───────┼────────░──────»
                       β–‘      β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”      β–‘ β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β–‘      Β»
     2: ───────────────░─────── Ry(1.4249) β”œβ”€β”€β”€β”€β”€β”€β–‘β”€β”€ Ry(1.5019) β”œβ”€β–‘β”€β”€β”€β”€β”€β”€Β»
                       β–‘      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β–‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–‘      Β»
   3_0: ───────────────░──────────────────────────░────────────────░──────»
                       β–‘                          β–‘                β–‘      Β»
   3_1: ───────────────░──────────────────────────░────────────────░──────»
                       β–‘                          β–‘                β–‘      Β»
   4_0: ───────────────░──────────────────────────░────────────────░──────»
                       β–‘                          β–‘                β–‘      Β»
   4_1: ───────────────░──────────────────────────░────────────────░──────»
                       β–‘                          β–‘                β–‘      Β»
meas: 7/══════════════════════════════════════════════════════════════════»
                                                                          Β»
Β«                                                       β”Œβ”€β”€β”€β” β–‘               Β»
Β«     0: ──────■───────────■──────■────────■─────────■─── X β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€Β»
Β«              β”‚           β”‚      β”‚        β”‚         β”‚  β””β”€β”€β”€β”˜ β–‘       β”‚       Β»
Β«     1: ──────┼───────────┼──────┼────────┼─────────┼────────░───────┼───────»
Β«              β”‚           β”‚      β”‚        β”‚         β”‚        β–‘       β”‚       Β»
Β«     2: ──────┼───────────┼──────┼────────┼─────────┼────────░───────┼───────»
Β«              β”‚           β”‚      β”‚        β”‚         β”‚        β–‘       β”‚       Β»
Β«   3_0: ──────┼───────────┼──────┼────────┼─────────┼────────░───────┼───────»
Β«              β”‚           β”‚      β”‚        β”‚         β”‚        β–‘       β”‚       Β»
Β«   3_1: ──────┼───────────┼──────┼────────┼─────────┼────────░───────┼───────»
Β«        β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”    β”‚    β”Œβ”€β”΄β”€β”      β”‚       β”Œβ”€β”΄β”€β”      β–‘ β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”Β»
Β«   4_0: ─ Ry(1.3497) β”œβ”€β”€β”€β”€β– β”€β”€β”€β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β–‘β”€β”€ Ry(1.4611) β”œΒ»
Β«        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”Œβ”€β”€β”€β”΄β”€β”€β”€β”β””β”€β”€β”€β”˜β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”β””β”€β”€β”€β”˜      β–‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜Β»
Β«   4_1: ─────────────── Ry(0) β”œβ”€β”€β”€β”€β”€β”€ Ry(2.2073) β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€Β»
Β«                      β””β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β–‘               Β»
Β«meas: 7/═════════════════════════════════════════════════════════════════════»
Β«                                                                             Β»
Β«                                          β–‘ β”Œβ”€β”€β”€β”              β”Œβ”€β”€β”€β” β–‘ Β»
Β«     0: ────■──────■────────■─────────■───░── X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β–‘β”€Β»
Β«            β”‚      β”‚        β”‚         β”‚   β–‘ β””β”€β”€β”€β”˜β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”β””β”€β”€β”€β”˜ β–‘ Β»
Β«     1: ────┼──────┼────────┼─────────┼───░─────── Ry(1.3767) β”œβ”€β”€β”€β”€β”€β”€β–‘β”€Β»
Β«            β”‚      β”‚        β”‚         β”‚   β–‘      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β–‘ Β»
Β«     2: ────┼──────┼────────┼─────────┼───░──────────────────────────░─»
Β«            β”‚      β”‚        β”‚         β”‚   β–‘                          β–‘ Β»
Β«   3_0: ────┼──────┼────────┼─────────┼───░──────────────────────────░─»
Β«            β”‚      β”‚        β”‚         β”‚   β–‘                          β–‘ Β»
Β«   3_1: ────┼──────┼────────┼─────────┼───░──────────────────────────░─»
Β«            β”‚    β”Œβ”€β”΄β”€β”      β”‚       β”Œβ”€β”΄β”€β” β–‘                          β–‘ Β»
Β«   4_0: ────■───── X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€Β»
Β«        β”Œβ”€β”€β”€β”΄β”€β”€β”€β”β””β”€β”€β”€β”˜β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”β””β”€β”€β”€β”˜ β–‘                          β–‘ Β»
Β«   4_1: ─ Ry(0) β”œβ”€β”€β”€β”€β”€β”€ Ry(1.6664) β”œβ”€β”€β”€β”€β”€β”€β–‘β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–‘β”€Β»
Β«        β””β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β–‘                          β–‘ Β»
Β«meas: 7/═══════════════════════════════════════════════════════════════»
Β«                                                                       Β»
Β«                       β–‘ β”Œβ”€β”€β”€β”                                                Β»
Β«     0: ──────■────────░── X β”œβ”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€Β»
Β«        β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β–‘ β””β”€β”€β”€β”˜       β”‚           β”‚      β”‚        β”‚         β”‚  Β»
Β«     1: ─ Ry(1.1793) β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€Β»
Β«        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β–‘             β”‚           β”‚      β”‚        β”‚         β”‚  Β»
Β«     2: ───────────────░─────────────┼───────────┼──────┼────────┼─────────┼──»
Β«                       β–‘      β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”    β”‚    β”Œβ”€β”΄β”€β”      β”‚       β”Œβ”€β”΄β”€β”Β»
Β«   3_0: ───────────────░─────── Ry(0.63789) β”œβ”€β”€β”€β”€β– β”€β”€β”€β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œΒ»
Β«                       β–‘      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”Œβ”€β”€β”€β”΄β”€β”€β”€β”β””β”€β”€β”€β”˜β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”β””β”€β”€β”€β”˜Β»
Β«   3_1: ───────────────░────────────────────── Ry(0) β”œβ”€β”€β”€β”€β”€β”€ Ry(1.3859) β”œβ”€β”€β”€β”€β”€Β»
Β«                       β–‘                     β””β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     Β»
Β«   4_0: ───────────────░──────────────────────────────────────────────────────»
Β«                       β–‘                                                      Β»
Β«   4_1: ───────────────░──────────────────────────────────────────────────────»
Β«                       β–‘                                                      Β»
Β«meas: 7/══════════════════════════════════════════════════════════════════════»
Β«                                                                              Β»
Β«        β”Œβ”€β”€β”€β” β–‘                                                  β–‘ β”Œβ”€β”      Β»
Β«     0: ─ X β”œβ”€β–‘β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€β”€β– β”€β”€β”€β–‘β”€β”€Mβ”œβ”€β”€β”€β”€β”€β”€Β»
Β«        β””β”€β”€β”€β”˜ β–‘        β”‚           β”‚      β”‚        β”‚         β”‚   β–‘ β””β•₯β”˜β”Œβ”€β”   Β»
Β«     1: ──────░────────┼───────────┼──────┼────────┼─────────┼───░──╫──Mβ”œβ”€β”€β”€Β»
Β«              β–‘        β”‚           β”‚      β”‚        β”‚         β”‚   β–‘  β•‘ β””β•₯β”˜β”Œβ”€β”Β»
Β«     2: ──────░────────┼───────────┼──────┼────────┼─────────┼───░──╫──╫──Mβ”œΒ»
Β«              β–‘ β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”    β”‚    β”Œβ”€β”΄β”€β”      β”‚       β”Œβ”€β”΄β”€β” β–‘  β•‘  β•‘ β””β•₯β”˜Β»
Β«   3_0: ──────░── Ry(0.62371) β”œβ”€β”€β”€β”€β– β”€β”€β”€β”€β”€ X β”œβ”€β”€β”€β”€β”€β”€β– β”€β”€β”€β”€β”€β”€β”€β”€ X β”œβ”€β–‘β”€β”€β•«β”€β”€β•«β”€β”€β•«β”€Β»
Β«              β–‘ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”Œβ”€β”€β”€β”΄β”€β”€β”€β”β””β”€β”€β”€β”˜β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”β””β”€β”€β”€β”˜ β–‘  β•‘  β•‘  β•‘ Β»
Β«   3_1: ──────░───────────────── Ry(0) β”œβ”€β”€β”€β”€β”€β”€ Ry(1.2431) β”œβ”€β”€β”€β”€β”€β”€β–‘β”€β”€β•«β”€β”€β•«β”€β”€β•«β”€Β»
Β«              β–‘                β””β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β–‘  β•‘  β•‘  β•‘ Β»
Β«   4_0: ──────░──────────────────────────────────────────────────░──╫──╫──╫─»
Β«              β–‘                                                  β–‘  β•‘  β•‘  β•‘ Β»
Β«   4_1: ──────░──────────────────────────────────────────────────░──╫──╫──╫─»
Β«              β–‘                                                  β–‘  β•‘  β•‘  β•‘ Β»
Β«meas: 7/════════════════════════════════════════════════════════════╩══╩══╩═»
Β«                                                                    0  1  2 Β»
Β«                    
Β«     0: ────────────
Β«                    
Β«     1: ────────────
Β«                    
Β«     2: ────────────
Β«        β”Œβ”€β”         
Β«   3_0: ─Mβ”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€
Β«        β””β•₯β”˜β”Œβ”€β”      
Β«   3_1: ─╫──Mβ”œβ”€β”€β”€β”€β”€β”€
Β«         β•‘ β””β•₯β”˜β”Œβ”€β”   
Β«   4_0: ─╫──╫──Mβ”œβ”€β”€β”€
Β«         β•‘  β•‘ β””β•₯β”˜β”Œβ”€β”
Β«   4_1: ─╫──╫──╫──Mβ”œ
Β«         β•‘  β•‘  β•‘ β””β•₯β”˜
Β«meas: 7/═╩══╩══╩══╩═
Β«         3  4  5  6 
marginals_bk = qbn_bk.runBN(shots=10000)
ie_bk = gum.LazyPropagation(bn_bk)
ie_bk.makeInference()
gnb.sideBySide(
marginals_bk["CH"],
ie_bk.posterior("CH"),
captions=["qBNMC β€” 10 000 shots", "LazyPropagation β€” exact"],
)
CH
0
1
2
0.57880.32500.0962

qBNMC β€” 10 000 shots
CH
0
1
2
0.57820.32630.0955

LazyPropagation β€” exact

qBNRejection implements quantum rejection sampling (Low et al., 2014). Given evidence ee, it uses the Grover iterate G=Se Aβˆ’1 S0 AG = S_e \, A^{-1} \, S_0 \, A to amplify the amplitude of states consistent with ee, where:

  • AA is the quantum circuit encoding of the BN (built by qBNMC);
  • SeS_e is a phase flip on the evidence qubits;
  • S0S_0 is a phase flip on the all-zero state.

Each call to getSample applies G⌈2kβŒ‰G^{\lceil 2^k \rceil} for increasing kk until a measurement consistent with the evidence is obtained (Algorithm 1). makeInference accumulates max_iter such samples to estimate the posterior.

bn = gum.fastBN("A->B<-C", 2)
evidence = {"B": 0}
## Exact reference
ie = gum.LazyPropagation(bn)
ie.setEvidence(evidence)
ie.makeInference()
print("Exact P(A | B=0):", ie.posterior("A"))
Exact P(A | B=0):
A β”‚
0 β”‚1 β”‚
─────────│─────────│
0.8467 β”‚ 0.1533 β”‚
qbn = qBNS.qBNMC(bn)
qinf = qBNS.qBNRejection(qbn)
qinf.setEvidence(evidence)
qinf.setMaxIter(500)
qinf.makeInference()
{'A': [0.8340000000000006, 0.16600000000000012],
'B': [1.0000000000000007, 0.0],
'C': [0.4880000000000004, 0.5120000000000003]}
gnb.sideBySide(
qinf.posterior("A"),
ie.posterior("A"),
captions=["qBNRejection β€” 500 samples", "LazyPropagation β€” exact"],
)
A
0
1
0.83400.1660

qBNRejection β€” 500 samples
A
0
1
0.84670.1533

LazyPropagation β€” exact

For a query involving only a subset of nodes, useFragmentBN builds a minimal BayesNetFragment containing only the ancestors of the target and evidence nodes. This reduces the number of qubits and speeds up the circuit.

## Larger BN: A->B->C->H; I->H; A->D->C; D->E; G->F->E
bn_large = gum.fastBN("A->B->C->H;I->H;A->D->C;D->E;G->F->E", 2)
gnb.showBN(bn_large, size=8)

svg

evidence_large = {"H": 0, "A": 1}
target = "D"
qbn_large = qBNS.qBNMC(bn_large)
qinf_large = qBNS.qBNRejection(qbn_large)
qinf_large.setEvidence(evidence_large)
## Restrict the circuit to the ancestors of {target} βˆͺ evidence
qinf_large.useFragmentBN(target={target})
print(f"Full BN: {bn_large.size()} nodes, {qbn_large.getTotNumQBits()} qubits")
print(f"Fragment: {qinf_large.qbn.bn.size()} nodes, {qinf_large.qbn.getTotNumQBits()} qubits")
gnb.showBN(qinf_large.qbn.bn)
Full BN: 9 nodes, 9 qubits
Fragment: 6 nodes, 6 qubits

svg

qinf_large.setMaxIter(500)
qinf_large.makeInference()
ie_large = gum.LazyPropagation(bn_large)
ie_large.setEvidence(evidence_large)
ie_large.makeInference()
gnb.sideBySide(
qinf_large.posterior(target),
ie_large.posterior(target),
captions=[f"qBNRejection β€” P({target} | H=0, A=1)", "LazyPropagation β€” exact"],
)
D
0
1
0.83800.1620

qBNRejection β€” P(D | H=0, A=1)
D
0
1
0.82980.1702

LazyPropagation β€” exact
bn_oil = gum.fastBN("IR->SM->SP<-OI", 2)
bn_oil.cpt("IR")[:] = [0.75, 0.25]
bn_oil.cpt("SM")[:] = [[0.3, 0.7], [0.8, 0.2]]
bn_oil.cpt("OI")[:] = [0.6, 0.4]
bn_oil.cpt("SP")[:] = [[[0.1, 0.9], [0.3, 0.7]], [[0.4, 0.6], [0.7, 0.3]]]
evidence_oil = {"SP": 1}
target_oil = "OI"
ie_oil = gum.LazyPropagation(bn_oil)
ie_oil.setEvidence(evidence_oil)
ie_oil.makeInference()
print(f"Exact P({target_oil} | SP=1) = {ie_oil.posterior(target_oil)}")
Exact P(OI | SP=1) =
OI β”‚
0 β”‚1 β”‚
─────────│─────────│
0.7336 β”‚ 0.2664 β”‚
qbn_oil = qBNS.qBNMC(bn_oil)
qinf_oil = qBNS.qBNRejection(qbn_oil)
qinf_oil.setEvidence(evidence_oil)
qinf_oil.useFragmentBN(target={target_oil})
qinf_oil.setMaxIter(500)
qinf_oil.makeInference()
gnb.sideBySide(
qinf_oil.posterior(target_oil),
ie_oil.posterior(target_oil),
captions=[f"qBNRejection β€” P({target_oil} | SP=1)", "LazyPropagation β€” exact"],
)
OI
0
1
0.71400.2860

qBNRejection β€” P(OI | SP=1)
OI
0
1
0.73360.2664

LazyPropagation β€” exact
ClassPurposeKey method
qBNMCEncode BN as quantum circuitbuildCircuit(), runBN(shots)
qBNRejectionPosterior inference with evidencesetEvidence(), makeInference(), posterior(node)

Useful workflow:

  1. Build qBNMC(bn) β€” circuit encoding.
  2. Check marginals via runBN() (no evidence).
  3. Build qBNRejection(qbn) and call useFragmentBN(target, evidence) to reduce circuit size.
  4. setEvidence(), setMaxIter(), makeInference(), posterior(node).