Qibo circuit convertor
This commit is contained in:
committed by
Alessandro Candido
parent
d1721ae37a
commit
6838faba33
107
src/qibotn/QiboCircuitConvertor.py
Normal file
107
src/qibotn/QiboCircuitConvertor.py
Normal file
@@ -0,0 +1,107 @@
|
||||
|
||||
import cupy as cp
|
||||
import numpy as np
|
||||
|
||||
EINSUM_SYMBOLS_BASE = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
|
||||
class QiboCircuitToEinsum:
|
||||
def __init__(self, circuit, dtype='complex128'):
|
||||
|
||||
self.backend = cp
|
||||
self.dtype = getattr(self.backend, dtype)
|
||||
|
||||
self.input_tensor_counter = np. zeros((circuit.nqubits,))
|
||||
self.gates = []
|
||||
for gate in circuit.queue:
|
||||
targets = list(gate.target_qubits)
|
||||
for target in targets:
|
||||
self.input_tensor_counter[target] = self.input_tensor_counter[target] + 1
|
||||
controls = list(gate.control_qubits)
|
||||
for control in controls:
|
||||
self.input_tensor_counter[control] = self.input_tensor_counter[control] + 1
|
||||
gate_qubits = controls + targets
|
||||
self.gates.append((cp.asarray(gate.matrix).reshape((2,) * 2 * len(gate_qubits)), gate_qubits))
|
||||
|
||||
self.qubit_name = [indx for indx, value in enumerate(self.input_tensor_counter) if value > 0]
|
||||
|
||||
def state_vector(self):
|
||||
|
||||
input_tensor_count = np.count_nonzero(self.input_tensor_counter)
|
||||
|
||||
input_operands = self._get_bitstring_tensors('0'*input_tensor_count, self.dtype, backend=self.backend)
|
||||
|
||||
mode_labels, qubits_frontier, next_frontier = self._init_mode_labels_from_qubits(self.qubit_name)
|
||||
|
||||
gate_mode_labels, gate_operands = self._parse_gates_to_mode_labels_operands(self.gates,
|
||||
qubits_frontier,
|
||||
next_frontier)
|
||||
|
||||
operands = input_operands + gate_operands
|
||||
mode_labels += gate_mode_labels
|
||||
|
||||
expression = self._convert_mode_labels_to_expression(mode_labels, qubits_frontier)
|
||||
|
||||
return expression, operands
|
||||
|
||||
def _get_symbol(self,i):
|
||||
"""
|
||||
Return a Unicode as label for index.
|
||||
|
||||
.. note:: This function is adopted from `opt_einsum <https://optimized-einsum.readthedocs.io/en/stable/_modules/opt_einsum/parser.html#get_symbol>`_
|
||||
"""
|
||||
if i < 52:
|
||||
return EINSUM_SYMBOLS_BASE[i]
|
||||
return chr(i + 140)
|
||||
|
||||
def _init_mode_labels_from_qubits(self,qubits):
|
||||
|
||||
frontier_dict ={}
|
||||
n = len(qubits)
|
||||
for x in range(n):
|
||||
frontier_dict[qubits[x]]=x
|
||||
return [[i] for i in range(n)], frontier_dict, n
|
||||
|
||||
def _get_bitstring_tensors(self, bitstring, dtype=np.complex128, backend=cp):
|
||||
|
||||
asarray = backend.asarray #_get_backend_asarray_func(backend)
|
||||
state_0 = asarray([1, 0], dtype=dtype)
|
||||
state_1 = asarray([0, 1], dtype=dtype)
|
||||
|
||||
basis_map = {'0': state_0,
|
||||
'1': state_1}
|
||||
|
||||
operands = [basis_map[ibit] for ibit in bitstring]
|
||||
return operands
|
||||
|
||||
def _parse_gates_to_mode_labels_operands(
|
||||
self,
|
||||
gates,
|
||||
qubits_frontier,
|
||||
next_frontier
|
||||
):
|
||||
|
||||
mode_labels = []
|
||||
operands = []
|
||||
|
||||
for tensor, gate_qubits in gates:
|
||||
operands.append(tensor)
|
||||
input_mode_labels = []
|
||||
output_mode_labels = []
|
||||
for q in gate_qubits:
|
||||
input_mode_labels.append(qubits_frontier[q])
|
||||
output_mode_labels.append(next_frontier)
|
||||
qubits_frontier[q] = next_frontier
|
||||
next_frontier += 1
|
||||
mode_labels.append(output_mode_labels+input_mode_labels)
|
||||
return mode_labels, operands
|
||||
|
||||
def _convert_mode_labels_to_expression(self,input_mode_labels, output_mode_labels):
|
||||
|
||||
out_list = []
|
||||
for key in output_mode_labels:
|
||||
out_list.append(output_mode_labels[key])
|
||||
|
||||
input_symbols = [''.join(map(self._get_symbol, idx)) for idx in input_mode_labels]
|
||||
expression = ','.join(input_symbols) + '->' + ''.join(map(self._get_symbol, out_list))
|
||||
|
||||
return expression
|
||||
@@ -1,5 +1,11 @@
|
||||
import argparse
|
||||
from qibotn import qasm_quimb
|
||||
from timeit import default_timer as timer
|
||||
|
||||
from qibotn import quimb as qiboquimb
|
||||
from QiboCircuitConvertor import QiboCircuitToEinsum
|
||||
from cuquantum import contract
|
||||
import cupy as cp
|
||||
from qibo.models import *
|
||||
|
||||
|
||||
def parser():
|
||||
@@ -12,7 +18,65 @@ def parser():
|
||||
|
||||
def main(args: argparse.Namespace):
|
||||
print("Testing for %d nqubits" % (args.nqubits))
|
||||
qasm_quimb.eval_QI_qft(args.nqubits, args.qasm_circ, args.init_state)
|
||||
qiboquimb.eval(args.nqubits, args.qasm_circ, args.init_state)
|
||||
|
||||
|
||||
def parser_cuquantum():
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
"--nqubits", default=10, type=int, help="Number of quibits in the circuits."
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--circuit",
|
||||
default="qft",
|
||||
type=str,
|
||||
help="Type of circuit to use. See README for the list of "
|
||||
"available circuits.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--precision",
|
||||
default="complex128",
|
||||
type=str,
|
||||
help="Numerical precision of the simulation. "
|
||||
"Choose between 'complex128' and 'complex64'.",
|
||||
)
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main_cuquantum(args: argparse.Namespace):
|
||||
print("Testing for %d nqubits" % (args.nqubits))
|
||||
nqubits = args.nqubits
|
||||
circuit_name = args.circuit
|
||||
datatype = args.precision
|
||||
# Create qibo quibit
|
||||
|
||||
if circuit_name in ("qft", "QFT"):
|
||||
circuit = QFT(nqubits)
|
||||
else:
|
||||
raise NotImplementedError(f"Cannot find circuit {circuit_name}.")
|
||||
|
||||
myconvertor = QiboCircuitToEinsum(circuit, dtype=datatype)
|
||||
|
||||
expression, operands = myconvertor.state_vector()
|
||||
|
||||
start = timer()
|
||||
result_qibo = circuit()
|
||||
end = timer()
|
||||
circuit_eval_time = end - start
|
||||
print("Simulation time: Qibo =", circuit_eval_time, "s")
|
||||
|
||||
start = timer()
|
||||
sv_cutn = contract(expression, *operands)
|
||||
end = timer()
|
||||
circuit_eval_time = end - start
|
||||
print("Simulation time: cuQuantum cuTensorNet =", circuit_eval_time, "s")
|
||||
|
||||
# print(f"is sv in agreement?", cp.allclose(sv_cutn.flatten(), result_qibo.state(numpy=True)))
|
||||
assert cp.allclose(sv_cutn.flatten(), result_qibo.state(numpy=True))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user