Skip to content

Commit

Permalink
Merge pull request #192 from BoxiLi/cleaning
Browse files Browse the repository at this point in the history
- Remove some unnecessary branching that was used for the compatibility of `qutip-v5`. They are no longer needed in the new alpha version.
- Update the pulse paper examples to be compatible with `qutip-v5`.
- Update the documentation to be compatible with `qutip-v5`.
  • Loading branch information
BoxiLi committed Mar 5, 2023
2 parents fd84732 + 06ec33b commit 2eccfec
Show file tree
Hide file tree
Showing 16 changed files with 34 additions and 45 deletions.
10 changes: 4 additions & 6 deletions doc/pulse-paper/customize.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,13 @@
import numpy as np
from qutip import (
fidelity, sigmax, sigmay, sigmaz, basis, qeye, tensor, Qobj, fock_dm)
from qutip_qip.circuit import QubitCircuit, Gate
from qutip_qip.circuit import QubitCircuit
from qutip_qip.operations import Gate
from qutip_qip.device import ModelProcessor, Model
from qutip_qip.compiler import GateCompiler, Instruction
import qutip
from packaging.version import parse as parse_version
if parse_version(qutip.__version__) < parse_version('5.dev'):
from qutip import Options as SolverOptions
else:
from qutip import SolverOptions
from qutip import Options
from qutip_qip.noise import Noise


Expand Down Expand Up @@ -219,7 +217,7 @@ def single_crosstalk_simulation(num_gates):
init_state = tensor(
[Qobj([[init_fid, 0], [0, 0.025]]), Qobj([[init_fid, 0], [0, 0.025]])]
)
options = SolverOptions(nsteps=10000) # increase the maximal allowed steps
options = Options(nsteps=10000) # increase the maximal allowed steps
e_ops = [tensor([qeye(2), fock_dm(2)])] # observable

# compute results of the run using a solver of choice with custom options
Expand Down
6 changes: 3 additions & 3 deletions doc/pulse-paper/dj_algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
OptPulseProcessor, LinearSpinChain, SCQubits, SpinChainModel)
from qutip_qip.circuit import QubitCircuit
from qutip import sigmaz, sigmax, identity, tensor, basis
from qutip_qip.compat import to_scalar


# Deutsch-Josza algorithm
dj_circuit = QubitCircuit(num_qubits)
Expand Down Expand Up @@ -79,7 +81,6 @@
ax[i].fill_between([full_tlist[point2], full_tlist[point3]], [vmin ,vmin], [vmax, vmax], color="lightgray", alpha=0.5)
ax[i].vlines([full_tlist[point2], full_tlist[point3]], vmin, vmax, "gray", "--", linewidth=0.8, alpha=0.5)

fig.tight_layout()
fig.savefig("optimal_control_pulse.pdf")
fig.show()

Expand Down Expand Up @@ -124,7 +125,6 @@

full_tlist = scqubits_processor.get_full_tlist()

fig3.tight_layout()
fig3.savefig("transmon_pulse.pdf")
fig3.show()

Expand All @@ -146,7 +146,7 @@
for state in result1.states:
tmp = state.ptrace([0,1])
tmp = basis([2,2], [0,0]).dag() * tmp * basis([2,2], [0,0])
expect.append(np.real(tmp[0, 0]))
expect.append(np.real(to_scalar(tmp)))

fig5, ax5 = plt.subplots(figsize=(LINEWIDTH, LINEWIDTH*0.7), dpi=200)
ax5.plot(t_record, expect, color="slategrey")
Expand Down
2 changes: 1 addition & 1 deletion doc/source/qip-basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ gate function returning a :class:`qutip.Qobj` and save it in the attribute ``use
# controlled rotation X
mat = np.zeros((4, 4), dtype=np.complex)
mat[0, 0] = mat[1, 1] = 1.
mat[2:4, 2:4] = rx(arg_value)
mat[2:4, 2:4] = rx(arg_value).full()
return Qobj(mat, dims=[[2, 2], [2, 2]])


Expand Down
5 changes: 0 additions & 5 deletions src/qutip_qip/circuit/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,7 @@ def add_circuit(self, qc, start=0, overwrite_user_gates=False):
self.user_gates[user_gate] = qc.user_gates[user_gate]

for circuit_op in qc.gates:

if isinstance(circuit_op, Gate):

