HitachiĀ¶

Hitachi Annealing Cloud WebĀ¶

The CMOS annealing machine provided by Hitachi.

ć‚½ćƒ«ćƒćƒ¼ä»•ę§˜:

Binary variable

Ising variable

Integer variable

Real variable

Objective function

-

2nd

-

-

Equality constraint

-

-

-

-

Inequality constraint

-

-

-

-

Note

There are three types of machines that can be used, specified by type. (Defaultļ¼štype = 4)

  • type = 3: GPU 32bit (int)

    • Can process 256k spins (equivalent to 512x512 Kingā€™s graph) using GPGPU.

  • type = 4: GPU 32bit (float)

    • Can process 256k spins (equivalent to 512x512 Kingā€™s graph) using GPGPU.

  • type = 5: ASIC 4bit

    • Can process 147,456 spins (equivalent to a 384x384 Kingā€™s graph) in a single annealing.

Machines of type = 3, 5 can only handle models with integer coefficients. Refer to API Reference for the range of integer values for each type. Even if the objective function has only integer coefficients, the model submitted to the solver may contain real values because the Amplify SDK performs model conversion and graph embedding within the amplify.solve() function. In such cases, Amplify SDK internally converts them to integers by rounding away from zero, which may result in a discrepancy from the intended formulation. When utilizing these machines, it is recommended to use amplify.HitachiClient.solve() method directly. (See here).

Configuration example:
from amplify import HitachiClient

client = HitachiClient()

# Set API token
client.token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Set Number of annealing runs to 3
client.parameters.num_executions = 3

# Output average value per site of spin
client.parameters.outputs.averaged_spins = True

# Output the average value of energy
client.parameters.outputs.averaged_energy = True
Execution example:
from amplify import VariableGenerator, Model, solve

# Create decision variables and the objective function
g = VariableGenerator()
s = g.array("Ising", 2)
f = s[0] * s[1] + s[0] - s[1] + 1

# Create a model
model = Model(f)

# Run the solver
result = solve(model, client)

Obtain the solver version:

>>> client.version
'v2'

Obtain detailed solution:

>>> result.client_result.result
HitachiClient.Result.Result({
"execution_time": 185832138,
"energies": [
    -3.0,
    -3.0,
    -3.0
],
"spins": [
    [[0, 0, -1], [1, 0, 1]], [[0, 0, -1], [1, 0, 1]], ...
],
"averaged_energy": -3.0,
"averaged_spins": [
    [1, 0, 1], [0, 0, -1]
]
})

Execute with client interfaceĀ¶

amplify.HitachiClient.solve() method submits the problem directly to the solver using the solverā€™s API and retrieves the results. This method is useful for problems that are optimized for the topology of the Hitachi CMOS Annealing Machine chip or for problems that are already embedded in the graphs.

The CMOS Annealing Machine API defines the Ising variables with coordinates \((x, y)\) on the Kingā€™s graph. On the other hand, the Amplify SDK manages variables by ID (id). Thus, in the amplify.HitachiClient class, the mapping to the coordinates on Kingā€™s graph is defined as id = x + y * graph_size.

Using the graph_size corresponding to the type of the CMOS Annealing Machine, the variables satisfying this relationship can be output as follows.

from amplify import VariableGenerator, HitachiClient

client = HitachiClient()
client.parameters.type = 3
client.token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
graph_size = client.graph.shape[0]  # Size of a side of the graph

g = VariableGenerator()
# Generate Ising variables on the King's graph of graph_size x graph_size
s = g.array("Ising", (graph_size, graph_size))

The array indices of the generated Ising variable array s correspond to the coordinates on Kingā€™s graph. For example, s[x, y] represents the Ising variable at \((x, y)\) on the Kingā€™s graph.

Then, an objective function Poly must satisfy the following conditions.

  • Consists only of Ising variables of degree two or less.

  • Constraints are included in the objective function in advance as a penalty function.

  • The range of coefficient values is restricted depending on the machine type (see API Reference)

  • The indices of a quadratic term are adjacent to the two-dimensional array vertically, horizontally, or diagonally (adjacent on the Kingā€™s graph).

The following is an example of an objective function that satisfies the above conditions.

f = s[0, 0] * s[0, 1] + 2 * s[0, 0] * s[1, 0] - s[0, 1] * s[1, 0] - s[1, 0] * s[1, 1] + 1

The solver response is returned when the created objective function is submitted with the amplify.HitachiClient.solve() method.

>>> res = client.solve(f)
>>> res.result.energies
array([-5.])
>>> res.result.spins
[[(0, 0, 1), (1, 0, -1), (0, 1, -1), (1, 1, -1)]]

The solution \(s'\) for each Ising variable returned by the solver is stored in spins in the form [[(x, y, s'), ...], ...], where s' represents the value of the Ising variable at the coordinates \((x, y)\) on the Kingā€™s graph. Note that no values are returned for variables that are not used in the objective function. Since multiple solutions may be returned, variable values are stored as a list of lists of tuples.

To obtain the solution of the Ising variable on the Kingā€™s graph in the same array shape as the variable array s, you can do the following.

import numpy as np

# Generate a zero array of graph_size x graph_size
spin_values = np.zeros((graph_size, graph_size))

# Enumerate and assign solutions with index 0
# (If multiple solutions are returned, an appropriate index should be specified)
for x, y, s in res.result.spins[0]:
    spin_values[x, y] = s