Solving Factoring problem with Ising machine

Introduction

Ising machines are powerful tools for solving SpinGlass problem. Given that many NP problems can be reduced to SpinGlass, it's possible to solve these NP problems with Ising machines. Among these problems, the Factoring problem is one of the most important problems and it's the basis of RSA encryption system for its practical hardness.

Therefore, solving Factoring problem with Ising machine is a significant task. In this example, we will show how to reduce the Factoring problem to SpinGlass with ProblemReductions.jl and solve it with an Ising machine solver GenericTensorNetworks.jl

Factoring -> SpinGlass -> Ising machine

Consider a simple Factoring problem: $6 = p \times q$, we need to figure out the prime factors of 6. In our package, the Factoring problem is modeling under binary representation and when we initialize an instance, we need to offer the information of the number of bits for the two factors. Here, since 6 is a 3 bit number, the number of bits for the two factors are both 2.

Run the following code in Julia REPL:

using ProblemReductions
factoring = Factoring(2, 2, 6) # initialize the Factoring problem
Factoring(2, 2, 6)

Using reduction_graph and reduction_paths, we could obtain the way to reduce Factoring to SpinGlass.

g = reduction_graph()
paths = reduction_paths(g,Factoring,SpinGlass)
1-element Vector{Vector{Type}}:
 [Factoring, CircuitSAT, SpinGlass]

The input of reduction_paths is the reduction graph and the types of source and target problems. And the output is a nested vector, each element of the outer vector is a path from source to target problem.

Then we could use implement_reduction_path to obtain the corresponding SpinGlass problem.

reduction_result = implement_reduction_path(paths[1], factoring)
target = target_problem(reduction_result)
SpinGlass{HyperGraph, Vector{Int64}}(HyperGraph(44, [[1, 2], [1, 3], [2, 3], [1], [2], [3], [4], [3, 4], [3, 5], [3, 6]  …  [38, 42], [36, 42], [42], [37, 43], [25, 43], [43], [42, 43], [42, 44], [43, 44], [44]]), [1, -2, -2, 2, 2, 0, 0, 1, -1, -2  …  -2, -2, -3, -2, -2, -3, 1, -2, -2, 1])

Note that the output of implement_reduction_path is a AbstractReductionResult, which contains the target problem and reduction information. So we need to extract the target problem by target_problem function.

import GenericTensorNetworks # import Ising machine solver
gtn_problem = GenericTensorNetworks.SpinGlass(
                  target.graph.n,
                  target.graph.edges,
                  target.weights
                )
result = GenericTensorNetworks.solve(
                    GenericTensorNetworks.GenericTensorNetwork(gtn_problem),
                    GenericTensorNetworks.SingleConfigMin()
                  )[]
(-92.0, GenericTensorNetworks.ConfigSampler{44, 1, 1}(01000000000000100000000001110010000011010000))ₜ

Here we use GenericTensorNetworks.jl to solve the SpinGlass problem and obtain the result, we need to extract the solution for source problem from the result.

extract_solution(reduction_result, 1 .- 2 .* Int.(GenericTensorNetworks.read_config(result)))
4-element Vector{Int64}:
 0
 1
 1
 1

The result is 01 and 11, decimally 2 and 3, which yields the correct factors of 6.

Conclusion

In this example, we show how to reduce Factoring problem to SpinGlass and solve it with Ising machine solver. This shows the power of ProblemReductions.jl in helping Problem Reduction.

For your convenience, here is how to use ProblemReductions.jl to reduce source problem to target problem:

  • Initialize the source problem source = SourceProblem(...), ... is the parameters of the source problem.
  • Obtain the reduction paths paths = reduction_paths(reduction_graph(), SourceProblem, TargetProblem).
  • Implement the reduction path reduction_result = implement_reduction_path(paths[1], source).
  • Extract the target problem target = target_problem(reduction_result).

This page was generated using Literate.jl.