Skip to content

Commit

Permalink
Fix log scans with int bug (#117)
Browse files Browse the repository at this point in the history
* Fix log scans with int bug
Fixed in from_array() and qua_logspace()
* changelog
  • Loading branch information
TheoLaudatQM authored Jul 18, 2022
1 parent 9cc2e2a commit 8cc90d9
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 27 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## [Unreleased]
### Added
- Calibrations - a new package with an API to perform basic single qubit calibration protocols.
### Fixed
- Loops - Fixed qua_logspace() and from_array() for logarithmic increments with integers.

## [0.10.0] - 2022-07-04
### Fixed
Expand Down
44 changes: 21 additions & 23 deletions qualang_tools/loops/loops.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def from_array(var, array):
# Check array increment
if np.isclose(np.std(np.diff(array)), 0):
increment = "lin"
elif np.isclose(np.std(array[1:] / array[:-1]), 0):
elif np.isclose(np.std(array[1:] / array[:-1]), 0, atol=1e-3):
increment = "log"
else:
raise Exception(
Expand Down Expand Up @@ -95,24 +95,20 @@ def from_array(var, array):
if var_type == "int":

warnings.warn(
"When using logarithmic increments with QUA integers, the resulting values will slightly differ from the ones in numpy.logspace() because of rounding errors. \n Please use the get_equivalent_log_array() function to get the exact values taken by the QUA variable."
"When using logarithmic increments with QUA integers, the resulting values will slightly differ from the ones in numpy.logspace() because of rounding errors. \n Please use the get_equivalent_log_array() function to get the exact values taken by the QUA variable and note that the number of points may also change."
)
if not float(start).is_integer() or not float(stop).is_integer():
raise Exception(
"When looping over a QUA int variable, the array elements must be integers."
)
if step > 1:
return (
var,
float(start),
var < float(stop) * np.sqrt(float(step)),
round(start),
var < round(stop) * np.sqrt(float(step)),
Cast.mul_int_by_fixed(var, float(step)),
)
else:
return (
var,
float(start),
var > float(stop) * np.sqrt(float(step)),
round(start),
var > round(stop) / np.sqrt(float(step)),
Cast.mul_int_by_fixed(var, float(step)),
)

Expand Down Expand Up @@ -261,24 +257,20 @@ def qua_logspace(var, start, stop, num):
var_type = _get_qua_variable_type(var)
if var_type == "int":
warnings.warn(
"When using logarithmic increments with QUA integers, the resulting values will slightly differ from the ones in numpy.logspace() because of rounding errors. \n Please use the get_equivalent_log_array() function to get the exact values taken by the QUA variable."
"When using logarithmic increments with QUA integers, the resulting values will slightly differ from the ones in numpy.logspace() because of rounding errors. \n Please use the get_equivalent_log_array() function to get the exact values taken by the QUA variable and note that the number of points may also change."
)
if not float(start).is_integer() or not float(stop).is_integer():
raise Exception(
"When looping over a QUA int variable, the array elements must be integers."
)
if step > 1:
return (
var,
10**start,
var < 10**stop * np.sqrt(step),
round(10**start),
var < round(10**stop * np.sqrt(step)),
Cast.mul_int_by_fixed(var, float(step)),
)
else:
return (
var,
10**start,
var > 10**stop * np.sqrt(step),
round(10**start),
var > round(10**stop / np.sqrt(step)),
Cast.mul_int_by_fixed(var, float(step)),
)
elif var_type == "fixed":
Expand All @@ -305,16 +297,22 @@ def qua_logspace(var, start, stop, num):
def get_equivalent_log_array(log_array):
"""Function returning the values taken by the QUA int variable within the logarithmic QUA `for_` loop.
Because of rounding errors occuring with QUA integers, these values are not exactly the ones given by `numpy.logspace()`.
Note that the number of points may also change.
:param log_array: a Python list or numpy array containing the values parametrizing the QUA `for_` loop. The spacing must be even in logarithmic scale and it cannot be a QUA array.
:return: numpy array containing the values taken by the QUA int variable within the logarithmic QUA `for_` loop.
"""
a_log = []
aprev = int(log_array[0])
aprev = round(log_array[0])
step = np.mean(np.array(log_array[1:]) / np.array(log_array[:-1]))
for k in range(len(log_array)):
a_log.append(aprev)
aprev = int(aprev * step)
if step > 1:
while aprev < log_array[-1]:
a_log.append(aprev)
aprev = int(aprev * step)
else:
while aprev > log_array[-1]:
a_log.append(aprev)
aprev = int(aprev * step)
return np.array(a_log)


Expand Down
43 changes: 39 additions & 4 deletions tests_against_server/test_loops.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ def IQ_imbalance(g, phi):
}


def simulate_program_and_return(config, prog, duration=2000):
def simulate_program_and_return(config, prog, duration=50000):


qmm = QuantumMachinesManager(host="172.16.2.103", port=80)
qmm.close_all_quantum_machines()
# qmm.close_all_quantum_machines()
# job = qmm.simulate(
# config,
# prog,
Expand Down Expand Up @@ -198,6 +198,8 @@ def prog_maker(list_param):

cfg = deepcopy(config)
arange_param_list = [
[np.logspace(np.log10(50), np.log10(12500), 19), "int"],
[np.logspace(np.log10(50000), np.log10(33), 72), "int"],
[np.logspace(6, 4, 19), "int"],
[np.logspace(3, 6, 199), "int"],
[np.logspace(-3, 0, 99), "fixed"],
Expand Down Expand Up @@ -227,10 +229,10 @@ def prog_maker(list_param):
a_qua = job.result_handles.get("a").fetch_all()["value"]
a_list = param[0]

assert len(a_list) == len(a_qua)
if (param[1] == "int") and (np.isclose(a_list[1]/a_list[0], a_list[-1]/a_list[-2])):
a_list = get_equivalent_log_array(a_list)

assert len(a_list) == len(a_qua)
assert np.allclose(a_list, a_qua, atol=1e-4)
print("PASSED !")

Expand Down Expand Up @@ -276,7 +278,7 @@ def prog_maker(linspace_param):
assert np.allclose(a_list, a_qua, atol=1e-4)


def test_qua_logspace(config):
def test_qua_logspace_fixed(config):
def prog_maker(logspace_param):
with program() as prog:
a = declare(fixed)
Expand Down Expand Up @@ -309,3 +311,36 @@ def prog_maker(logspace_param):
a_list = np.logspace(param[0], param[1], param[2])
assert len(a_list) == len(a_qua)
assert np.allclose(a_list, a_qua, atol=1e-4)


def test_qua_logspace_int(config):
def prog_maker(logspace_param):
with program() as prog:
t = declare(int)
t_st = declare_stream()
with for_(
*qua_logspace(
t, logspace_param[0], logspace_param[1], logspace_param[2]
)
):
play("readout", "resonator", duration=t)
save(t, t_st)
with stream_processing():
t_st.save_all("a")
return prog

cfg = deepcopy(config)

arange_param_list = [
[np.log10(500), np.log10(12500), 11],
[np.log10(5000), np.log10(125), 30],
[np.log10(40), np.log10(1001), 51],
]
for param in arange_param_list:
print(f"Test qua_logspace with {param}:")
job = simulate_program_and_return(cfg, prog_maker(param))
job.result_handles.wait_for_all_values()
a_qua = job.result_handles.get("a").fetch_all()["value"]
a_list = get_equivalent_log_array(np.round(np.logspace(param[0], param[1], param[2])))
assert len(a_list) == len(a_qua)
assert np.allclose(a_list, a_qua, atol=1e-4)

0 comments on commit 8cc90d9

Please sign in to comment.