Products & servicesTechnologyCompanyInvestor relationsResource libraryNews
Contact us
Resource library
    Resource library home
    Developer resources
      Entropy quantum optimization
        Dirac Quick Start
        Dirac-3 Developer Beginner Guide
        Dirac 3s Software Interface
        Multibody formulation
        QUBO formulation
        QLCBO formulation
        QBoost formulation
        qci-client software package
          Getting Started
          Basic Usage
          qci-client
          Dirac-3S (dirac-3s)
          Dependencies
          Index
          Module Index
        eqc-direct software package
        eqc-models software package
      Quantum random number generation
      Reservoir computing
    Applications
    Lessons
    Benchmarking
    Research and publications
    Support

Couldn’t find what you are looking for? Reach out to technical support.

Contact support
Privacy PolicyCookie PolicyTerms of UseForward Looking StatementsAccessibility Statement
Terms and Conditions of SaleEnd User License Agreement

© 2018-2026 Quantum Computing Inc.

Download

Default

Dirac-3S (dirac-3s)

dirac-3s is QCi’s second generation Dirac-3 device. It runs the same two qudit problem types as dirac-3, namely the normalized-qudit (continuous) and qudit (integer) Hamiltonian optimizations, and is selected by name in the job parameters.

Selecting the Dirac-3S Device

Pass device_type="dirac-3s" in the job_params dictionary given to build_job_body—

  • job_body = client.build_job_body(
  • job_type="sample-hamiltonian",
  • job_params={"device_type": "dirac-3s", "sum_constraint": 1},
  • polynomial_file_id=file_id,
  • )

The device_type key is required for every job type. Omitting it raises—

  • ValueError: no 'device_type' specified in job_params, must be one of ('dirac-1',
  • 'dirac-3', 'dirac-3s', 'dirac-3_normalized_qudit', 'dirac-3_qudit')

An unrecognized device name raises a ValueError from qci_client.optimization.enum.DeviceType.

Supported Job Types on Dirac-3S

dirac-3s accepts both qudit job types.

job_type

problem_config key

Required file ID

sample-hamiltonian

normalized_qudit_hamiltonian_optimization

exactly one of polynomial_file_id or hamiltonian_file_id

sample-hamiltonian-integer

qudit_hamiltonian_optimization

exactly one of polynomial_file_id or hamiltonian_file_id

Use sample-hamiltonian for continuous variables subject to a sum constraint, and sample-hamiltonian-integer for integer variables with a bounded number of levels per variable.

Supplying both polynomial_file_id and hamiltonian_file_id, or neither, raises—

  • AssertionError: exactly one of hamiltonian_file_id or polynomial_file_id must be
  • specified for job_type='<job_type>'
Note
hamiltonian_file_id is deprecated for the Hamiltonian job types. Prefer polynomial_file_id.

Every other job type is restricted to qubit devices. Pairing one with dirac-3s raises ValueError: <job_type> not supported on dirac-3s.

Device-Name Remapping and Job Metrics

dirac-3 is a convenience alias. When it is requested, the client rewrites the device_config key to the specific device name that the API expects, based on the job type. dirac-3s is passed through literally and is never rewritten.

Requested device_type

job_type

Submitted device_config key

dirac-3

sample-hamiltonian

dirac-3_normalized_qudit

dirac-3

sample-hamiltonian-integer

dirac-3_qudit

dirac-3s

either

dirac-3s

So a job body built for dirac-3s keys its device configuration exactly as written—

  • {
  • "job_submission": {
  • "problem_config": {
  • "normalized_qudit_hamiltonian_optimization": {
  • "polynomial_file_id": "<file id>"
  • }
  • },
  • "device_config": {
  • "dirac-3s": {
  • "num_samples": 5,
  • "relaxation_schedule": 1,
  • "sum_constraint": 10
  • }
  • }
  • }
  • }

This matters when reading job metrics, which are keyed by the device name that was actually submitted rather than the one that was requested. Read the device block without hardcoding the name—

  • metrics = client.get_job_metrics(job_id=job_id)
  • device = next(iter(metrics["job_metrics"]["time_ns"]["device"].values()))

