Tutorial preparation
Multi-body support was added to qci-client
in version 3.2.0, but in order to utilize this tutorial, a version of qci-client
of at least 4.0 is required.
In [1]:
- !pip install --quiet "qci-client>=4.0"
- import numpy as np
- from matplotlib import cm
- import matplotlib.pyplot as plt
- import qci_client as qc
Multi-body Tutorial
Multi-body problems are polynomials where the total degree of at least one term in the polynomial is higher than 2. For instance
is a two variable, cubic problem.
Optimization
Dirac-3 is a purpose-built device for finding global minima of a polynomial function. As demonstrated in the Dirac-3 Quick Start, it optimizes a multi-variate polynomial over a domain where is a positive value all must sum to.
Example
Observe the following visualization of the function. The surface with the jet color scale describes the function across the entire domain , while the surface in semi transparent blue shows the domain of the optimization problem with the sum constraint of . Notice the cross section with two extrema due to the cubic curvature indicates the function range Dirac-3 samples.
In [2]:
- X = np.linspace(0, 10, 100)
- Y = np.linspace(0, 10, 100)
- X, Y = np.meshgrid(X, Y)
- Z = X*Y**2 - X**2*Y - X*X - 2*X +Y*Y
- fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
- surface = ax.plot_surface(X, Y, Z, cmap=cm.jet)
- # Add a color bar which maps values to colors.
- fig.colorbar(surface, shrink=0.5, aspect=5)
- X2 = np.linspace(0, 10, 20)
- Y2 = 10 - X2
- Z2 = X2 * Y2 ** 2 - X2 ** 2 * Y2 - X2 ** 2 - 2 * X2 + Y2 ** 2
- ax.plot3D(X2, Y2, Z2, "k-")
- X3 = X2 * np.ones((20, 20))
- Y3 = 10 - X3
- Z3 = np.linspace(np.min(Z), np.max(Z), 20) * np.ones((20, 20))
- sum_surface = ax.plot_surface(X3, Y3, Z3.T, alpha=0.2)
- ax.view_init(azim=15, elev=20)
- ax.set_xlabel("$x$")
- ax.set_ylabel("$y$")
- ax.set_zlabel("$f(x,y)$")
- ax.zaxis.set_label_position("upper")
- ax.zaxis.set_ticks_position("upper")
Out [ ]:
<Figure size 640x480 with 2 Axes>
Running the Problem
We will prepare data in a list and a list of lists, upload the polynomial file to Qatalyst and submit a job.
QciClient Instantiation
This call to QciClient
uses the environment variables QCI_TOKEN
and QCI_API_URL
to configure the API connection. It may also be called with api_token
and url
parameters to configure it explicitly. See the Quick Start on Cloud tutorial for a deeper explanation on this configuration.
In [3]:
- client = qc.QciClient()
Polynomial Format
The ability to support higher order terms efficiently for the majority of problems requires a sparse format. That format is inspired by polynomials themselves. Two different arrays are required. The first is a coefficient array. Each term in the function has an entry in the coefficient array. The second array, the indices array, is where to indicate which term the corresponding coefficient is for. The second polynomial from above is presented here.
is represented in polynomial format
poly_coefficients = [1, -1, 1, 1]
poly_indices = [[1, 2, 2], [1, 1, 2], [0, 0, 1], [0, 0, 2]]
In [4]:
- poly_coefficients = [1, -1, 1, 1]
- poly_indices = [[1, 2, 2], [1, 1, 2], [0, 0, 1], [0, 0, 2]]
- data = []
- for i in range(len(poly_coefficients)):
- data.append({
- "val": poly_coefficients[i],
- "idx": poly_indices[i]
- })
- poly_file = {"file_name": "test-polynomial",
- "file_config": {"polynomial": {
- "min_degree": 1,
- "max_degree": 3,
- "num_variables": 2,
- "data": data
- }}}
- file_id = client.upload_file(file=poly_file)["file_id"]
- file_id
Out [4]:
'6672ed6798263204a365ddc1'
In [5]:
- poly_file
Out [5]:
{'file_name': 'test-polynomial', 'file_config': {'polynomial': {'min_degree': 1, 'max_degree': 3, 'num_variables': 2, 'data': [{'val': 1, 'idx': [1, 2, 2]}, {'val': -1, 'idx': [1, 1, 2]}, {'val': 1, 'idx': [0, 0, 1]}, {'val': 1, 'idx': [0, 0, 2]}]}}}
In [6]:
- job_body = client.build_job_body(job_type="sample-hamiltonian", polynomial_file_id=file_id, job_params={"device_type": "dirac-3", "sum_constraint": 10, "solution_precision": 1, "relaxation_schedule": 1, "num_samples": 15})
- job_body
Out [6]:
{'job_submission': {'problem_config': {'normalized_qudit_hamiltonian_optimization': {'polynomial_file_id': '6672ed6798263204a365ddc1'}}, 'device_config': {'dirac-3': {'num_samples': 15, 'relaxation_schedule': 1, 'solution_precision': 1, 'sum_constraint': 10}}}}
In [7]:
- response = client.process_job(job_body=job_body)
Out [ ]:
2024-06-19 08:38:31 - Dirac allocation balance = 0 s (unmetered) 2024-06-19 08:38:31 - Job submitted: job_id='6672ed67a3e6a645a5c4e7c5' 2024-06-19 08:38:31 - QUEUED 2024-06-19 08:38:34 - RUNNING 2024-06-19 08:38:55 - COMPLETED 2024-06-19 08:38:57 - Dirac allocation balance = 0 s (unmetered)
In [8]:
- response
Out [8]:
{'job_info': {'job_id': '6672ed67a3e6a645a5c4e7c5', 'job_submission': {'problem_config': {'normalized_qudit_hamiltonian_optimization': {'polynomial_file_id': '6672ed6798263204a365ddc1'}}, 'device_config': {'dirac-3': {'num_samples': 15, 'relaxation_schedule': 1, 'solution_precision': 1, 'sum_constraint': 10}}}, 'job_status': {'submitted_at_rfc3339nano': '2024-06-19T14:38:31.913Z', 'queued_at_rfc3339nano': '2024-06-19T14:38:31.913Z', 'running_at_rfc3339nano': '2024-06-19T14:38:32.764Z', 'completed_at_rfc3339nano': '2024-06-19T14:38:54.734Z'}, 'job_result': {'file_id': '6672ed7e98263204a365ddc3', 'device_usage_s': 20}}, 'status': 'COMPLETED', 'results': {'counts': [4, 4, 2, 2, 2, 1], 'energies': [-77.1194382, -84.6596832, -74.1873169, -83.8009644, -83.8447723, -86.1170654], 'solutions': [[7.1276598, 2.8723404], [8.182374, 1.817626], [7.0072289, 2.9927711], [7.504097, 2.4959033], [7.5076513, 2.4923487], [7.8074245, 2.1925759]], 'distilled_energies': [-86, -86, -86, -86, -86, -86], 'distilled_solutions': [[8, 2], [8, 2], [8, 2], [8, 2], [8, 2], [8, 2]]}}
Dirac-3 has identified multiple solutions near the integer optimal solution [8, 2]
with a value of -86 with some less than -86.
Next Steps
Beyond two variables, visualization becomes tricky, but the value of the solver becomes higher. The current version of Dirac-3 supports 135 variables with rank 3 polynomials.
Try experimenting with different polynomials using the format described.