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
16 changes: 14 additions & 2 deletions qsoverlay/DiCarlo_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,14 @@ def quick_setup(qubit_list, connectivity_dic=None, rng=None, *, seed=None,
setup['gate_set'] = make_1q2q_gateset(qubit_dic=setup['qubit_dic'],
gate_dic=setup['gate_dic'],
connectivity_dic=connectivity_dic)
return Setup(**setup)

system_params = {
'uses_waiting_gates': True
}

setup = Setup(**setup, system_params=system_params)

return setup


def asymmetric_setup(qubit_parameters=None,
Expand Down Expand Up @@ -184,7 +191,12 @@ def asymmetric_setup(qubit_parameters=None,
qubit_dic=asym_setup['qubit_dic'],
gate_dic=asym_setup['gate_dic'],
connectivity_dic=connectivity_dic)
return Setup(**asym_setup)

system_params = {
'uses_waiting_gates': True
}

return Setup(**asym_setup, system_params=system_params)


def get_gate_dic():
Expand Down
173 changes: 106 additions & 67 deletions qsoverlay/circuit_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,45 +14,17 @@

class Builder:

def __init__(self,
setup=None,
qubit_dic=None,
gate_dic=None,
gate_set=None,
update_rules=None,
**kwargs):
def __init__(self, setup, **kwargs):
'''
qubit_dic: list of the qubits in the system.
Each qubit should have a set of parameters,
which is called whenever required by the gates.
gate_dic: a dictionary of allowed gates.
Each 'allowed gate' consists of:
- the function to be called
- a set of 'qubit_args' that will be found in
the qubit dictionary and passed to the gate.
- a 'time' - the length of the gate
Note that 'Measure' should be in the gate_set
gate_set: a dictionary of allowed gate instances.
An allowed gate instance is a list of the gate
along with the qubits it is performed between.
update_rules: a set of rules for updating the system.
(i.e. between experiments).
Args:
-------
setup: an experiment_setup.Setup containing details of
the experiment.

kwargs: Can add t1 and t2 via the kwargs instead of
passing them with the qubit_dic.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kinda weak explanation here (I would not be able to understand). May be better link it to Quantumsim circuit documentation?

'''
if setup is not None:
self.qubit_dic = setup.qubit_dic
self.gate_dic = setup.gate_dic
self.gate_set = setup.gate_set
self.update_rules = setup.update_rules
else:
self.qubit_dic = qubit_dic or {}
self.gate_dic = gate_dic or {}
self.gate_set = gate_set or {}
self.update_rules = update_rules or []

self.save_flag = True
self.setup = setup
self.new_circuit(**kwargs)

def new_circuit(self, circuit_title='New Circuit', **kwargs):
Expand All @@ -68,9 +40,14 @@ def new_circuit(self, circuit_title='New Circuit', **kwargs):

# Times stores the current time of every qubit (beginning at 0)
self.times = {}
self.tmins = {}

# save_flag is used to keep track of which gates have been
# saved during a circuit, and needs to be reset here.
self.save_flag = True

# Make qubits
for qubit, qubit_args in sorted(self.qubit_dic.items()):
for qubit, qubit_args in sorted(self.setup.qubit_dic.items()):

if 'classical' in qubit_args.keys() and\
qubit_args['classical'] is True:
Expand All @@ -93,6 +70,7 @@ def new_circuit(self, circuit_title='New Circuit', **kwargs):

# Initialise the time of the latest gate on each qubit to 0
self.times[qubit] = 0
self.tmins[qubit] = None

def make_reverse_circuit(self, title='reversed',
finalize=True):
Expand All @@ -109,19 +87,16 @@ def make_reverse_circuit(self, title='reversed',
for n, gate_desc in enumerate(reversed_circuit_list):
gate_name = gate_desc[0]

num_qubits = self.gate_dic[gate_name]['num_qubits']
user_kws = self.gate_dic[gate_name]['user_kws']
num_qubits = self.setup.gate_dic[gate_name]['num_qubits']
user_kws = self.setup.gate_dic[gate_name]['user_kws']

if 'angle' in user_kws:
gate_desc = list(gate_desc)
angle_index = user_kws.index('angle')
gate_desc[num_qubits + 1 + angle_index] *= -1
reversed_circuit_list[n] = tuple(gate_desc)

reversed_circuit_builder = Builder(qubit_dic=self.qubit_dic,
gate_dic=self.gate_dic,
gate_set=self.gate_set,
update_rules=self.update_rules)
reversed_circuit_builder = Builder(setup=self.setup)
reversed_circuit_builder.add_circuit_list(reversed_circuit_list)
if finalize:
reversed_circuit_builder.finalize()
Expand Down Expand Up @@ -151,8 +126,8 @@ def add_qasm(self, qasm_generator, qubits_first=True, **params):
# Get the gate name
gate_name = line[:spaces[0]]

num_qubits = self.gate_dic[gate_name]['num_qubits']
user_kws = self.gate_dic[gate_name]['user_kws']
num_qubits = self.setup.gate_dic[gate_name]['num_qubits']
user_kws = self.setup.gate_dic[gate_name]['user_kws']

if gate_name == 'measure':
# line looks like 'measure q -> c;'
Expand Down Expand Up @@ -226,8 +201,8 @@ def __lt__(self, gate_desc):

gate_name = gate_desc[0]

num_qubits = self.gate_dic[gate_name]['num_qubits']
user_kws = self.gate_dic[gate_name]['user_kws']
num_qubits = self.setup.gate_dic[gate_name]['num_qubits']
user_kws = self.setup.gate_dic[gate_name]['user_kws']

if len(gate_desc) == len(user_kws) + num_qubits + 2:
return_flag = gate_desc[-1]
Expand All @@ -251,10 +226,10 @@ def add_gates_simultaneous(self, gate_descriptions):
starting_time = max([
self.times[gate_desc[j]]
for gate_desc in gate_descriptions
for j in range(1, self.gate_dic[gate_desc[0]]['num_qubits']+1)])
for j in range(1, self.setup.gate_dic[gate_desc[0]]['num_qubits']+1)])

for gate_desc in gate_descriptions:
num_qubits = self.gate_dic[gate_desc[0]]['num_qubits']
num_qubits = self.setup.gate_dic[gate_desc[0]]['num_qubits']
qubit_list = gate_desc[1:num_qubits + 1]
for qubit in qubit_list:
self.times[qubit] = starting_time
Expand Down Expand Up @@ -285,7 +260,7 @@ def add_gate(self, gate_name,
# the same for every qubit/pair of qubits).
gate_tuple = (gate_name, *qubit_list)

circuit_args, builder_args = self.gate_set[gate_tuple]
circuit_args, builder_args = self.setup.gate_set[gate_tuple]

# kwargs is the list of arguments that gets passed to the gate
# itself. We initiate with the set of additional arguments passed
Expand Down Expand Up @@ -327,7 +302,7 @@ def add_gate(self, gate_name,
# data.
if self.save_flag:
user_data = [kwargs[kw]
for kw in self.gate_dic[gate_name]['user_kws']]
for kw in self.setup.gate_dic[gate_name]['user_kws']]
if return_flag is not False:
self.circuit_list.append((gate_name, *qubit_list,
*user_data, return_flag))
Expand All @@ -336,7 +311,7 @@ def add_gate(self, gate_name,
*user_data))

# Get the gate to add to quantumsim.
gate = self.gate_dic[gate_name]['function']
gate = self.setup.gate_dic[gate_name]['function']

# The save flag prevents saving multiple gate
# definitions when using recursive gates (i.e.
Expand Down Expand Up @@ -372,6 +347,11 @@ def add_gate(self, gate_name,
for qubit in qubit_list:
self.times[qubit] = max(self.times[qubit], time + gate_time)

# If this qubit has not been used before, store the start
# of this gate as the first time it is activated.
if self.tmins[qubit] is None:
self.tmins[qubit] = time

# My current best idea for adjustable gates - return the
# gate that could be adjusted to the user.
if return_flag is not False:
Expand All @@ -381,22 +361,86 @@ def update(self, **kwargs):
for rule in self.update_rules:
update_function_dic[rule](self, **kwargs)

def finalize(self, topo_order=False, t_add=0):
def finalize(self, toposort=False, tmin=None, tmax=None,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not rename topo_order to toposort without extra need: larger chance to get reverse incompatibility in the case of someone called the function as finalize(topo_order=True).

dtmax=0, dtmin=0, shrink=False):
"""
Script to run to finalize gates. Currently adds waiting gates
as required and sorts gates.

Args:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Numpydoc's keyword is Parameters, not Args

--------
toposort : bool or "simple"
whether to toposort gates or simply order them by time.
Setting toposort="simple" uses the simple toposort algorithm.
tmin : float or dict of floats
earliest time to add decay on qubits. If set, overrides
shrink.
tmax : float of dict of floats
latest time to add decay on qubits. If set, overrides
shrink.
dtmax : float or dict of floats
time to pad qubits by (i.e. dead time after the gates
in the circuit are executed). If float, applies same
padding to all qubits.
dtmin : float or dict of floats
time to pad qubits by on the left (i.e. dead time before
any gates are executed). If float, applies same padding
to all qubits.
shrink : bool
whether to shrink resting gates around qubits. When
"""
Adds resting gates to all systems as required.
quantumsim currently assumes fixed values for photon
numbers, so we take them from a random qubit

Photons in quantumsim are currently broken, so
they're not in here right now.
if ('uses_waiting_gates' in self.setup.system_params and
self.setup.system_params['uses_waiting_gates'] is True):
self.add_waiting_gates(
tmin=tmin, tmax=tmax,
dtmin=dtmin, dtmax=dtmax, shrink=shrink)

self.circuit.order(toposort)

def add_waiting_gates(self, tmin=None, tmax=None,
dtmin=0, dtmax=0, shrink=False):
"""
Function to add waiting gates to system

Args:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameters

--------
dtmax : float or dict of floats
time to pad qubits by (i.e. dead time after the gates
in the circuit are executed). If float, applies same
padding to all qubits.
dtmin : float or dict of floats
time to pad qubits by on the left (i.e. dead time before
any gates are executed). If float, applies same padding
to all qubits.
shrink : bool
whether to shrink resting gates around qubits. When
"""
if tmin is None:
if shrink:
tmin = self.tmins
else:
tmin = {key: 0 for key in self.times.keys()}
if tmax is None:
if shrink:
tmax = self.times
else:
circuit_time = max(self.times.values())
tmax = {key: circuit_time for key in self.times.keys()}

if type(dtmax) == dict:
for key,val in dtmax.items():
tmax[key] += val
else:
for key in tmax.keys():
tmax[key] += dtmax

circuit_time = max(self.times.values())
if type(t_add) == dict:
circuit_time = {key: val + circuit_time
for key, val in t_add.items()}
if type(dtmin) == dict:
for key,val in dtmin.items():
tmin[key] -= val
else:
circuit_time += t_add
for key in tmin.keys():
tmin[key] -= dtmin

# args = list(self.qubit_dic.values())[0]

Expand All @@ -408,9 +452,4 @@ def finalize(self, topo_order=False, t_add=0):
# chi=args['chi'])
# else:

self.circuit.add_waiting_gates(tmin=0, tmax=circuit_time)
if topo_order is True:
self.circuit.order()
else:
self.circuit.gates = sorted(self.circuit.gates,
key=lambda x: x.time)
self.circuit.add_waiting_gates(tmin=tmin, tmax=tmax)
11 changes: 9 additions & 2 deletions qsoverlay/experiment_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ def __init__(
self, filename=None,
seed=None, state=None,
gate_dic=None, update_rules=None,
qubit_dic=None, gate_set=None):
qubit_dic=None, gate_set=None,
system_params=None):

if filename is not None:
self.load(filename, seed, state)
Expand All @@ -24,13 +25,18 @@ def __init__(
self.update_rules = update_rules or []
self.qubit_dic = qubit_dic or {}
self.gate_set = gate_set or {}
self.system_params = system_params or {}

def load(self, filename, seed=None, state=None):
with open(filename, 'r') as infile:
setup_load_format = json.load(infile)

self.update_rules = setup_load_format['update_rules']
self.qubit_dic = setup_load_format['qubit_dic']
try:
self.system_params = setup_load_format['system_params']
except:
self.system_params = {}

# Currently assumes each qubit uses the same
# uniform_noisy_sampler - this needs fixing
Expand Down Expand Up @@ -90,7 +96,8 @@ def save(self, filename):
'gate_dic': gate_dic_save_format,
'update_rules': self.update_rules,
'qubit_dic': qubit_dic_save_format,
'gate_set': gate_set_save_format
'gate_set': gate_set_save_format,
'system_params': system_params
}
with open(filename, 'w') as outfile:
json.dump(setup_save_format, outfile)
Loading