Dirac-3S Device Configuration Parameters

job_params is a flat dictionary. build_job_body sorts its keys into problem_config or device_config. The parameters below are the ones routed to device_config for the two job types that dirac-3s supports.

num_samples

How many samples the stochastic solver draws.

  • Range: 1 to 100, inclusive.
  • Default: 1.
  • Accepted by both job types.

relaxation_schedule

Tunes a group of device parameters as a preset. Higher schedules give better solution quality at the cost of longer evolution time.

  • Range: 1 to 4, inclusive.
  • Default: 1.
  • Accepted by both job types.

sum_constraint

The value that the solution variables must sum to. This is what makes a normalized-qudit problem normalized: the solution lives on a simplex of the given size.

  • Range: 1 to 10000, inclusive.
  • Accepted by sample-hamiltonian only.

num_levels

The number of discrete levels available to each variable, as a list of integers. A variable with k levels ranges over 0 through k - 1.

  • Required by sample-hamiltonian-integer. Omitting it raises AssertionError: num_levels is a required field.

mean_photon_number

Advanced. Overrides the value that relaxation_schedule would otherwise set implicitly.

  • Range: 0.0000667 to 0.0066666, inclusive.
  • Accepted by both job types.

quantum_fluctuation_coefficient

Advanced. Also overrides a value implied by relaxation_schedule.

  • Range: 1 to 100, inclusive.
  • Accepted by both job types.
Note
The client validates that parameter names are recognized and that the job type and device are compatible. It does not range-check numeric values. The ranges above are enforced by the API, which rejects out-of-range submissions with an requests.HTTPError. Unrecognized keys are dropped from the job body without warning, so inspect the built body when a parameter appears to have no effect.
Warning
The solution_precision parameter is no longer supported. Passing it to build_job_body emits a UserWarning and the value is ignored; use client-side postprocessing to distill continuous solutions instead.

Continuous Example on Dirac-3S

This minimizes the polynomial H = -x1^2 + 2*x1*x2 - x2^2 subject to x1 + x2 = 1 with both variables non-negative. The constraint is expressed through sum_constraint rather than through a constraints file, which is what the normalized-qudit problem type is for. The optimum is H = -1, reached when one variable takes the whole budget and the other is zero.

In the polynomial file, each entry of data is one term: idx names the variables in that term and val is its coefficient. Variables are numbered from 1, so [1, 1] is x1^2 and [1, 2] is x1*x2. Every idx list has length max_degree, and all three terms here are of degree 2.

  • from qci_client import QciClient
  • client = QciClient()
  • polynomial = {
  • "file_name": "dirac-3s-continuous-example",
  • "file_config": {
  • "polynomial": {
  • "num_variables": 2,
  • "min_degree": 2,
  • "max_degree": 2,
  • "data": [
  • {"idx": [1, 1], "val": -1.0},
  • {"idx": [1, 2], "val": 2.0},
  • {"idx": [2, 2], "val": -1.0},
  • ],
  • }
  • },
  • }
  • file_id = client.upload_file(file=polynomial)["file_id"]
  • job_body = client.build_job_body(
  • job_type="sample-hamiltonian",
  • job_name="dirac-3s-continuous-example",
  • job_tags=["quickstart"],
  • job_params={
  • "device_type": "dirac-3s",
  • "relaxation_schedule": 1,
  • "sum_constraint": 1,
  • },
  • polynomial_file_id=file_id,
  • )
  • response = client.process_job(job_body=job_body)
  • if response["status"] != "COMPLETED":
  • raise RuntimeError(f"job did not complete: {response['status']}")
  • print(f"x = {response['results']['solutions'][0]}")
  • print(f"H = {response['results']['energies'][0]}")

