Skip to content

Commit

Permalink
Merge pull request #203 from lss0208/master
Browse files Browse the repository at this point in the history
fix some bug
  • Loading branch information
Zhaoyilunnn authored Dec 23, 2024
2 parents 1471e50 + da53daf commit f674616
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 116 deletions.
12 changes: 6 additions & 6 deletions quafu/algorithms/gradients/gradiant.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def assemble_grads(para_grads, gate_grads):
return grads


def grad_para_shift(qc: QuantumCircuit, hamiltonian, backend=SVSimulator()):
def grad_para_shift(qc: QuantumCircuit, hamiltonian, backend=SVSimulator(), psi_in = np.array([], dtype=complex)):
"""
Parameter shift gradients. Each gate must have one parameter
"""
Expand All @@ -50,23 +50,23 @@ def grad_para_shift(qc: QuantumCircuit, hamiltonian, backend=SVSimulator()):
" You may need compile the circuit first"
)
op.paras[0] = op.paras[0] + np.pi / 2
res1 = sum(backend.run(qc, hamiltonian=hamiltonian)["pauli_expects"])
res1 = sum(backend.run(qc, hamiltonian=hamiltonian, psi=psi_in)["pauli_expects"])
op.paras[0] = op.paras[0] - np.pi
res2 = sum(backend.run(qc, hamiltonian=hamiltonian)["pauli_expects"])
res2 = sum(backend.run(qc, hamiltonian=hamiltonian, psi=psi_in)["pauli_expects"])
op.paras[0]._undo(2)
gate_grads[i].append((res1 - res2) / 2.0)

return assemble_grads(para_grads, gate_grads)


def grad_finit_diff(qc, hamiltonian, backend=SVSimulator()):
def grad_finit_diff(qc, hamiltonian, backend=SVSimulator(), psi_in = np.array([], dtype=complex)):
variables = qc.variables
grads = []
for v in variables:
v.value += 1e-10
res1 = sum(backend.run(qc, hamiltonian=hamiltonian)["pauli_expects"])
res1 = sum(backend.run(qc, hamiltonian=hamiltonian, psi=psi_in)["pauli_expects"])
v.value -= 2 * 1e-10
res2 = sum(backend.run(qc, hamiltonian=hamiltonian)["pauli_expects"])
res2 = sum(backend.run(qc, hamiltonian=hamiltonian, psi=psi_in)["pauli_expects"])
v.value += 1e-10
grads.append((res1 - res2) / (2 * 1e-10))

Expand Down
15 changes: 9 additions & 6 deletions quafu/circuits/quantum_circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
Reset,
UnitaryDecomposer,
XYResonance,
KrausChannel,
UnitaryChannel
)
from ..elements import element_gates as qeg
from ..exceptions import CircuitError
Expand Down Expand Up @@ -175,24 +177,25 @@ def add_ins(self, ins: Instruction):

# pylint: disable=too-many-branches
def add_noise(
self, channel: str, channel_args, qubits: Union[None, List[int]] = None, gates: Union[None, List[str]] = None
):
self, channel: str, channel_args, qubits: Union[None, List[int]] = None, gates: Union[None, List[str]] = None, checkgates=True):
if qubits is None:
qubits = []
if gates is None:
gates = []
if channel not in ["bitflip", "dephasing", "depolarizing", "ampdamping"]:
raise ValueError("Invalid channel name")

for g in gates:
if g not in QuantumGate.gate_classes:
raise ValueError("Invalid gate name")
if checkgates:
for g in gates:
if g not in QuantumGate.gate_classes:
raise ValueError("Invalid gate name")

newinstructions = []
newgates = []
for op in self.instructions:
newinstructions.append(op)
if isinstance(op, (QuantumGate, Delay, Barrier, XYResonance)):
if isinstance(op, (QuantumGate, Delay, Barrier, XYResonance, KrausChannel,
UnitaryChannel)):
newgates.append(op)
if isinstance(op, QuantumGate):
add_q = False
Expand Down
182 changes: 91 additions & 91 deletions quafu/circuits/quantum_register.py
Original file line number Diff line number Diff line change
@@ -1,91 +1,91 @@
# (C) Copyright 2023 Beijing Academy of Quantum Information Sciences
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Quantum register module."""
from collections import OrderedDict


class Qubit:
"""
Representation of logical qubits.
"""

def __init__(
self,
logic_pos: int,
reg_name: str = None,
label: str = None,
):
self.pos = logic_pos
self.reg_name = "q" if reg_name is None else reg_name
self.label = self.reg_name if label is None else label
self.physical_info = None
self._depth = 0 # present depth

def __repr__(self):
return f"{self.reg_name}_{self.pos}"

def load_physical_info(self, *args, **kwargs):
raise NotImplementedError

@property
def used(self):
return self._depth > 0

def add_depth(self, num: int = 1):
self._depth += num

def move_pos(self, new_pos) -> int:
old_pos = self.pos
self.pos = new_pos
return old_pos # noqa:R504


class QuantumRegister:
"""
Collection of Qubit(s)
"""

def __init__(self, num: int = 0, name: str = None):
self.name = name
self.qubits = OrderedDict({i: Qubit(logic_pos=i, reg_name=name) for i in range(num)})

def __getitem__(self, item):
if item < len(self.qubits):
return self.qubits[item]
raise IndexError("Index out of range:", item)

def __iter__(self):
self._i = 0 # pylint: disable=attribute-defined-outside-init
return self

def __next__(self):
if self._i < len(self):
x = self._i
self._i += 1
return self.qubits[x]
raise StopIteration

def __len__(self):
return len(self.qubits)

def __add__(self, other: "QuantumRegister"):
qreg = QuantumRegister(name=self.name)
qreg.qubits = {
**{self.qubits},
**{i + len(self): qubit for i, qubit in other.qubits.items()},
}
return QuantumRegister(len(self) + len(other), name=self.name)

def exchange(self, p1, p2):
pass
# (C) Copyright 2023 Beijing Academy of Quantum Information Sciences
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Quantum register module."""
from collections import OrderedDict