if circuit_op.targets is not None:
tar = [target + start for target in circuit_op.targets]
else:
Expand Down Expand Up @@ -958,9 +956,7 @@ def latex_code(self):
col = []
_swap_processing = False
for n in range(self.N + self.num_cbits):

if gate.targets and n in gate.targets:

if len(gate.targets) > 1:
if gate.name == "SWAP":
if _swap_processing:
Expand Down Expand Up @@ -1041,7 +1037,6 @@ def latex_code(self):
measurement = op
col = []
for n in range(self.N + self.num_cbits):

if n in measurement.targets:
col.append(r" \meter")
elif (n - self.N) == measurement.classical_store:
Expand Down
1 change: 0 additions & 1 deletion src/qutip_qip/circuit/circuitsimulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@ def _gate_sequence_product(U_list, ind_list):
overall_inds = []

for i, (U, inds) in enumerate(zip(U_list, ind_list)):

# when the tensor_list covers the full dimension of the circuit, we
# expand the tensor_list to a unitary and call _gate_sequence_product
# recursively on the rest of the U_list.
Expand Down
15 changes: 15 additions & 0 deletions src/qutip_qip/compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""
For the compatibility between qutip-v5 and v4.
"""
from itertools import chain
from functools import reduce
from packaging.version import parse as parse_version
import numpy as np
import qutip


def to_scalar(qobj_or_scalar):
if isinstance(qobj_or_scalar, qutip.Qobj):
if qobj_or_scalar.dims == [[1], [1]]:
return qobj_or_scalar[0, 0]
return qobj_or_scalar
4 changes: 3 additions & 1 deletion src/qutip_qip/device/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ def find_pulse(self, pulse_name):
else:
try:
return self.pulses[pulse_dict[pulse_name]]
except (KeyError):
except KeyError:
raise KeyError(
"Pulse name {} undefined. "
"Please define it in the attribute "
Expand Down Expand Up @@ -1209,10 +1209,12 @@ def run_state(
options = kwargs.get("options", qutip.Options())
if options.get("max_step", 0.0) == 0.0:
options["max_step"] = total_circuit_time / 25
options["progress_bar"] = False
else:
options = kwargs.get("options", qutip.Options())
if options.max_step == 0.0:
options.max_step = total_circuit_time / 10
options.progress_bar = False
kwargs["options"] = options
# choose solver:
if solver == "mesolve":
Expand Down
1 change: 0 additions & 1 deletion src/qutip_qip/operations/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,6 @@ def qubit_clifford_group(N=None, target=0):
partial(reduce, mul),
product(_powers(E, 3), _powers(X, 2), _powers(S, 4)),
):

# partial(reduce, mul) returns a function that takes products
# of its argument, by analogy to sum. Note that by analogy,
# sum can be written as partial(reduce, add).
Expand Down
4 changes: 0 additions & 4 deletions src/qutip_qip/qasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ def _tokenize(token_cmds):
processed_commands = []

for line in token_cmds:

# carry out some pre-processing for convenience
for c in "[]()":
line = line.replace(c, " " + c + " ")
Expand Down Expand Up @@ -241,7 +240,6 @@ def _process_includes(self):
expanded_commands = []

for curr_index, command in enumerate(self.commands):

if command[0] != "include":
continue

Expand Down Expand Up @@ -384,7 +382,6 @@ def _custom_gate(self, qc_temp, gate_call):
regs_map[reg] = regs[i]
# process all the constituent gates with supplied arguments, registers
for call in gate.gates_inside:

# create function call for the constituent gate
name, com_args, com_regs = call

Expand Down Expand Up @@ -455,7 +452,6 @@ def _regs_processor(self, regs, reg_type):
regs = new_regs

if reg_type == "measure":

# processes register tokens of the form q[i] -> c[i]
groups = re.match(r"(.*)\[(.*)\]->(.*)\[(.*)\]", "".join(regs))
if groups:
Expand Down
1 change: 1 addition & 0 deletions src/qutip_qip/qir.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ def circuit_to_qir(circuit, format, module_name="qutip_circuit"):
A QIR representation of `circuit`, encoded using the format specified by
`format`.
"""

