Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
fail-fast: false
matrix:
os: ['ubuntu-latest', 'windows-2022', 'macos-latest']
python: ['3.8', '3.9', '3.10', '3.11']
python: ['3.9', '3.10', '3.11', '3.12']

name: "Python ${{ matrix.python }} / ${{ matrix.os }}"
runs-on: ${{ matrix.os }}
Expand Down
2 changes: 1 addition & 1 deletion docs/source/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Then we define a circuit:
# generate a slightly modified GHZ state generation pattern
circuit = Circuit(3)
simple_circ(circuit)
pattern = circuit.transpile()
pattern = circuit.transpile().pattern

# plot the pattern
nodes, edges = pattern.get_graph()
Expand Down
34 changes: 23 additions & 11 deletions graphix_perceval/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
import graphix
import perceval as pcvl
import sympy as sp
from graphix.extraction import ResourceGraph, ResourceType, get_fusion_network_from_graph
from graphix.clifford import Clifford
from graphix.command import M
from graphix.extraction import (
ResourceGraph,
ResourceType,
get_fusion_network_from_graph,
)
from perceval import components as comp

from graphix_perceval.clifford import CLIFFORD_TO_PERCEVAL_POLAR
Expand All @@ -29,12 +35,15 @@ def pattern2graphstate(
output_nodes : list
List of output nodes.
"""
nodes, edges = pattern.get_graph()
graph = pattern.extract_graph()
nodes = list(graph.nodes())
edges = list(graph.edges())
vop_init = pattern.get_vops()
graph_state = graphix.GraphState(nodes=nodes, edges=edges, vops=vop_init)
phasedict = {}
for command in pattern.get_measurement_commands():
phasedict[command[1]] = command[3]
for command in pattern:
if isinstance(command, M):
phasedict[command.node] = command.angle

output_nodes = pattern.output_nodes
return graph_state, phasedict, output_nodes
Expand Down Expand Up @@ -104,10 +113,10 @@ def add_resourcegraph(self, ResourceGraph: ResourceGraph, phasedict: dict[int, f
self.num_photons += 1
self.photons.append(ph)

if ResourceGraph.type in (ResourceType.GHZ, ResourceType.LINEAR):
if ResourceGraph.cltype in (ResourceType.GHZ, ResourceType.LINEAR):
self.ResourceGraphs.append(ResourceGraph)
else:
raise TypeError(f"ResourceType {ResourceGraph.type} is not supported")
raise TypeError(f"ResourceType {ResourceGraph.cltype} is not supported")

def get_readouts(self) -> list[Photon]:
return [ph for ph in self.photons if ph.type == PhotonType.READOUT]
Expand Down Expand Up @@ -144,13 +153,13 @@ def setup_perceval_circuit(self, name: str | None = None, merge: bool = False) -
# Create circuits for all the ResourceGraphs
photon_idx = 0
for cl in self.ResourceGraphs:
if cl.type == ResourceType.GHZ:
if cl.cltype == ResourceType.GHZ:
circ.add(
[idx for idx in range(photon_idx, photon_idx + len(cl.graph.nodes))],
ghz_circuit(len(cl.graph.nodes)),
merge,
)
elif cl.type == ResourceType.LINEAR:
elif cl.cltype == ResourceType.LINEAR:
circ.add(
[idx for idx in range(photon_idx, photon_idx + len(cl.graph.nodes))],
linear_circuit(len(cl.graph.nodes)),
Expand Down Expand Up @@ -207,21 +216,24 @@ def apply_local_clifford(self, vops: dict[int, int]) -> None:
self._clifford_applied = True


def local_clifford_circuit(clifford_id: int) -> pcvl.Circuit:
def local_clifford_circuit(clifford_id: int | Clifford) -> pcvl.Circuit:
"""Create a Perceval Circuit for a local clifford.

Parameters
----------
mode_id : int
Mode id.
clifford_id : int
Clifford id.
clifford_id : int or Clifford
Clifford id (0-23) or Clifford enum.

Returns
-------
perceval.Circuit
Perceval Circuit for a local clifford.
"""
# Convert Clifford enum to int if needed
if isinstance(clifford_id, Clifford):
clifford_id = clifford_id.value
if not 0 <= clifford_id <= 23:
raise ValueError("clifford_id must be in [0, 23]")
circ = pcvl.Circuit(m=1, name="LOCAL CLIFFORD ID:" + str(clifford_id))
Expand Down
36 changes: 23 additions & 13 deletions graphix_perceval/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
import itertools
import sys
import warnings
from _collections_abc import dict_items
from enum import Enum

import perceval as pcvl
import sympy as sp
from _collections_abc import dict_items
from perceval.algorithm import Sampler
from perceval.utils import PostSelect
from tabulate import tabulate
Expand Down Expand Up @@ -76,15 +76,13 @@ def __init__(self, circuit: pcvl.Circuit, photons: list[Photon]):
self.input_state = None
self.output_states: dict[str, str] | None = None

def set_local_processor(self, backend: str, source: pcvl.Source = pcvl.Source(), name: str = None):
def set_local_processor(self, backend: str, name: str = None):
r"""Set the local computing backend.

Parameters
----------
backend : str
Name of a local backend.
source : :class:`perceval.Source` object, optional
Setting of single-photon source.
name : str, optional
Name for the processor.
"""
Expand All @@ -93,7 +91,7 @@ def set_local_processor(self, backend: str, source: pcvl.Source = pcvl.Source(),
self.to_perceval()
if self.processor is not None:
warnings.warn("The processor has already been set. The previous processor will be overwritten.")
self.processor = pcvl.Processor(backend=backend, m_circuit=self.circ, source=source, name=name)
self.processor = pcvl.Processor(backend=backend, m_circuit=self.circ, name=name)
self.backend = backend

self.set_input_state()
Expand Down Expand Up @@ -136,7 +134,7 @@ def set_input_state(self):
input_state = input_state + ">"

self.input_state = pcvl.BasicState(input_state)
self.processor.with_polarized_input(self.input_state) # not with_input (it will not work for polarized input)
self.processor.with_input(self.input_state)

def set_output_states(self):
r"""Set the output states.
Expand Down Expand Up @@ -198,12 +196,17 @@ def get_probability_distribution(
self.set_postselection()

sampler = Sampler(self.processor)
probs = PhotonDistribution(sampler.probs()["results"])
result = sampler.probs()

if format_result:
probs.replace_keys(self.output_states)
# Convert BSDistribution to PhotonDistribution
dist = {}
for state, prob in result['results'].items():
key = str(state)
if format_result and self.output_states and key in self.output_states:
key = self.output_states[key]
dist[key] = float(prob)

return probs
return PhotonDistribution(dist)

def sample(self, num_samples=1024, format_result: bool = True, postselection: bool = True) -> PhotonCount:
"""Run the MBQC pattern on IBMQ devices
Expand Down Expand Up @@ -241,11 +244,18 @@ def set_postselection(self):
"""Postselect the results according to the pattern."""
ps = PostSelect()
for ph in self.get_readout_photons():
ps.eq([2 * ph.id, 2 * ph.id + 1], 1)
ps_ = PostSelect(f"[{2*ph.id}, {2*ph.id + 1}] == 1")
ps.merge(ps_)
for ph in self.get_compute_photons():
ps.eq([2 * ph.id], 0).eq([2 * ph.id + 1], 1)
ps_ = PostSelect(f"[{2*ph.id}] == 0")
ps.merge(ps_)
ps_ = PostSelect(f"[{2*ph.id + 1}] == 1")
ps.merge(ps_)
for ph in self.get_witness_photons():
ps.eq([2 * ph.id], 0).eq([2 * ph.id + 1], 1)
ps_ = PostSelect(f"[{2*ph.id}] == 0")
ps.merge(ps_)
ps_ = PostSelect(f"[{2*ph.id + 1}] == 1")
ps.merge(ps_)

self.processor.set_postselection(ps)

Expand Down
2 changes: 1 addition & 1 deletion graphix_perceval/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.0.2"
__version__ = "0.0.3"
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
graphix>=0.2.8
perceval-quandela>=0.9.1
graphix>=0.3.0
perceval-quandela>=0.12.0
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@
"Development Status :: 4 - Beta",
"Environment :: Console",
"Intended Audience :: Science/Research",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Topic :: Scientific/Engineering :: Physics",
],
"python_requires": ">=3.8,<3.12",
"python_requires": ">=3.9,<3.14",
"install_requires": requirements,
"extras_require": {},
}
Expand Down
9 changes: 6 additions & 3 deletions tests/test_clifford.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import unittest

from graphix.clifford import CLIFFORD
from graphix_perceval.clifford import CLIFFORD_TO_PERCEVAL_BS, CLIFFORD_TO_PERCEVAL_POLAR
from sympy import matrix2numpy
import numpy as np
import perceval as pcvl
from graphix.clifford import CLIFFORD
from graphix_perceval.clifford import (
CLIFFORD_TO_PERCEVAL_BS,
CLIFFORD_TO_PERCEVAL_POLAR,
)
from sympy import matrix2numpy


class TestConverter(unittest.TestCase):
Expand Down
19 changes: 9 additions & 10 deletions tests/test_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import numpy as np
from graphix import Circuit

from graphix_perceval.converter import to_perceval
from graphix_perceval.experiment import PhotonDistribution

Expand All @@ -12,7 +11,7 @@ def test_sampling_circuit_wo_postselection(self):
circuit = Circuit(2)
circuit.h(1)
circuit.cnot(0, 1)
pattern = circuit.transpile()
pattern = circuit.transpile().pattern
pattern.standardize()
pattern.shift_signals()

Expand All @@ -28,7 +27,7 @@ def test_sampling_circuit_w_postselection(self):
circuit = Circuit(2)
circuit.h(1)
circuit.cnot(0, 1)
pattern = circuit.transpile()
pattern = circuit.transpile().pattern
pattern.standardize()
pattern.shift_signals()

Expand All @@ -44,7 +43,7 @@ def test_sampling_circuit_w_postselection(self):
def test_zero_state_creation_wo_pauli_meas(self):
circuit = Circuit(1) # initialize with |+>
circuit.h(0)
pattern = circuit.transpile()
pattern = circuit.transpile().pattern
pattern.standardize()
pattern.shift_signals()

Expand All @@ -60,7 +59,7 @@ def test_one_state_creation_wo_pauli_meas(self):
circuit = Circuit(1) # initialize with |+>
circuit.h(0)
circuit.x(0)
pattern = circuit.transpile()
pattern = circuit.transpile().pattern
pattern.standardize()
pattern.shift_signals()

Expand All @@ -76,7 +75,7 @@ def test_rotated_one_qubit_state_creation_wo_pauli_meas(self):
circuit = Circuit(1) # initialize with |+>
circuit.h(0)
circuit.rx(0, np.pi / 1.23)
pattern = circuit.transpile()
pattern = circuit.transpile().pattern
pattern.standardize()
pattern.shift_signals()

Expand All @@ -93,7 +92,7 @@ def test_bell_state_phi_plus_creation_wo_pauli_meas(self):
circuit = Circuit(2) # initialize with |+> \otimes |+>
circuit.h(1)
circuit.cnot(0, 1)
pattern = circuit.transpile()
pattern = circuit.transpile().pattern
pattern.standardize()
pattern.shift_signals()

Expand All @@ -110,7 +109,7 @@ def test_bell_state_phi_plus_creation_with_pauli_meas(self):
circuit = Circuit(2) # initialize with |+> \otimes |+>
circuit.h(1)
circuit.cnot(0, 1)
pattern = circuit.transpile()
pattern = circuit.transpile().pattern
pattern.standardize()
pattern.shift_signals()
pattern.perform_pauli_measurements()
Expand All @@ -130,7 +129,7 @@ def test_ghz_state_creation_with_pauli_meas(self):
circuit.h(2)
circuit.cnot(0, 1)
circuit.cnot(1, 2)
pattern = circuit.transpile()
pattern = circuit.transpile().pattern
pattern.standardize()
pattern.shift_signals()
pattern.perform_pauli_measurements()
Expand All @@ -149,7 +148,7 @@ def test_bell_state_and_ry_with_pauli_meas(self):
circuit.h(1)
circuit.cnot(0, 1)
circuit.ry(1, np.pi / 4)
pattern = circuit.transpile()
pattern = circuit.transpile().pattern
pattern.standardize()
pattern.shift_signals()
pattern.perform_pauli_measurements()
Expand Down
6 changes: 3 additions & 3 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[tox]
envlist = py38, py39, py310, lint
envlist = py39, py310, py311, py312, lint

[gh-actions]
python =
3.8: lint, py38
3.9: py39
3.9: lint, py39
3.10: py310
3.11: py311
3.12: py312

[testenv]
description = Run the unit tests
Expand Down