Skip to content

How to use

Elscrux edited this page Feb 5, 2025 · 5 revisions

How to use

Frontend

The ProvideQ frontend (main|dev) visualizes the concepts of the toolbox in a user-friendly manner and enables interested users to test the toolbox's capabilities. However, the frontend is not suitable for more advanced use-cases such as batch processing or integration as a component into larger pieces of software.

Backend

For programmatic use-cases we offer a full API (main|dev). This is the same API that powers the ProvideQ frontend, which shows that the possible use-cases are endless. One could create a different kind of user interface, integrate it into another website or application, build batch processing functionality on top of the API, or use it for any custom programmatic use case that is relevant to you.

Anyone familiar with a REST API should already have a good understanding of the purpose of the individual endpoints in our API. In essence, the API manages three concepts.

  • Problem Type
  • Problem Instance
  • Solver

Problem Type

For each problem type implemented in the toolbox, we provide a distinct set of endpoints. Examples include the Vehicle Routing Problem or the QUBO Problem.

Problem Instance

A problem instance is the core piece that is required to interact with when solving a problem. The API defines ways to create, read, and update a problem. According to the REST API conventions, we define the following endpoints:

– GET /problems/{problemType}
This endpoint is used to get all problems of a problem type that have been created.

– GET /problems/{problemType}/{problemId}
This GET endpoint is a specialized variant that only returns the problem with the requested id.

– POST /problems/{problemType}
The POST request creates a new problem of the specified type. The request body takes all relevant information, such as the problem input. Refer to the API specification for all the details.

– PATCH /problems/{problemType}/{problemId}
Using the PATCH requests, it is possible to adjust certain values about the problem. The fields 'input', 'solverId', 'solverSettings', and 'state' can be changed using this request. The 'state' field must be set to 'SOLVING' in order to start the solving process using the specified solver. The other fields must be set before the problem state is started. After this point in time, it is not possible to adjust them. The 'input' field stores all information about the problem to solve. The fields for 'solverId' and 'solverSettings' determine what solver to use for the solving process and what settings specific to the solver should be used.

Solver

Each solver is tied to one specific problem type. The purpose of each solver is to take an input of a supported input format and calculate a valid output, however it sees fit. This includes quantum and classical solvers.\

GET /solvers/{problemType}
The possible solvers for a given problem type can be explored via the endpoint. You will receive a list of solvers with their ids and names.
Additionally, solvers may define any amount of subroutines that they require to solve a problem instance. The solver can call into their subroutines for use in their solution process.

GET /solvers/{problemType}/{solverId}/sub-routines
Subroutines are solvers themselves, and thus there can be an arbitrary number of nested solvers that are used to solve a problem. You can list the subroutines of a certain solver via the endpoint. The response contains a list of subroutine definitions with their typeId and a description. The description specifies the use of the subroutine in the solving process.

– POST /problems/{problemType}
Furthermore, solvers may define settings which can include aspects such as the number of clusters that a clusterer should create, or an API token that is used to execute a quantum circuit on a quantum backend. They can be explored via the endpoint GET /solvers/cluster-vrp/{solverId}/settings

– GET /problems/{problemType}/{problemId}/bound
Some problems support the calculation of an upper or lower bound for their solution. We support this through this special endpoint for more insight into the quality of the problem solution.

– GET /problems/{problemType}/{problemId}/bound/compare
This endpoint makes it possible to compare the problem's bound with its actual solution. Note that this is only possible after the problem is solved and once the bound of a problem is calculated.

API Usage

Python Examples API Usage via Code

We provide a Python library that makes it easy to interact with the API. This library is available here.

Example API Walkthrough

We want to solve a VRP problem. For that we have a textual representation of the problem instance in the VRP format.

Our first step is to call the request POST /problems/vrp to create a problem with the input set to our problem instance. At this point, the problem has already been created in the toolbox. In the response of the initial POST request, we received the id that the toolbox assigned to our problem. We can always request the current representation of our problem via GET /problems/vrp/{problemId}.

Now that we have created the problem, we cannot start it directly. As long as the backend shows the problem state as 'NEEDS_CONFIGURATION', we are missing a piece to start the solving process. In this case, we haven't selected a solverId yet.

To do that, we first need to know which solver we want to use. We can explore our options using the GET /solvers/vrp request. For this example, we want to use the solver which wants to cluster the VRP problem first and save this solver's id. To do that, we can use a PATCH request PATCH /problems/vrp/{problemId} in which we assign the solverId to the id of the VRP solver that uses clustering. Now, our problem should be ready to solve. Requesting data on our problem using a GET request should verify this.

As a next step, we can send another PATCH request and set the 'state' to 'SOLVING' to initiate the solving process. Doing this, one might expect that, after some time, there will be a solution to our problem. However, this is not the case. This is because our VRP solver with clustering defines a subroutine which needs to be configured to cluster the VRP problem. We can check this by calling GET /solvers/{problemType}/{solverId}/sub-routines. Here we can observe that there is a subroutine of the problem type 'cluster-vrp'. Similarly, we can see this when checking our problem via GET /problems/vrp/{problemId}. There is a list of 'subProblems' that lists the same subroutine, as well as a list of 'subProblemIds' which represent the concrete problems that were created to solve the VRP clustering problem.

Here we can repeat what we did before and check the VRP clustering problem via GET /problems/cluster-vrp/{subProblemId}. The problem is not configured, so we check our solver options via GET /solvers/cluster-vrp. For this example, we select the Two Phase Clusterer to cluster the VRP problem. Using PATCH /problems/cluster-vrp/{subProblemId} we set the solverId and the state to start solving process on the VRP clustering problem.

After starting the clustering process, we will receive another list of subproblem ids of the various clusters to solve. These are multiple problems, one for each cluster. In our case with the Two Phase Clusterer, we received a list of 6 TSP problems. Each of the problems will need to be configured via the PATCH /problems/tsp/{problemId} request. However, not every TSP problem needs to be configured in the same way. Of the 6 problems, we solve 3 of them directly using the Lkh TSP solver. The other 3 problems are solved via a solver that first transforms the TSP problem to a QUBO problem. Here we use the /problems/qubo/{problemId} request to assign the Qrsip QUBO solver which uses QAOA.

After all 6 TSP problems have been solved, there are no more steps to take and all problems are solved to completion. We end up with solutions for our VRP problem which we can look up via GET /problems/vrp/{problemId}.

Sequence Diagrams

Untitled Diagram drawio Untitled Diagram drawio-1