# Define as an inner function to make it easier to call from conditional
# branches.
def append_operation(
Expand Down
3 changes: 0 additions & 3 deletions src/qutip_qip/qiskit/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ class QiskitSimulatorBase(BackendV1):
"""

def __init__(self, configuration=None, **fields):

if configuration is None:
configuration_dict = self._DEFAULT_CONFIGURATION
else:
Expand Down Expand Up @@ -160,7 +159,6 @@ class QiskitCircuitSimulator(QiskitSimulatorBase):
}

def __init__(self, configuration=None, **fields):

super().__init__(configuration=configuration, **fields)

def _parse_results(
Expand Down Expand Up @@ -325,7 +323,6 @@ class QiskitPulseSimulator(QiskitSimulatorBase):
}

def __init__(self, processor: Processor, configuration=None, **fields):

self.processor = processor
super().__init__(configuration=configuration, **fields)

Expand Down
2 changes: 0 additions & 2 deletions src/qutip_qip/transpiler/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ def to_chain_structure(qc, setup="linear"):
temp = QubitCircuit(N - end + start)
i = 0
while i < (N - end + start):

if (
N + start - end - i - i == 1
and (N - end + start + 1) % 2 == 0
Expand Down Expand Up @@ -215,7 +214,6 @@ def to_chain_structure(qc, setup="linear"):
temp = QubitCircuit(N - end + start)
i = 0
while i < (N - end + start):

if (
N + start - end - i - i == 1
and (N - end + start + 1) % 2 == 0
Expand Down
7 changes: 3 additions & 4 deletions src/qutip_qip/vqa.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from scipy.optimize import minimize
from scipy.linalg import expm_frechet
from .operations import gate_sequence_product
from .compat import to_scalar


class VQA:
Expand Down Expand Up @@ -429,10 +430,8 @@ def cost_derivative(self, U, dU):
dCost = (init.dag() * dU.dag()) * obs * (U * init) + (
init.dag() * U.dag()
) * obs * (dU * init)
if isinstance(dCost, Qobj): # qutip version < 5
return np.real(dCost.full().item())
else: # qutip version >= 5
return np.real(dCost)
dCost = to_scalar(dCost)
return np.real(dCost)

def compute_jac(self, angles, indices_to_compute=None):
"""
Expand Down
1 change: 1 addition & 0 deletions tests/pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ markers =
filterwarnings =
ignore:matplotlib not found:UserWarning
ignore:the imp module is deprecated in favour of importlib:DeprecationWarning
ignore:Dedicated options class are no longer needed, options should be passed as dict to solvers.:FutureWarning
4 changes: 0 additions & 4 deletions tests/test_noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@

import qutip
from packaging.version import parse as parse_version
if parse_version(qutip.__version__) >= parse_version('5.dev'):
is_qutip5 = True
else:
is_qutip5 = False


class TestNoise:
Expand Down
13 changes: 3 additions & 10 deletions tests/test_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@
import pytest

import qutip
if parse_version(qutip.__version__) < parse_version('5.dev'):
from qutip import Options as SolverOptions
else:
from qutip import SolverOptions
from qutip_qip.device import Processor, LinearSpinChain
from qutip import (
basis, sigmaz, sigmax, sigmay, identity, destroy, tensor,
Expand All @@ -21,10 +17,7 @@
from qutip_qip.qubits import qubit_states
from qutip_qip.pulse import Pulse
from qutip_qip.circuit import QubitCircuit
if parse_version(qutip.__version__) < parse_version('5.dev'):
from qutip import Options as SolverOptions
else:
from qutip import SolverOptions
from qutip import Options


class TestCircuitProcessor:
Expand Down Expand Up @@ -96,7 +89,7 @@ def test_id_evolution(self):
tlist = [0., 1., 2.]
proc.add_pulse(Pulse(identity(2), 0, tlist, False))
result = proc.run_state(
init_state, options=SolverOptions(store_final_state=True))
init_state, options=Options(store_final_state=True))
global_phase = init_state[0, 0]/result.final_state[0, 0]
assert_allclose(
global_phase*result.final_state.full(), init_state.full())
Expand Down Expand Up @@ -407,7 +400,7 @@ def test_max_step_size(self):
# No max_step
final_state = processor.run_state(
init_state,
options=SolverOptions(max_step=10000) # too large max_step
options=Options(max_step=10000) # too large max_step
).states[-1]
expected_state = tensor([basis(2, 0), basis(2, 1)])
assert pytest.approx(fidelity(final_state, expected_state), 0.001) == 0
Expand Down

0 comments on commit 2eccfec

Please sign in to comment.