Download

Basic Usage

Formatting input polynomial

Dirac has the ability to solve higher order polynomials with many variables. In order to illustrate the input format that is used for submitting these problems we will utilize a simple example polynomial:

f(X)=3x4+2.1x12+1.5x22+7.9x2x3+x2x42+x33f(X) = 3 x_4+2.1 x_1^2+1.5 x_2^2+7.9 x_2 x_3+x_2 x_4^2+ x_3^3

The submission input is split into two parts the coefficients and the set of variable indices associated with each coefficient. As an example for above the leading submission coefficients would be created as follows:

  • poly_coefs = [3, 2.1, 1.5, 7.9, 1, 1]

The set of variable indices associated with each coefficient will be represented as follows:

  • poly_indices = [[0,0,4], [0,1,1], [0,2,2], [0,2,3], [2,4,4], [3,3,3]]

Taking the first polynomial term, x4x_4, which is represented by the first poly index set in the list, [0,0,4], with each 0 indicating a place holder for no variable used for a given degree in the polynomial index set and the 4 in the last place indicating the 4th variable for the input problem. Additionally, each individual polynomial variable index set has non-decreasing values moving from left to right such that for each set of indices:

[k1,k2,k3,,kn1,kn][k_1, k_2, k_3, \dots, k_{n-1}, k_n]

must meet following condition:

k1k2k3kn1knk_1 \leq k_2 \leq k_3 \leq \dots \leq k_{n-1} \leq k_n

This property guarantees the uniqueness of the submitted polynomial index set. Also, this sparse representation minimizes the amount of data needed to be transferred to the device to obtain a solution. If the same polynomial index set is specified more than once then the coefficients will be added together to create the final polynomial input.

A dual purpose solver

There are two separate types of of solving routines that can be utilized with Dirac-3 a sum constrained solver and an integer solver.

Integer solver

The integer solver will return solutions vector xix_i based on the associated num_levels, LiL_i, such that each solution variable xix_i will be from the following integer set:

xi{0,1,,Li1}x_i \in \{0, 1, \dots, L_i-1\}

Additionally, the current iteration of the device allows for a maximum of 954 unique optical levels. This implies when considering all num_levels, LiL_i, across all variables together they must meet the following constraint in order for the device to accept the input:

i=1nLi954\sum_{i=1}^{n} L_i \leq 954

For example if considering a problem where each variable is binary then the maximum number of variables that will be accepted is 477.

A simple example of solving an integer problem based on the input polynomial that was constructed above can be seen below:

  • from eqc_direct.client import EqcClient
  • # MUST FILL IN THE VALUES IN THIS FROM YOUR NETWORKING SETUP FOR THE DEVICE
  • eqc_client = EqcClient(ip_address="YOUR DEVICE IP ADDRESS", port="YOUR DEVICE PORT")
  • poly_coefs = [3, 2.1, 1.5, 7.9, 1, 1]
  • poly_indices = [[0,0,4], [0,1,1], [0,2,2], [0,2,3], [2,4,4], [3,3,3]]
  • # use lock to prevent other users from taking exclusive access to the device
  • lock_id, start_ts, end_ts=eqc_client.wait_for_lock()
  • try:
  • result_dict = eqc_client.solve_integer(
  • lock_id=lock_id,
  • poly_indices = poly_indices,
  • poly_coefficients = poly_coefs,
  • relaxation_schedule = 2,
  • num_levels = [2,2,3,4])
  • # release lock when finished using the device
  • finally:
  • lock_release_out = eqc_client.release_lock(lock_id=lock_id)

For more information on additional parameters see Advanced Usage and eqc_direct.client.EqcClient.solve_integer(). To learn about the response for this solve routine see eqc_direct.client.IntegerResult.

Sum constrained solver

The sum constrained solver solves for the objective over an affine simplex such that for each solution XX and sum constraint RR:

i=1nxi=Rxi>0\begin{split}\sum_{i=1}^{n} x_i=R \\ x_i>0\end{split}

This implication should be taken into account when analyzing solutions and selecting appropriate problems for this device.

Another important feature for the sum-constrained solver is the solution_precision, which distills the solution so that each xix_i is rounded to the unit of precision specified. For example, if solution_precision = 0.5 and sum_constraint = 10, for a solution with values [1.25,5.75,2.25,0][1.25, 5.75, 2.25, 0], one possible distilled solution would be [1,6,2.5,0.5][1, 6, 2.5, 0.5]. Notice that the distilled solution preserves the sum_constraint while ensuring that each value in the solution is divisible by the solution_precision.

A simple example of solving a sum constrained problem using the eqc_direct.client.EqcClient.solve_sum_constrained() can be seen below:

  • from eqc_direct.client import EqcClient
  • # MUST FILL IN THE VALUES IN THIS FROM YOUR NETWORKING SETUP FOR THE DEVICE
  • eqc_client = EqcClient(ip_address="YOUR DEVICE IP ADDRESS", port="YOUR DEVICE PORT")
  • poly_coefs = [3, 2.1, 1.5, 7.9, 1, 1]
  • poly_indices = [[0,0,4], [0,1,1], [0,2,2], [0,2,3], [2,4,4], [3,3,3]]
  • # use lock to prevent other users from taking exclusive access to the device
  • lock_id, start_ts, end_ts=eqc_client.wait_for_lock()
  • try:
  • result_dict = eqc_client.solve_sum_constrained(
  • lock_id=lock_id,
  • poly_indices = poly_indices,
  • poly_coefficients = poly_coefs,
  • relaxation_schedule = 2,
  • solution_precision=1,
  • sum_constraint = 100)
  • finally:
  • # release lock when finished using the device
  • lock_release_out = eqc_client.release_lock(lock_id=lock_id)

Each time a job is processed, it blocks for the duration of the device run when using this call. For information regarding results object, see eqc_direct.client.SumConstrainedResult.

System monitoring

eqc_direct.client.EqcClient.system_status() returns status_code and status_desc. For details, see eqc_direct.utils.SysStatus. In general, status_code greater than or equal to 3 indicates the system is currently in an errored state. See device manual for how to trouble shoot issues based on status_code. Displayed below is a simple system status check followed by a print out ofversions associated with device from eqc_direct.client.EqcClient.system_info():

  • from eqc_direct.client import EqcClient
  • eqc_client = EqcClient(ip_address="YOUR DEVICE IP ADDRESS", port="YOUR DEVICE PORT")
  • curr_sys_status = eqc_client.system_status()
  • sys_info = eqc_client.system_info()
  • print("System status:", curr_sys_status)
  • print("System info:", sys_info)

Device Lock Basics

Device locking ensures that only one process is running on the device at a time. In order to ensure this functionality, there are a few useful functions:

In order to ensure access to users there is a timer on the server that if a user is inactive for more than one minute and another user wishes to use the device they will be able to acquire the device lock and the previous idle user will lose it’s lock on the device. In order to help ease the process of acquiring the lock it’s recommended to use eqc_direct.client.EqcClient.wait_for_lock(). In order to ensure maximum device availability it is a good practice to release the lock if taking time between runs on the device.

Health monitoring and calibration for Dirac

Dirac devices periodically automatically calibrate to ensure that it is able to produce high quality results consistently. Similarily, health tests also run on set intervals to ensure that the device is functioning properly. If either of these operations fails the device will enter a hardware fail state see eqc_direct.utils.SysStatus for various status codes associated to this state. If the device enters an error state try power cycling the device with switch located on back panel. This will cause the device to calibrate and perform the health testing suite. If hardware failure state persists then contact QCi for further support https://quantumcomputinginc.ladesk.com