Skip to content

Commit

Permalink
Merge branch 'improve_transpiler' of https://github.com/qilimanjaro-t…
Browse files Browse the repository at this point in the history
…ech/qililab into improve_transpiler
  • Loading branch information
GuillermoAbadLopez committed Nov 7, 2024
2 parents c7b3e5d + df5745f commit 944e2f0
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 66 deletions.
116 changes: 60 additions & 56 deletions docs/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

### New features since last release

- Support GRES in %%submit_job magic method

[#828](https://github.com/qilimanjaro-tech/qililab/pull/828)

- Added intermediate frequency to single input lines on qm. The default is 0 (this prevents some bugs from qua-qm). Now it is possible to use the set_parameter IF and qm.set_frequency for buses with single_input.

[#807](https://github.com/qilimanjaro-tech/qililab/pull/807)
Expand Down Expand Up @@ -92,67 +96,67 @@
- Added routing algorithms to `qililab` in function of the platform connectivity. This is done passing `Qibo` own `Routers` and `Placers` classes,
and can be called from different points of the stack.

The most common way to route, will be automatically through `qililab.execute_circuit.execute()`, or also from `qililab.platform.execute/compile()`. Another way, would be doing the transpilation/routing directly from an instance of the Transpiler, with: `qililab.digital.circuit_transpiler.transpile/route_circuit()` (with this last one, you can route with a different topology from the platform one, if desired, defaults to platform)

Example:

```python
from qibo import gates
from qibo.models import Circuit
from qibo.transpiler.placer import ReverseTraversal, Trivial
from qibo.transpiler.router import Sabre
from qililab import build_platform
from qililab.circuit_transpiler import CircuitTranspiler

# Create circuit:
c = Circuit(5)
c.add(gates.CNOT(1, 0))

### From execute_circuit:
# With defaults (ReverseTraversal placer and Sabre routing):
probabilities = ql.execute(c, runcard="./runcards/galadriel.yml", placer= Trivial, router = Sabre, routing_iterations: int = 10,)
# Changing the placer to Trivial, and changing the number of iterations:
probabilities = ql.execute(c, runcard="./runcards/galadriel.yml",

### From the platform:
# Create platform:
platform = build_platform(runcard="<path_to_runcard>")
# With defaults (ReverseTraversal placer, Sabre routing)
probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000)
# With non-defaults, and specifying the router with kwargs:
probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000, placer= Trivial, router = (Sabre, {"lookahead": 2}), routing_iterations: int = 20))
# With a router instance:
router = Sabre(connectivity=None, lookahead=1) # No connectivity needed, since it will be overwritten by the platform's one
probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000, placer=Trivial, router=router)

### Using the transpiler directly:
### (If using the routing from this points of the stack, you can route with a different topology from the platform one)
# Create transpiler:
transpiler = CircuitTranspiler(platform)
# Default Transpilation (ReverseTraversal, Sabre and Platform connectivity):
routed_circ, final_layouts = transpiler.route_circuit([c])
# With Non-Default Trivial placer, specifying the kwargs, for the router, and different coupling_map:
routed_circ, final_layouts = transpiler.route_circuit([c], placer=Trivial, router=(Sabre, {"lookahead": 2}, coupling_map=<some_different_topology>))
# Or finally, Routing with a concrete Routing instance:
router = Sabre(connectivity=None, lookahead=1) # No connectivity needed, since it will be overwritten by the specified in the Transpiler:
routed_circ, final_layouts = transpiler.route_circuit([c], placer=Trivial, router=router, coupling_map=<connectivity_to_use>)
```
The most common way to route, will be automatically through `qililab.execute_circuit.execute()`, or also from `qililab.platform.execute/compile()`. Another way, would be doing the transpilation/routing directly from an instance of the Transpiler, with: `qililab.digital.circuit_transpiler.transpile/route_circuit()` (with this last one, you can route with a different topology from the platform one, if desired, defaults to platform)

Example:

```python
from qibo import gates
from qibo.models import Circuit
from qibo.transpiler.placer import ReverseTraversal, Trivial
from qibo.transpiler.router import Sabre
from qililab import build_platform
from qililab.circuit_transpiler import CircuitTranspiler

# Create circuit:
c = Circuit(5)
c.add(gates.CNOT(1, 0))

### From execute_circuit:
# With defaults (ReverseTraversal placer and Sabre routing):
probabilities = ql.execute(c, runcard="./runcards/galadriel.yml", placer= Trivial, router = Sabre, routing_iterations: int = 10,)
# Changing the placer to Trivial, and changing the number of iterations:
probabilities = ql.execute(c, runcard="./runcards/galadriel.yml",

### From the platform:
# Create platform:
platform = build_platform(runcard="<path_to_runcard>")
# With defaults (ReverseTraversal placer, Sabre routing)
probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000)
# With non-defaults, and specifying the router with kwargs:
probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000, placer= Trivial, router = (Sabre, {"lookahead": 2}), routing_iterations: int = 20))
# With a router instance:
router = Sabre(connectivity=None, lookahead=1) # No connectivity needed, since it will be overwritten by the platform's one
probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000, placer=Trivial, router=router)

### Using the transpiler directly:
### (If using the routing from this points of the stack, you can route with a different topology from the platform one)
# Create transpiler:
transpiler = CircuitTranspiler(platform)
# Default Transpilation (ReverseTraversal, Sabre and Platform connectivity):
routed_circ, final_layouts = transpiler.route_circuit([c])
# With Non-Default Trivial placer, specifying the kwargs, for the router, and different coupling_map:
routed_circ, final_layouts = transpiler.route_circuit([c], placer=Trivial, router=(Sabre, {"lookahead": 2}, coupling_map=<some_different_topology>))
# Or finally, Routing with a concrete Routing instance:
router = Sabre(connectivity=None, lookahead=1) # No connectivity needed, since it will be overwritten by the specified in the Transpiler:
routed_circ, final_layouts = transpiler.route_circuit([c], placer=Trivial, router=router, coupling_map=<connectivity_to_use>)
```

[#821](https://github.com/qilimanjaro-tech/qililab/pull/821)

- Added a timeout inside quantum machines to control the `wait_for_all_values` function. The timeout is controlled through the runcard as shown in the example:

```
instruments:
- name: quantum_machines_cluster
alias: QMM
...
timeout: 10000 # optional timeout in seconds
octaves:
...
```
```json
instruments:
- name: quantum_machines_cluster
alias: QMM
...
timeout: 10000 # optional timeout in seconds
octaves:
...
```

[#826](https://github.com/qilimanjaro-tech/qililab/pull/826)
[#826](https://github.com/qilimanjaro-tech/qililab/pull/826)

### Improvements

Expand All @@ -164,7 +168,7 @@ instruments:

Example (for Qblox)

```
```json
buses:
- alias: readout
...
Expand Down
6 changes: 5 additions & 1 deletion src/qililab/slurm.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def is_variable_used(code, variable):
" the results of the job, you need to call `variable.result()`.",
)
@argument("-p", "--partition", help="Name of the partition where you want to execute the SLURM job.")
@argument("-g", "--gres", default=None, help="GRES (chip) where you want to execute the SLURM job.")
@argument("-n", "--name", default="submitit", help="Name of the slurm job.")
@argument("-t", "--time", default=120, help="Time limit (in minutes) of the job.")
@argument(
Expand Down Expand Up @@ -85,13 +86,16 @@ def submit_job(line: str, cell: str, local_ns: dict) -> None:
args = parse_argstring(submit_job, line)
output = args.output
partition = args.partition
gres = args.gres
job_name = args.name
time_limit = int(args.time)
folder_path = args.logs
execution_env = args.execution_environment
begin_time = args.begin
low_priority = args.low_priority

if gres is None:
raise ValueError("GRES needs to be provided! See the available ones typing 'sinfo -o '%G'' in the terminal")
nice_factor = 0
if low_priority in ["True", "true"]:
nice_factor = 1000000 # this ensures Lab jobs have 0 priority, same as QaaS jobs
Expand All @@ -108,7 +112,7 @@ def submit_job(line: str, cell: str, local_ns: dict) -> None:
slurm_partition=partition,
name=job_name,
timeout_min=time_limit,
slurm_additional_parameters={"begin": begin_time, "nice": nice_factor},
slurm_additional_parameters={"begin": begin_time, "nice": nice_factor, "gres": f"{gres}:1"},
)

# Compile the code defined above
Expand Down
29 changes: 20 additions & 9 deletions tests/test_slurm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
from unittest.mock import MagicMock, patch

import pytest
from IPython.testing.globalipapp import start_ipython

import qililab as ql
from IPython.testing.globalipapp import start_ipython

slurm_job_data_test = "slurm_job_data_test"

Expand Down Expand Up @@ -34,7 +33,7 @@ def test_submit_job(self, ip):
ip.run_cell(raw_cell="a=1\nb=1")
ip.run_cell_magic(
magic_name="submit_job",
line=f"-o results -p debug -l {slurm_job_data_test} -n unit_test -e local",
line=f"-o results -g aQPU1 -l {slurm_job_data_test} -n unit_test -e local",
cell="results = a+b ",
)
time.sleep(4)
Expand All @@ -48,7 +47,19 @@ def test_submit_job_output_not_assigned(self, ip):
):
ip.run_cell_magic(
magic_name="submit_job",
line=f"-o results -p debug -l {slurm_job_data_test} -n unit_test -e local",
line=f"-o results -g aQPU1 -l {slurm_job_data_test} -n unit_test -e local",
cell="a+b",
)

def test_submit_job_no_gres_provided(self, ip):
"""Check ValueError is raised in case GRES is not provided."""
ip.run_cell(raw_cell="a=1\nb=1")
with pytest.raises(
ValueError, match="GRES needs to be provided! See the available ones typing 'sinfo -o '%G'' in the terminal"
):
ip.run_cell_magic(
magic_name="submit_job",
line=f"-o results -l {slurm_job_data_test} -n unit_test -e local",
cell="a+b",
)

Expand All @@ -59,7 +70,7 @@ def test_submit_job_with_random_file_in_logs_folder(self, ip):
)
ip.run_cell_magic(
magic_name="submit_job",
line=f"-o results -p debug -l {slurm_job_data_test} -n unit_test -e local",
line=f"-o results -g aQPU1 -l {slurm_job_data_test} -n unit_test -e local",
cell="results=a+b",
)
time.sleep(4) # give time to ensure processes are finished
Expand All @@ -72,7 +83,7 @@ def test_submit_job_delete_info_from_past_jobs(self, ip):
for _ in range(int(ql.slurm.num_files_to_keep / 4)):
ip.run_cell_magic(
magic_name="submit_job",
line=f"-o results -p debug -l {slurm_job_data_test} -n unit_test -e local",
line=f"-o results -g aQPU1 -l {slurm_job_data_test} -n unit_test -e local",
cell="results=a+b",
)
time.sleep(2) # give time submitit to create the files
Expand All @@ -83,7 +94,7 @@ def test_submit_job_delete_info_from_past_jobs(self, ip):
)
ip.run_cell_magic(
magic_name="submit_job",
line=f"-o results -p debug -l {slurm_job_data_test} -n unit_test -e local",
line=f"-o results -g aQPU1 -l {slurm_job_data_test} -n unit_test -e local",
cell="results=a+b",
)
time.sleep(2)
Expand All @@ -102,13 +113,13 @@ def test_setting_parameters(self, ip):
with patch("qililab.slurm.os"):
ip.run_cell_magic(
magic_name="submit_job",
line=f"-o results -p debug -l {slurm_job_data_test} -n unit_test -e local -t 5 --begin now+1hour -lp true",
line=f"-o results -p debug -l {slurm_job_data_test} -n unit_test -e local -t 5 --begin now+1hour -lp true -g aQPU1",
cell="results=a+b",
)
executor.assert_called_once_with(folder=slurm_job_data_test, cluster="local")
executor_instance.update_parameters.assert_called_once_with(
slurm_partition="debug",
name="unit_test",
timeout_min=5,
slurm_additional_parameters={"begin": "now+1hour", "nice": 1000000},
slurm_additional_parameters={"begin": "now+1hour", "nice": 1000000, "gres":"aQPU1:1"},
)

0 comments on commit 944e2f0

Please sign in to comment.