Getting Started
Environment Setup
It is recommended to use Playground Environment to try JijZeptLab. If you have already completed registration, you can use the Playground Environment (JijZept Playground) with the same login information of JijZept Portal site.
Install JijZeptLab Client
You can access JijZeptLab from the client library jijzeptlab-client
.
You can install JijZeptLab client by running the following command.
pip install jijzeptlab-client -U
Note that from jupyter notebook in JijZept Playground, you need to add !
before the command.
!pip install jijzeptlab-client -U
Authentication Setup
First you need to get your API key from the JijZept Portal site and create config.toml
file.
Please refer the account setup guide for details.
Also please make sure you have the access to JijZeptLab solver.
The following code registers your API key to the client.
import jijzeptlab as jzl
client = jzl.client.JijZeptLabClient(config="./config.toml")
Submit request
The steps for submitting your request are as follows:
- Setup
jzl.client.JijZeptLabClient
- Define your problem (and instance data)
- Define your script that works on server-side environment
- run
client.submit(...)
to submit the job with the above information - wait for the job to finish
- get the result via
result.variables
The figure below shows the schematic diagram of the flow.
In this section we solve the Knapsack Problem to folllow the steps above one by one.
Please refer the above document for the detail formulation of the problem.
Defining Problem and Instance Data
Following the problem setup, we first define the problem as a JijModeling object.
import jijmodeling as jm
# define variables
v = jm.Placeholder('v', ndim=1)
N = v.len_at(0, latex='N')
w = jm.Placeholder('w', ndim=1)
W = jm.Placeholder('W')
x = jm.BinaryVar('x', shape=(N,))
i = jm.Element('i', belong_to=(0, N))
# set problem
problem = jm.Problem('Knapsack')
# set objective function
obj = - jm.sum(i, v[i]*x[i])
problem += obj
# set total weight constarint
const = jm.sum(i, w[i]*x[i])
problem += jm.Constraint('weight', const<=W)
If you are using JijZept Playground, you can show the current mathematical model
problem
Also instance_data are prepared as follows:
import numpy as np
# set a list of values & weights
inst_v = np.random.randint(5,30,100)
inst_w = inst_v + np.random.randint(-2,20,100)
# set maximum weight
inst_W = 100
instance_data = {'v': inst_v, 'w': inst_w, 'W': inst_W}
Define the script
Next we define the script to solve the problem as a function named secript_on_server_side
.
This script does the following steps on server side:
- Compile the problem to generate intermediate representation
- Solve the problem
- Convert the solution to
jm.SampleSet
- store the result as
final_solution
Please note that the code below is not executable in the environment you are using now since the function is intended to be executed on the server side.
Only jijzeptlab.client
modules are available on the client side. Other modules of jijzeptlab.*
are available only on the server side.
def script_on_server_side():
import jijzeptlab as jzl
import jijmodeling as jm
# we are going to solve knapsack problem using MIP solver in this tutorial
# of course we can switch to quantum Ising sampler
import jijzeptlab.solver.mip as mip
# problem, instance_data are pre-defined (passed from client-side)
problem: jm.Problem
instance_data: dict
# compile the problem to generate intermediate representation
compiled_model = jzl.compile_model(problem, instance_data)
# initialize MIP instance
mip_model = mip.create_model(compiled_model)
# solve
mip_result = mip.solve(mip_model)
# convert the solution to `jm.SampleSet`。
final_solution = mip_result.to_sample_set()
Submit the job
Finally, we submit the job to the server.
We use .submit_func(...)
method to submit the job.
The definition of the method is as follows:
client.submit_func(
func: 'typ.Callable',
result_variables: 'list[str]',
input_data: 'typ.Optional[InputData]' = None,
...
) -> 'JijZeptLabResponse'
func
: the function to be executed on the server side. In this case, we passscript_on_server_side
to the function.result_variables
: the list of variables to be returned from the server. Any variables defined as local variables in the submitted script can be specified. In this case, we pass [final_solution
] since we would like to get back the informationfinal_solution
from the server.input_data
: the input data to be passed to the function. If specified, the corresponding local variables in the submitted script are replaced with the input data. In this case, we passproblem
,instance_data
to the function. This replaces the local variablesproblem
andinstance_data
in the submitted script.
The following code submits the job to the server.
input_data = jzl.client.InputData(problem, instance_data)
result = client.submit_func(script_on_server_side, ["final_solution"], input_data)
The script above sends the request (problem, instance data, and script to be executed) to the server. If you receive the error, please check the script if there is no syntax error.
Once the response is returned, you can get the result via result.variables
.
print(result.variables)
You will see the output with the following dict[str, jm.SampleSet]
format.
Please refer the document for the detail document of jm.SampleSet
{'final_solution': SampleSet(record=Record(solution={'x': [(([14, 28, 34, 52, 93, 99],), [1.0, 1.0, 1.0, 1.0, 1.0, 1.0], (100,))]}, num_occurrences=[1]), evaluation=Evaluation(energy=None, objective=[-108.0], constraint_violations={'weight': [0.0]}, penalty=None), measuring_time=MeasuringTime(solve=SolvingTime(preprocess=None, solve=None, postprocess=None), system=SystemTime(post_problem_and_instance_data=None, request_queue=None, fetch_problem_and_instance_data=None, fetch_result=None, deserialize_solution=None), total=None))}
Return mutlple information
Note that the above example returns only final_solution
from the server.
If you would like to return multiple information from the server, you can do it by specifying the list of variables to be returned from the server.
In the following example we change the script as the following:
- generate
instance_data
inside the script with different system size. - calculate the solving time for each instance (not a one-shot calculation)
- return the list of
final_solution
andsolving_time
from the server
Since code size of the submitted script is larger than the previous one. It is advised to use .submit_file(...)
method to submit the script. this method takes the path to the script file as an argument and submit the code in the file.
First we create the following submit_file.py
file.
This script creates instance_data
inside the script and returns final_solution
and solving_time
from the server.
import jijzeptlab as jzl
import jijmodeling as jm
import numpy as np
import time
# we are going to solve knapsack problem using MIP solver in this tutorial
# of course we can switch to quantum Ising sampler
import jijzeptlab.solver.mip as mip
# problem are pre-defined
problem: jm.Problem
# compile the problem to generate intermediate representation
returned_data = {}
for system_size in [10, 20, 50, 100, 200, 500, 1000, 2000]:
# create instance_data inside the script
# set a list of values & weights
inst_v = np.random.randint(5,30,system_size)
inst_w = inst_v + np.random.randint(-2,20,system_size)
# set maximum weight
inst_W = 100
instance_data = {'v': inst_v, 'w': inst_w, 'W': inst_W}
start = time.time()
compiled_model = jzl.compile_model(problem, instance_data)
# initialize MIP instance
mip_model = mip.create_model(compiled_model)
# solve
mip_result = mip.solve(mip_model)
# convert the solution to `jm.SampleSet`。
end = time.time()
final_solution = mip_result.to_sample_set()
returned_data[f"size_{system_size}"] = {"solution": final_solution, "elapsed": end-start}
Note that the all information (solution, elapsed time) are stored in the returned_data
variable.
Next we submit the script to the server.
# instance data is not needed since it is generated inside the script
input_data = jzl.client.InputData(problem)
result = client.submit_file("./submit_file.py", ["returned_data"], input_data)
Once the response is returned, you can get the result via result.variables
.
result.variables["returned_data"]
contains the information same as returned_data
in the script.
for k,v in result.variables["returned_data"].items():
print(f"{k}, elapsed: {v['elapsed']}")
The output will be
size_10, elapsed: 0.01280665397644043
size_20, elapsed: 0.015268564224243164
size_50, elapsed: 0.018834829330444336
size_100, elapsed: 0.02100682258605957
size_200, elapsed: 0.021231889724731445
size_500, elapsed: 0.03410673141479492
size_1000, elapsed: 0.1317446231842041
size_2000, elapsed: 1.9615247249603271
Please note that you cannot get this detailed calculation information if you do not use JijZeptLab.