Skip to main contentIBM Quantum Documentation Preview
This is a preview build of IBM Quantum® documentation. Refer to quantum.cloud.ibm.com/docs for the official documentation.

Get started with Parity Twine Optimizer

See the API reference

Note

Qiskit Functions are an experimental feature available only to IBM Quantum® Premium Plan, Flex Plan, and On-Prem (via IBM Quantum Platform API) Plan users. They are in preview release status and subject to change.

For an overview of this function, see the Parity Twine Optimizer documentation home.


Set up

Authenticate using your IBM Quantum Platform API token and select the Qiskit Function as:

from qiskit_ibm_catalog import QiskitFunctionsCatalog

# Authenticate and load the Qiskit Function
catalog = QiskitFunctionsCatalog(
    channel="ibm_quantum_platform",
)
function = catalog.load("parityqc/parity-twine-optimizer")

Example

The Parity Twine Optimizer can be applied to a simple QUBO example as follows. The problem is first defined by using a dictionary:

problem = {"()": 3, "(0,)": 1, "(0, 1)": 2, "(1, 2)": -1}

Then, the variable type has be defined as binary or spin:

variable_type = "spin"

This defines the objective function 3+s0+2s0s1−s1s23 + s_0 + 2 s_0s_1 - s_1s_2 where si∈{−1,1}s_i \in \{-1, 1\}.

Choose a backend. For example:

backend_name = "ibm_phoenix"

Use catalog.backends() to see a list of available backends from the user account/instance.

If no backend is specified, the least-busy backend (the one with the least number of pending jobs) is automatically selected.

Once the optimizer is loaded (see previous), you can run it on the problem using default options:

function_job = function.run(
    problem=problem, variable_type=variable_type, backend_name=backend_name
)
print(f"Job ID: {function_job.job_id}")

Check the job status as follows:

# Monitor the job status
function_job.status()

Retrieve results as follows:

# Retrieve the job result if the status is DONE
result = function_job.result()

result

Printing the results gives the following:

{
    'solution': {'0': -1, '1': 1, '2': 1},
    'objective_value': -1.0,
    'solution_bitstring': '100',
    'metadata': {
        'circuit_metrics': {
            'depth': 20,
            'gate_count': 198,
            'two_qubit_gate_depth': 4,
            'two_qubit_gate_count': 4,
            'num_qubits': 3,
            'operations': {'delay': 158, 'rz': 17, 'sx': 14, 'cz': 4, 'measure': 3, 'x': 2}
        },
        'solver_info': {
            'variable_mapping': {'0': 0, '1': 1, '2': 2},
            'bitstring_distributions': {
                'before_postprocessing': {'100': 71760, ... },
                'after_postprocessing': {'100': 88440, '011': 11560}
            },
            'best_parameters': {
                'beta': [-0.46259546391008877],
                'gamma': [0.6181957189727373]
            }
        },
        'resource_usage': {
            'RUNNING: MAPPING': {'CPU_TIME': 42.878},
            'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU_TIME': 0.094},
            'RUNNING: WAITING_FOR_QPU': {'CPU_TIME': 790.623},
            'RUNNING: EXECUTING_QPU': {'QPU_TIME': 28.0},
            'RUNNING: POST_PROCESSING': {'CPU_TIME': 0.828}
        }
    }
}

The solution dictionary corresponds to the qubits defined in the problem (s0,s1s_0, s_1, and s2s_2) and gives their optimized spin values.

The objective_value is the cost or energy of the optimization problem. It quantifies the solution quality.

metadata gives information on the transpilation (two-qubit gate counts/depth, gates used, active qubits) and various runtimes for both quantum and classical compute time.

Additionally, metadata provides a glimpse into the internal workings of the algorithm. You can see the optimized variational parameters (beta and gamma) and review how the distribution of measured bitstrings improved after classical post-processing was applied to the raw quantum results.

All bitstrings in the result output can be mapped to the problem variables by using the variable_mapping. For example, you can map the 'solution_bitstring': '100' with the 'variable_mapping': {'0': 0, '1': 1, '2': 2} to the binary solution: {'0': 1, '1': 0, '2': 0}. Since you are solving the problem in terms of spin variables, you need to apply the binary to spin transformation (0 -> 1, 1 -> -1 ). You then arrive at the final solution 'solution': {'0': -1, '1': 1, '2': 1}.

Refer to the API reference for full details of the input to and output from the Parity Twine Optimizer function.