Skip to main content

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.

maxi=0N1vixi(1)\max \quad \sum_{i=0}^{N-1} v_i x_i \tag{1}
s.t.i=0N1wixiW(2)\mathrm{s.t.} \quad \sum_{i=0}^{N-1} w_i x_i \leq W \tag{2}
xi{0,1}(i{0,1,,N1})(3)x_i \in \{0, 1\} \quad (\forall i \in \{0, 1, \dots, N-1\}) \tag{3}

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
info

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 pass script_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 information final_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 pass problem, instance_data to the function. This replaces the local variables problem and instance_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 and solving_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.