# Fixstars Amplify SDK

Fixstars Amplify makes it easier and more efficient for developing applications that require complex and specialized skills of quantum annealing.

## Workflow

Fixstars Amplify automates the 3 steps of "logical model conversion", "physical model conversion", and "machine execution", thereby enabling a more intuitive workflow for quantum annealing programming.

#### Conventional programming

##### 1. Formulate a problem

Express the problem in the form of mathematical expressions that can be run by an Ising machine

##### 2. Convert to a logical model

Convert the objective functions and constraints of the problem into the Ising model or QUBO

##### 3. Convert to a physical model

Reconvert the logical model into a physical model that meets machine specifications and limitations

##### 4. Input data to a machine

Convert the physical model to data in accordance with the machine's API specifications

##### 5. Run the machine

Can run only a specific machine

#### Programming with Fixstars Amplify

##### 1. Formulate a problem

Express the problem in terms of mathematical expressions and write a corresponding code

##### 2. Run a machine

Can choose a machine from multiple machines

## Features

Amplify SDK provides an intuitive platform to handle various input forms and constraints for running the Ising machines.
In addition, it also reconciles complicated model transformation of inputs and inverse transformation of outputs for each machine.

# Formulate the input model
q = gen_symbols(BinaryPoly, 2)
f = 1 - q[0] * q[1]

# Set up the machine to run
client = FixstarsClient()

# Run the machine to get results
s = Solver(client)
result = s.solve(f)
values = result.solutions[0].values

# Interpret the results
solution = decode_solution(q, values)

>>> print(f"result: {q} = {solution}")
result: [q_0, q_1] = [1, 1]

Amplify makes it possible to handle various mathematical formulas independent of the machine of your choice.
It also supports the input of higher order polynomials, which are difficult for ordinary annealing machines to handle.

##### Binary polynomial
q = gen_symbols(BinaryPoly, 3)
f = 1 - q[0] * q[1] + q[2]
>>> f
- q_0 q_1 + q_2 + 1.000000
##### Ising polynomial
s = gen_symbols(IsingPoly, 3)
f = 1 - s[0] * s[1] + s[2]
>>> f
- s_0 s_1 + s_2 + 1.000000
##### Binary matrix
q = BinaryMatrix(4)
>>> q
[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]
##### Ising matrix
q = IsingMatrix(4)
>>> q
[[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]]
##### Higher order binary polynomial
q = gen_symbols(BinaryPoly, 3)
f = q[0] * q[1] * q[2] + q[0] * q[0]
>>> f
q_0 q_1 q_2 + q_0
##### Higher order Ising polynomial
s = gen_symbols(IsingPoly, 3)
f = s[0] * s[1] * s[2] + s[0] * s[0]
>>> f
s_0 s_1 s_2 + 1.000000
##### Logical formula
x = gen_symbols(LogicPoly, 3)
f = (x[0] | x[1]) & (x[1] | x[2])
>>> f
- x_0 x_1 x_2 + x_0 x_2 + x_1

For binary and Ising polynomials, Amplify performs arithmetic operations and high-spped mathematical processing specialized for each algebraic law.
It also provides useful functions for representing mathematical expressions in natural ways.

###### $$f=\displaystyle\sum_{i=0}^{n-1}q_i$$
                  q = gen_symbols(BinaryPoly, 8)  # Generate 8 binary variables
f = sum_poly(q)                 # Sum all variables
>>> f
q_0 + q_1 + q_2 + q_3 + q_4 + q_5 + q_6 + q_7
###### $$f=\displaystyle\sum_{i=0}^{n-1}\displaystyle\sum_{j=0}^{n-1}q_i q_j$$
                  q = gen_symbols(BinaryPoly, 3)  # Generate 3 binary variables
f = sum_poly(3, lambda i:       # Sum the combinations of all variables
sum_poly(3, lambda j: q[i] * q[j]))
>>> f
2.0 q_0 q_1 + 2.0 q_0 q_2 + 2.0 q_1 q_2 + q_0 + q_1 + q_2
###### $$f=\displaystyle\sum_{i=0}^{n-1}\bigg(\displaystyle\sum_{j=0}^{n-1}q_{ij} -1\bigg)^2$$
                  q = gen_symbols(BinaryPoly, 2, 2)  # Generate 2x2 binary variables
f = sum_poly(2, lambda i: (        # Double summation of mathematical expressions
sum_poly(2, lambda j: q[i][j]) - 1) ** 2)
>>> f
2.0 q_0 q_1 + 2.0 q_2 q_3 - q_0 - q_1 - q_2 - q_3 + 2.0

Amplify abstracts the constraint conditions imposed on the input variables. It automatically generates penalty functions for the Ising machines and checks if the constraints are satisfied. This greatly reduces difficulties in handling constraint conditions with the Ising machines.

##### Minimum value constraint
###### $$f = 0 \space {\rm for} \space \min f = 0$$
q = gen_symbols(BinaryPoly, 2)  # Generate 2 binary variables
penalty(q[0] * q[1])        # Minimum value constraint q_0 q_1 = 0
##### Equality constraint
###### $$f = k$$
q = gen_symbols(BinaryPoly, 8)  # Generate 8 variables
equal_to(sum_poly(q), 1)        # Equality constraints \sum q = 1
##### Inequality constraint
###### $$f \le k$$
q = gen_symbols(BinaryPoly, 3)  # Generate 3 binary variables
less_equal(3 * q[0] + 2 * q[1] + q[2], 3) # Inequality constraints 3 * q[0] + 2 * q[1] + q[2] <= 3

Amplify is compatible with almost all available annealing machines.
By providing a common driver, it absorbs the difficulties that arise when using various machines due to their differences in hardware and interface specifications. This makes it possible to seamlessly switch between multiple machines with minimal changes.

# Example for Fixstars Amplify AE
client = FixstarsClient()

# Example for D-Wave 2000Q
client = DWaveClient()

# Example for Fujitsu Digital Annealer
client = FujitsuDASolverClient()

# Example for Toshiba SBM
client = ToshibaClient()

# Set Solver for the machine
s = Solver(client)