# -*- coding: utf-8 -*-
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================
"""Circuit module."""
from collections.abc import Iterable
from typing import List
import copy
import numpy as np
from rich.console import Console
import mindquantum.core.gates as G
from mindquantum.utils.type_value_check import _check_gate_type
from mindquantum.core.parameterresolver import ParameterResolver as PR
from mindquantum.core.parameterresolver.parameterresolver import ParameterResolver
from mindquantum.io import bprint
from mindquantum.io.display import brick_model
from mindquantum.utils.type_value_check import _check_input_type
from mindquantum.utils.type_value_check import _check_and_generate_pr_type
from mindquantum.utils.type_value_check import _check_gate_has_obj
from .utils import apply
GateSeq = List[G.BasicGate]
def _two_dim_array_to_list(data):
"""
Convert a two dimension array to a list of string.
"""
if len(data.shape) != 2:
raise ValueError("data need two dimensions, but get {} dimensions".format(len(data.shape)))
out_real = []
out_imag = []
for i in data:
out_real.append([])
out_imag.append([])
for j in i:
out_real[-1].append(str(float(np.real(j))))
out_imag[-1].append(str(float(np.imag(j))))
return [out_real, out_imag]
class CollectionMap:
"""A collection container."""
def __init__(self):
self.map = {}
def __str__(self):
return self.map.__str__()
def __repr__(self):
return self.map.__repr__()
def collect(self, keys):
"""collect items"""
if not isinstance(keys, list):
keys = [keys]
for k in keys:
if k not in self.map:
self.map[k] = 1
else:
self.map[k] += 1
def collect_only_one(self, keys, raise_msg):
"""collect item only single time, otherwise raise error"""
if not isinstance(keys, list):
keys = [keys]
for k in keys:
if k in self.map:
raise ValueError(raise_msg)
self.map[k] = 1
def delete(self, keys):
"""delete items"""
if not isinstance(keys, list):
keys = [keys]
for k in keys:
if k in self.map:
if self.map[k] == 1:
self.map.pop(k)
else:
self.map[k] -= 1
def num(self, k):
"""items count number"""
if k not in self.map:
return 0
return self.map[k]
def keys(self):
"""All items list"""
return list(self.map.keys())
@property
def size(self):
"""number of items"""
return len(self.map)
def __len__(self):
return self.size
def merge(self, other):
"""merge with other collection container"""
for k, v in other.map.items():
if k in self.map:
self.map[k] += v
else:
self.map[k] = v
def merge_only_one(self, other, raise_msg):
"""merge with other collection container"""
for k, _ in other.map.items():
if k in self.map:
raise ValueError(raise_msg)
self.map[k] = 1
def unmerge(self, other):
"""delete with other collection container"""
for k, v in other.map.items():
if k in self.map:
if self.map[k] <= v:
self.map.pop(k)
else:
self.map[k] -= v
def __copy__(self):
"""copy this container"""
out = CollectionMap()
out.merge(self)
return out
def __deepcopy__(self, memo):
"""deepcopy this container"""
out = CollectionMap()
out.merge(self)
return out
[docs]class Circuit(list):
"""
The quantum circuit module.
A quantum circuit contains one or more quantum gates, and can be evaluated
in a quantum simulator. You can build a quantum circuit very easy by add
a quantum gate or another circuit.
Args:
gates (BasicGate, list[BasicGate]): You can
initialize the quantum circuit by a single quantum gate or a
list of gates. gates: None.
Examples:
>>> from mindquantum import Circuit, RX, X
>>> circuit1 = Circuit()
>>> circuit1 += RX('a').on(0)
>>> circuit1 *= 2
>>> circuit1
q0: ──RX(a)────RX(a)──
>>> circuit2 = Circuit([X.on(0,1)])
>>> circuit3= circuit1 + circuit2
>>> assert len(circuit3) == 3
>>> circuit3.summary()
=======Circuit Summary=======
|Total number of gates : 3.|
|Parameter gates : 2.|
|with 1 parameters are : a.|
|Number qubit of circuit: 2 |
=============================
>>> circuit3
q0: ──RX(a)────RX(a)────X──
│
q1: ────────────────────●──
"""
def __init__(self, gates=None):
list.__init__([])
self.all_qubits = CollectionMap()
self.all_paras = CollectionMap()
self.all_measures = CollectionMap()
self.all_noises = CollectionMap()
if gates is not None:
if isinstance(gates, Iterable):
self.extend(gates)
else:
self.append(gates)
self.has_cpp_obj = False
[docs] def append(self, gate):
"""
Append a gate.
Args:
gate (BasicGate): The gate you want to append.
"""
_check_gate_type(gate)
_check_gate_has_obj(gate)
if isinstance(gate, G.Measure):
self.all_measures.collect_only_one(gate, f'measure key {gate.key} already exist.')
if isinstance(gate, G.PauliChannel):
self.all_noises.collect(gate.name)
self.all_qubits.collect(gate.obj_qubits)
self.all_qubits.collect(gate.ctrl_qubits)
if gate.parameterized:
self.all_paras.collect(list(gate.coeff.keys()))
super().append(gate)
self.has_cpp_obj = False
[docs] def extend(self, gates):
"""
Extend a circuit.
Args:
gates (Union[Circuit, list[BasicGate]]), A `Circuit` or a list of `BasicGate` you want to extend.
"""
if isinstance(gates, Circuit):
self.all_measures.merge_only_one(gates.all_measures, "Measure already exist.")
self.all_qubits.merge(gates.all_qubits)
self.all_paras.merge(gates.all_paras)
self.all_noises.merge(gates.all_noises)
super().extend(gates)
else:
for gate in gates:
self.append(gate)
self.has_cpp_obj = False
def __add__(self, gates):
out = Circuit()
out.extend(self)
if isinstance(gates, G.BasicGate):
out.append(gates)
else:
out.extend(gates)
return out
def __radd__(self, gates):
if isinstance(gates, int) and gates == 0:
return self
return Circuit(gates) + self
def __iadd__(self, gates):
if isinstance(gates, G.BasicGate):
self.append(gates)
elif isinstance(gates, Circuit):
self.extend(gates)
else:
raise TypeError("Require a quantum gate or a quantum circuit, but get {}.".format(type(gates)))
return self
def __mul__(self, num):
if not isinstance(num, int):
raise TypeError(f'{type(num)} object cannot be interpreted as an integer')
out = Circuit()
for _ in range(num):
out += copy.deepcopy(self)
return out
def __deepcopy__(self, memo):
res = Circuit()
for gate in self:
res.append(copy.deepcopy(gate))
return res
def __copy__(self):
res = Circuit()
for gate in self:
res.append(copy.deepcopy(gate))
return res
def __rmul__(self, num):
return self.__mul__(num)
def __setitem__(self, k, v):
_check_gate_type(v)
_check_gate_has_obj(v)
old_v = self[k]
self.all_qubits.delete(old_v.obj_qubits)
self.all_qubits.delete(old_v.ctrl_qubits)
if old_v.parameterized:
self.all_paras.delete(list(old_v.coeff.keys()))
if isinstance(old_v, G.Measure):
self.all_measures.delete(old_v)
if isinstance(old_v, G.PauliChannel):
self.all_noises.delete(old_v.name)
super().__setitem__(k, v)
self.all_qubits.collect(v.obj_qubits)
self.all_qubits.collect(v.ctrl_qubits)
if v.parameterized:
self.all_paras.collect(list(v.coeff.keys()))
if isinstance(v, G.Measure):
self.all_measures.collect_only_one(v, f'measure key {v.key} already exist.')
if isinstance(v, G.PauliChannel):
self.all_noises.collect(v.name)
self.has_cpp_obj = False
def __getitem__(self, sliced):
if isinstance(sliced, int):
return super().__getitem__(sliced)
return Circuit(super().__getitem__(sliced))
@property
def has_measure_gate(self):
"""
To check whether this circuit has measure gate.
Returns:
bool, whether this circuit has measure gate.
"""
return self.all_measures.size != 0
@property
def parameterized(self):
"""
To check whether this circuit is a parameterized quantum circuit.
Returns:
bool, whether this circuit is a parameterized quantum circuit.
"""
return self.all_paras.size != 0
@property
def is_noise_circuit(self):
"""
To check whether this circuit has pauli channel.
Returns:
bool, whether this circuit has pauli channel.
"""
return self.all_noises.size != 0
[docs] def insert(self, index, gates):
"""
Insert a quantum gate or quantum circuit in index.
Args:
index (int): Index to set gate.
gates (Union[BasicGate, list[BasicGate]]): Gates you need to insert.
"""
if isinstance(gates, G.BasicGate):
_check_gate_has_obj(gates)
_check_gate_type(gates)
super().insert(index, gates)
self.all_qubits.collect(gates.obj_qubits)
self.all_qubits.collect(gates.ctrl_qubits)
if gates.parameterized:
self.all_paras.collect(list(gates.coeff.keys()))
if isinstance(gates, G.Measure):
self.all_measures.collect_only_one(gates, f'measure key {gates.key} already exist.')
elif isinstance(gates, Iterable):
for gate in gates[::-1]:
self.insert(index, gate)
self.all_qubits.collect(gate.obj_qubits)
self.all_qubits.collect(gate.ctrl_qubits)
if gate.parameterized:
self.all_paras.collect(list(gate.coeff.keys()))
if isinstance(gate, G.Measure):
self.all_measures.collect_only_one(gate, f'measure key {gate.key} already exist.')
else:
raise TypeError("Unsupported type for quantum gate: {}".format(type(gates)))
self.has_cpp_obj = False
[docs] def no_grad(self):
"""
Set all parameterized gate in this quantum circuit not require grad.
"""
for gate in self:
gate.no_grad()
self.has_cpp_obj = False
return self
[docs] def requires_grad(self):
"""
Set all parameterized gates in this quantum circuit require grad.
"""
for gate in self:
gate.requires_grad()
self.has_cpp_obj = False
return self
[docs] def compress(self):
r"""
Remove all unused qubits, and map qubits to `range(n_qubits)`.
Examples:
>>> from mindquantum import qft
>>> qft([0, 2, 4])
q0: ──H────PS(π/2)────PS(π/4)─────────────────────────@──
│ │ │
q2: ──────────●──────────┼───────H────PS(π/2)─────────┼──
│ │ │
q4: ─────────────────────●───────────────●───────H────@──
>>> qft([0, 2, 4]).compress()
q0: ──H────PS(π/2)────PS(π/4)─────────────────────────@──
│ │ │
q1: ──────────●──────────┼───────H────PS(π/2)─────────┼──
│ │ │
q2: ─────────────────────●───────────────●───────H────@──
"""
circ = apply(self, list(range(len(self.all_qubits))))
return circ
def __str__(self):
return self.__repr__()
def __repr__(self):
from mindquantum.io.display._config import _CIRCUIT_STYLE
circ = self.compress()
s = brick_model(circ, sorted(self.all_qubits.map))
s = '\n'.join(s)
console = Console(record=True)
if not console.is_jupyter:
console.width = len(s)
with console.capture() as capture:
console.print(s, style=_CIRCUIT_STYLE['style'], width=len(s))
s = capture.get()
return s
def _repr_html_(self):
"""repr for jupyter nontebook"""
from mindquantum.io.display._config import CIRCUIT_HTML_FORMAT
from mindquantum.io.display._config import _CIRCUIT_STYLE
console = Console(record=True)
circ = self.compress()
s = brick_model(circ, sorted(self.all_qubits.map))
s = '\n'.join(s)
console.width = len(s)
with console.capture() as _:
console.print(s, style=_CIRCUIT_STYLE['style'], width=len(s))
s = console.export_html(code_format=CIRCUIT_HTML_FORMAT, inline_styles=True)
return '\n'.join(s.split('\n')[1:])
@property
def n_qubits(self):
if self.all_qubits:
return max(self.all_qubits.keys()) + 1
return 0
[docs] def summary(self, show=True):
"""
Print the information about current circuit, including block number,
gate number, non-parameterized gate number, parameterized gate number
and the total parameters.
Args:
show (bool): whether to show the information. Default: True.
Examples:
>>> from mindquantum import Circuit, RX, H
>>> circuit = Circuit([RX('a').on(1), H.on(1), RX('b').on(0)])
>>> circuit.summary()
=========Circuit Summary=========
|Total number of gates : 3. |
|Parameter gates : 2. |
|with 2 parameters are : a, b. |
|Number qubit of circuit: 2 |
=================================
"""
self.num_non_para_gate = 0
self.num_para_gate = 0
for gate in self:
if gate.parameterized:
self.num_para_gate += 1
else:
self.num_non_para_gate += 1
if show:
info = bprint([
'Total number of gates: {}.'.format(self.num_para_gate + self.num_non_para_gate),
'Parameter gates: {}.'.format(self.num_para_gate), 'with {} parameters are: {}{}'.format(
len(self.all_paras), ', '.join(self.all_paras.keys()[:10]),
('.' if len(self.all_paras) <= 10 else '...')), 'Number qubit of circuit: {}'.format(self.n_qubits)
],
title='Circuit Summary')
for i in info:
print(i)
[docs] def hermitian(self):
"""
Get the hermitian of this quantum circuit.
Examples:
>>> from mindquantum.core import Circuit
>>> from mindquantum.core import RX
>>> circ = Circuit(RX({'a': 0.2}).on(0))
>>> herm_circ = circ.hermitian()
>>> herm_circ[0].coeff
{'a': -0.2}
"""
return Circuit([gate.hermitian() for gate in self[::-1]])
[docs] def parameter_resolver(self):
"""
Get the parameter resolver of the whole circuit.
Note:
This parameter resolver only tells you what are the parameters of
this quantum circuit, and which part of parameters need grad, since
the same parameter can be in different gate, and the coefficient
can be different. The detail parameter resolver that shows the
coefficient is in each gate of the circuit.
Returns:
ParameterResolver, the parameter resolver of the whole circuit.
"""
pr = PR(self.all_paras.map)
pr *= 0
return pr
@property
def params_name(self):
"""
Get the parameter name of this circuit.
Returns:
list, a list that contains the parameter name.
Examples:
>>> from mindquantum.core.gates import RX
>>> from mindquantum.core.circuit import Circuit
>>> circuit = Circuit(RX({'a': 1, 'b': 2}).on(0))
>>> circuit.params_name
['a', 'b']
"""
return list(self.all_paras.keys())
[docs] def matrix(self, pr=None, big_end=False, backend='projectq', seed=None):
"""
Get the matrix of this circuit.
Args:
pr (ParameterResolver, dict, numpy.ndarray, list, numbers.Number): The parameter
resolver for parameterized quantum circuit. Default: None.
big_end (bool): The low index qubit is place in the end or not. Default: False.
backend (str): The backend to do simulation. Default: 'projectq'.
seed (int): The random to generate circuit matrix, if the circuit has noise channel.
Examples:
>>> from mindquantum.core import Circuit
>>> circuit = Circuit().rx('a',0).h(0)
>>> circuit.matrix({'a': 1.0})
array([[ 0.62054458-0.33900505j, 0.62054458-0.33900505j],
[ 0.62054458+0.33900505j, -0.62054458-0.33900505j]])
Returns:
numpy.ndarray, two dimensional complex matrix of this circuit.
"""
_check_input_type('big_end', bool, big_end)
if big_end:
circ = apply(self, list(range(self.n_qubits))[::-1])
else:
circ = self
if pr is None:
pr = ParameterResolver()
pr = _check_and_generate_pr_type(pr, self.params_name)
if self.has_measure_gate:
raise ValueError("This circuit cannot have measurement gate.")
from mindquantum.simulator import Simulator
sim = Simulator(backend, self.n_qubits, seed=seed)
m = np.array(sim.sim.get_circuit_matrix(circ.get_cpp_obj(), pr.get_cpp_obj())).T
return m
@property
def is_measure_end(self):
"""
Check whether the circuit is end with measurement gate that there is at most one measurement
gate that act on each qubit, and this measurement gate should be at end of gate serial of
this qubit.
Returns:
bool, whether the circuit is end with measurement.
"""
circ = self.remove_barrier()
high = [0 for i in range(self.n_qubits)]
for gate in circ:
for idx in set(gate.obj_qubits + gate.ctrl_qubits):
high[idx] += 1
if isinstance(gate, G.Measure):
m_idx = gate.obj_qubits[0]
if high[m_idx] != self.all_qubits.map[m_idx]:
return False
return True
[docs] def apply_value(self, pr):
"""
Convert this circuit to a non parameterized circuit with parameter you input.
Args:
pr (Union[dict, ParameterResolver]): parameters you want to apply into this circuit.
Returns:
Circuit, a non parameterized circuit.
Examples:
>>> from mindquantum.core.gates import X, RX
>>> from mindquantum.core.circuit import Circuit
>>> circuit = Circuit()
>>> circuit += X.on(0)
>>> circuit += RX({'a': 2}).on(0)
>>> circuit = circuit.apply_value({'a': 1.5})
>>> circuit
q0: ──X────RX(3)──
"""
circuit = Circuit()
for gate in self:
if not gate.parameterized:
circuit += gate
else:
if set(gate.coeff.params_name).issubset(pr):
coeff = gate.coeff.combination(pr)
else:
coeff = 1 * gate.coeff
circuit += gate.__class__(coeff).on(gate.obj_qubits, gate.ctrl_qubits)
return circuit
[docs] def remove_barrier(self):
"""Remove all barrier gates"""
circ = Circuit()
for g in self:
if not isinstance(g, G.BarrierGate):
circ += g
return circ
[docs] def remove_measure(self):
"""Remove all measure gate."""
circ = Circuit()
for g in self:
if not isinstance(g, G.Measure):
circ += g
return circ
[docs] def remove_measure_on_qubits(self, qubits):
"""
Remove all measure gate on some certain qubits.
Args:
qubit (Union[int, list[int]]): The qubits you want to remove measure.
Examples:
>>> from mindquantum import UN, H, Measure
>>> circ = UN(H, 3).x(0, 1).x(1, 2).measure_all()
>>> circ += H.on(0)
>>> circ += Measure('q0_1').on(0)
>>> circ.remove_measure_on_qubits(0)
q0: ──H────X────H───────────
│
q1: ──H────●────X────M(q1)──
│
q2: ──H─────────●────M(q2)──
"""
if not isinstance(qubits, list):
qubits = [qubits]
circ = Circuit()
for gate in self:
if isinstance(gate, G.Measure) and gate.obj_qubits[0] in qubits:
continue
circ += gate
return circ
[docs] def get_cpp_obj(self, hermitian=False):
"""
Get cpp obj of circuit.
Args:
hermitian (bool): Whether to get cpp object of this circuit in hermitian version. Default: False.
"""
if not self.has_cpp_obj:
self.has_cpp_obj = True
self.cpp_obj = [i.get_cpp_obj() for i in self if not isinstance(i, G.BarrierGate)]
self.herm_cpp_obj = [i.get_cpp_obj() for i in self.hermitian() if not isinstance(i, G.BarrierGate)]
if hasattr(self, 'cpp_obj') and hasattr(self, 'herm_cpp_obj'):
if hermitian:
return self.herm_cpp_obj
return self.cpp_obj
raise ValueError("Circuit does not generate cpp obj yet.")
[docs] def h(self, obj_qubits, ctrl_qubits=None):
"""
Add a hadamard gate.
Args:
obj_qubits (Union[int, list[int]]): The object qubits of `H` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `H` gate. Default: None.
"""
self.append(G.H.on(obj_qubits, ctrl_qubits))
return self
[docs] def x(self, obj_qubits, ctrl_qubits=None):
"""
Add a X gate.
Args:
obj_qubits (Union[int, list[int]]): The object qubits of `X` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `X` gate. Default: None.
"""
self.append(G.X.on(obj_qubits, ctrl_qubits))
return self
[docs] def y(self, obj_qubits, ctrl_qubits=None):
"""
Add a Y gate.
Args:
obj_qubits (Union[int, list[int]]): The object qubits of `Y` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `Y` gate. Default: None.
"""
self.append(G.Y.on(obj_qubits, ctrl_qubits))
return self
[docs] def z(self, obj_qubits, ctrl_qubits=None):
"""
Add a Z gate.
Args:
obj_qubits (Union[int, list[int]]): The object qubits of `Z` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `Z` gate. Default: None.
"""
self.append(G.Z.on(obj_qubits, ctrl_qubits))
return self
[docs] def s(self, obj_qubits, ctrl_qubits=None):
"""
Add a S gate.
Args:
obj_qubits (Union[int, list[int]]): The object qubits of `S` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `S` gate. Default: None.
"""
self.append(G.S.on(obj_qubits, ctrl_qubits))
return self
[docs] def swap(self, obj_qubits, ctrl_qubits=None):
"""
Add a SWAP gate.
Args:
obj_qubits (Union[int, list[int]]): The object qubits of `SWAP` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `SWAP` gate. Default: None.
"""
self.append(G.SWAP.on(obj_qubits, ctrl_qubits))
return self
[docs] def rx(self, para, obj_qubits, ctrl_qubits=None):
"""
Add a RX gate.
Args:
para (Union[dict, ParameterResolver]): The parameter for `RX` gate.
obj_qubits (Union[int, list[int]]): The object qubits of `RX` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `RX` gate. Default: None.
"""
self.append(G.RX(para).on(obj_qubits, ctrl_qubits))
return self
[docs] def ry(self, para, obj_qubits, ctrl_qubits=None):
"""
Add a RY gate.
Args:
para (Union[dict, ParameterResolver]): The parameter for `RY` gate.
obj_qubits (Union[int, list[int]]): The object qubits of `RY` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `RY` gate. Default: None.
"""
self.append(G.RY(para).on(obj_qubits, ctrl_qubits))
return self
[docs] def rz(self, para, obj_qubits, ctrl_qubits=None):
"""
Add a RZ gate.
Args:
para (Union[dict, ParameterResolver]): The parameter for `RZ` gate.
obj_qubits (Union[int, list[int]]): The object qubits of `RZ` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `RZ` gate. Default: None.
"""
self.append(G.RZ(para).on(obj_qubits, ctrl_qubits))
return self
[docs] def phase_shift(self, para, obj_qubits, ctrl_qubits=None):
"""
Add a Phase Shift gate.
Args:
para (Union[dict, ParameterResolver]): The parameter for `PhaseShift` gate.
obj_qubits (Union[int, list[int]]): The object qubits of `PhaseShift` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `PhaseShift` gate. Default: None."""
self.append(G.PhaseShift(para).on(obj_qubits, ctrl_qubits))
return self
[docs] def xx(self, para, obj_qubits, ctrl_qubits=None):
"""
Add a XX gate.
Args:
para (Union[dict, ParameterResolver]): The parameter for `XX` gate.
obj_qubits (Union[int, list[int]]): The object qubits of `XX` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `XX` gate. Default: None.
"""
self.append(G.XX(para).on(obj_qubits, ctrl_qubits))
return self
[docs] def yy(self, para, obj_qubits, ctrl_qubits=None):
"""
Add a YY gate.
Args:
para (Union[dict, ParameterResolver]): The parameter for `YY` gate.
obj_qubits (Union[int, list[int]]): The object qubits of `YY` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `YY` gate. Default: None.
"""
self.append(G.YY(para).on(obj_qubits, ctrl_qubits))
return self
[docs] def zz(self, para, obj_qubits, ctrl_qubits=None):
"""
Add a ZZ gate.
Args:
para (Union[dict, ParameterResolver]): The parameter for `ZZ` gate.
obj_qubits (Union[int, list[int]]): The object qubits of `ZZ` gate.
ctrl_qubits (Union[int, list[int]]): the control qubits of `ZZ` gate. Default: None.
"""
self.append(G.ZZ(para).on(obj_qubits, ctrl_qubits))
return self
[docs] def measure(self, key, obj_qubit=None):
"""
Add a measure gate.
Args:
key (Union[int, str]): If `obj_qubit` is None, then `key` should be a int and means which qubit to measure,
otherwise, `key` should be a str and means the name of this measure gate.
obj_qubit (int): Which qubit to measure. Default: None.
"""
if obj_qubit is None:
self.append(G.Measure().on(key))
else:
self.append(G.Measure(key).on(obj_qubit))
return self
[docs] def measure_all(self, subfix=None):
"""
Measure all qubits
Args:
subfix (str): The subfix string you want to add to the name of measure gate.
"""
for i in range(self.n_qubits):
s = f"q{i}" if subfix is None else f"q{i}_{subfix}"
self += G.Measure(s).on(i)
return self
[docs] def barrier(self, show=True):
"""
Add a barrier.
Args:
show (bool): Whether show barrier or not. Default: True.
"""
_check_input_type('show', bool, show)
self.append(G.BarrierGate(show))
return self
[docs] def un(self, gate, maps_obj, maps_ctrl=None):
"""
Map a quantum gate to different objective qubits and control qubits.
Please refers to UN.
Args:
gate (BasicGate): The BasicGate you want to map.
map_obj (Union[int, list[int]]): object qubits.
maps_ctrl (Union[int, list[int]]): control qubits. Default: None.
"""
from mindquantum import UN
self += UN(gate, maps_obj, maps_ctrl)
return self
[docs] def get_qs(self, backend='projectq', pr=None, ket=False, seed=None):
"""
Get the final quantum state of this circuit.
Args:
backend (str): Which backend you want to use. Default: 'projectq'.
pr (Union[numbers.Number, ParameterResolver, dict, numpy.ndarray]): The parameter of this circuit,
if this circuit is parameterized. Default: None.
ket (str): Whether to return the quantum state in ket format. Default: False.
seed (int): The random seed of simulator. Default: None
"""
from mindquantum import Simulator
sim = Simulator(backend, self.n_qubits, seed)
sim.apply_circuit(self, pr)
return sim.get_qs(ket)
[docs] def reverse_qubits(self):
"""
Flip the circuit to big endian.
Examples:
>>> from mindquantum.core import Circuit
>>> circ = Circuit().h(0).x(2, 0).y(3).x(3, 2)
>>> circ
q0: ──H────●───────
│
q2: ───────X────●──
│
q3: ──Y─────────X──
>>> circ.reverse_qubits()
q0: ──Y─────────X──
│
q1: ───────X────●──
│
q3: ──H────●───────
"""
return apply(self, [self.n_qubits - 1 - i for i in self.all_qubits.keys()])
[docs] def svg(self, style=None):
"""
Display current quantum circuit into SVG picture in jupyter notebook.
Args:
style (dict, str): the style to set svg circuit. Currently, we support
'official', 'light' and 'dark'. Default: None.
"""
from mindquantum.io.display.circuit_svg_drawer import SVGCircuit
from mindquantum.io.display._config import _svg_config_dark
from mindquantum.io.display._config import _svg_config_light
from mindquantum.io.display._config import _svg_config_official
supported_style = {
'official': _svg_config_official,
'dark': _svg_config_dark,
'light': _svg_config_light,
}
if style is None:
style = _svg_config_official
if isinstance(style, str):
if style not in supported_style:
raise ValueError(f"Style not found, currently we support {list(supported_style.keys())}")
style = supported_style[style]
return SVGCircuit(self, style)
__all__ = ['Circuit']