process_job blocks until the job reaches a terminal status and, because verbose defaults to True, logs its progress—

  • 2026-08-17 10:14:02 - Dirac allocation balance = 600.0 s
  • 2026-08-17 10:14:03 - Job submitted: job_id='6534d9d1e4b0a1f2c3d40001'
  • 2026-08-17 10:14:03 - QUEUED
  • 2026-08-17 10:14:11 - RUNNING
  • 2026-08-17 10:14:19 - COMPLETED
  • 2026-08-17 10:14:19 - Dirac allocation balance = 599.0 s
  • x = [1.0, 0.0]
  • H = -1.0

Integer Example on Dirac-3S

This runs an integer problem on dirac-3s and drives the polling loop by hand instead of using process_job. The pattern is useful when other work should proceed while the job runs, or when a failed job is to be handled without an exception.

The polynomial spans degrees 2 through 4 over two variables, so every idx list has length 4 and lower-degree terms are left-padded with 0. The index 0 is padding, not a variable: [0, 0, 1, 1] is x1^2, [0, 1, 1, 1] is x1^3, and [1, 1, 1, 1] is x1^4. Indices must be non-decreasing from left to right, so each term has exactly one representation.

The num_levels entry gives one level count per variable and is required for integer jobs.

  • from qci_client import QciClient, JobStatus, JOB_STATUSES_FINAL
  • client = QciClient()
  • polynomial = {
  • "file_name": "dirac-3s-integer-example",
  • "file_config": {
  • "polynomial": {
  • "num_variables": 2,
  • "min_degree": 2,
  • "max_degree": 4,
  • "data": [
  • {"idx": [0, 0, 1, 1], "val": 1.0},
  • {"idx": [0, 1, 1, 1], "val": -2.0},
  • {"idx": [1, 1, 1, 1], "val": 1.0},
  • ],
  • }
  • },
  • }
  • file_id = client.upload_file(file=polynomial)["file_id"]
  • job_body = client.build_job_body(
  • job_type="sample-hamiltonian-integer",
  • job_name="dirac-3s-integer-example",
  • job_params={
  • "device_type": "dirac-3s",
  • "num_levels": [3, 4],
  • "num_samples": 2,
  • "relaxation_schedule": 2,
  • },
  • polynomial_file_id=file_id,
  • )
  • assert list(job_body["job_submission"]["device_config"]) == ["dirac-3s"]
  • job_id = client.submit_job(job_body=job_body)["job_id"]
  • print(f"submitted {job_id}")
  • status = JobStatus.SUBMITTED
  • while status not in JOB_STATUSES_FINAL:
  • status = JobStatus(client.get_job_status(job_id=job_id)["status"])
  • response = client.get_job_results(job_id=job_id)
  • if status is not JobStatus.COMPLETED:
  • print(f"job finished as {status.value}")
  • print(response["job_info"])
  • else:
  • results = response["results"]
  • for solution, energy, count in zip(
  • results["solutions"], results["energies"], results["counts"]
  • ):
  • print(f"x = {solution} H = {energy} seen {count}x")
  • submitted 6534d9d1e4b0a1f2c3d40002
  • x = [1, 0] H = 0.0 seen 1x
  • x = [0, 2] H = 0.0 seen 1x

The assertion above holds because dirac-3s is never remapped, unlike dirac-3.

Poll against JOB_STATUSES_FINAL rather than against JobStatus.COMPLETED, otherwise a failed job loops forever. ERRORED and CANCELLED are terminal too, and leave results as None, so always check status before indexing into results.

This polynomial factors as x1^2 * (x1 - 1)^2, so it reaches zero at x1 = 0 and x1 = 1. Note that x2 does not appear in any term: it is declared by num_variables and given a level count, but the objective does not constrain it, so its value varies freely between samples.

Previous page
Next page

Content

  • Dirac-3S (dirac-3s)
  • Selecting the Dirac-3S Device
  • Supported Job Types on Dirac-3S
  • Device-Name Remapping and Job Metrics
  • Dirac-3S Device Configuration Parameters
  • num_samples
  • relaxation_schedule
  • sum_constraint
  • num_levels
  • mean_photon_number
  • quantum_fluctuation_coefficient
  • Continuous Example on Dirac-3S
  • Integer Example on Dirac-3S