class Qubit:
"""
Representation of logical qubits.
"""

def __init__(
self,
logic_pos: int,
reg_name: str = None,
label: str = None,
):
self.pos = logic_pos
self.reg_name = "q" if reg_name is None else reg_name
self.label = self.reg_name if label is None else label
self.physical_info = None
self._depth = 0 # present depth

def __repr__(self):
return f"{self.reg_name}_{self.pos}"

def load_physical_info(self, *args, **kwargs):
raise NotImplementedError

@property
def used(self):
return self._depth > 0

def add_depth(self, num: int = 1):
self._depth += num

def move_pos(self, new_pos) -> int:
old_pos = self.pos
self.pos = new_pos
return old_pos # noqa:R504


class QuantumRegister:
"""
Collection of Qubit(s)
"""

def __init__(self, num: int = 0, name: str = None):
self.name = name
self.qubits = OrderedDict({i: Qubit(logic_pos=i, reg_name=name) for i in range(num)})

def __getitem__(self, item):
if item < len(self.qubits):
return self.qubits[item]
raise IndexError("Index out of range:", item)

def __iter__(self):
self._i = 0 # pylint: disable=attribute-defined-outside-init
return self

def __next__(self):
if self._i < len(self):
x = self._i
self._i += 1
return self.qubits[x]
raise StopIteration

def __len__(self):
return len(self.qubits)

def __add__(self, other: "QuantumRegister"):
qreg = QuantumRegister(name=self.name)
qreg.qubits = {
**{self.qubits},
**{i + len(self): qubit for i, qubit in other.qubits.items()},
}
return QuantumRegister(len(self) + len(other), name=self.name)

def exchange(self, p1, p2):
pass
38 changes: 26 additions & 12 deletions quafu/results/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,22 +142,36 @@ def probabilities(self):
def counts(self):
return self["counts"]

def calc_probabilities(self):
psi = self.get_statevector()
def calc_probabilities(self, from_counts=False):
num = self["qbitnum"]
measures = list(self["measures"].keys())
values_tmp = list(self["measures"].values())
values = np.argsort(values_tmp)
if from_counts and self._meta_data['counts']:
counts = self._meta_data["counts"]
total_counts = sum(counts.values())
probabilities = {}
for key in self._meta_data["counts"]:
probabilities[key] = counts[key] / total_counts
self._probabilities = np.zeros(2**num)
for key in probabilities:
self._probabilities[int(key, 2)] = probabilities[key]

# pylint: disable=import-outside-toplevel
from quafu.simulators.default_simulator import permutebits, ptrace
elif "statevector" in self._meta_data.keys():
psi = self.get_statevector()
measures = list(self["measures"].keys())
values_tmp = list(self["measures"].values())
values = np.argsort(values_tmp)

psi = permutebits(psi, range(num)[::-1])
if measures:
self._probabilities = ptrace(psi, measures)
self._probabilities = permutebits(self._probabilities, values)
# pylint: disable=import-outside-toplevel
from quafu.simulators.default_simulator import permutebits, ptrace

psi = permutebits(psi, range(num)[::-1])
if measures:
self._probabilities = ptrace(psi, measures)
self._probabilities = permutebits(self._probabilities, values)
else:
self._probabilities = np.abs(psi) ** 2
else:
self._probabilities = np.abs(psi) ** 2
raise ValueError("No data saved for probs")


def plot_probabilities(
self,
Expand Down
2 changes: 1 addition & 1 deletion quafu/simulators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def simulate(
qc: Union[QuantumCircuit, str],
psi: np.ndarray = np.array([]),
simulator: str = "statevector",
shots: int = 100,
shots: int = 0,
hamiltonian=None,
use_gpu: bool = False,
use_custatevec: bool = False,
Expand Down
2 changes: 2 additions & 0 deletions src/qfvm/instructions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Instruction {
Instruction(){};
Instruction(string const& name, vector<pos_t> const& positions) : name_(name), positions_(positions) {
}
virtual ~Instruction() = default;
string name() const {
return name_;
}
Expand All @@ -38,6 +39,7 @@ class Instruction {
return !(name_ == "empty");
}


// interface
virtual vector<double> paras() const {
return {};
Expand Down
4 changes: 4 additions & 0 deletions tests/quafu/simulator/basis_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ def test_measure_atlast_collapse(self):
self.circuit = BellCircuits.bell_measure_atlast()
result = simulate(qc=self.circuit)
probs = result.probabilities
# print(probs)
self.assertAlmostEqual(probs[0], 1 / 2)
self.assertAlmostEqual(probs[1], 0)
self.assertAlmostEqual(probs[2], 0)
Expand Down Expand Up @@ -314,3 +315,6 @@ def test_anycbit_measure(self):
result = simulate(qc=self.circuit, shots=10, simulator="clifford")
counts = result.counts
self.assert_dict_almost_equal(counts, {"0101": 10})

if __name__ == "__main__":
TestSimulatorBasis().test_measure_atlast_collapse()

0 comments on commit f674616

Please sign in to comment.