diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml
index 1d9f992c..3fe05a41 100644
--- a/.github/workflows/documentation.yml
+++ b/.github/workflows/documentation.yml
@@ -14,10 +14,12 @@ jobs:
- uses: julia-actions/setup-julia@latest
with:
version: '1.6'
+ - name: Develop ToQUBO.jl
+ run: julia --project=docs -e 'using Pkg; Pkg.develop(path=pwd())'
- uses: julia-actions/julia-buildpkg@latest
with:
- project: "docs/"
+ project: "docs"
- name: Build and deploy
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # For authentication with GitHub Actions token
- run: julia --project=docs/ docs/make.jl
+ run: julia --project=docs docs/make.jl
diff --git a/CITATION.bib b/CITATION.bib
index 3d2bda4d..3a69a9de 100644
--- a/CITATION.bib
+++ b/CITATION.bib
@@ -1,7 +1,7 @@
% If you use this software, please cite it as below.
@software{toqubo:2023,
author = {Pedro Maciel Xavier and Pedro Ripper and Tiago Andrade and Joaquim Dias Garcia and David E. Bernal Neira},
- title = {ToQUBO.jl},
+ title = {{ToQUBO.jl}},
month = {feb},
year = {2023},
publisher = {Zenodo},
diff --git a/README.md b/README.md
index 87bed716..c6728028 100644
--- a/README.md
+++ b/README.md
@@ -28,10 +28,7 @@ ToQUBO.jl was written as a [MathOptInterface](https://github.com/jump-dev/MathOp
### Installation
ToQUBO is available via Julia's Pkg:
-```julia
-julia> ]add ToQUBO
-```
-or
+
```julia
julia> using Pkg
@@ -53,9 +50,10 @@ model = Model(() -> ToQUBO.Optimizer(ExactSampler.Optimizer))
optimize!(model)
for i = 1:result_count(model)
- xᵢ = value.(x, result = i)
- yᵢ = objective_value(model, result = i)
- println("f($xᵢ) = $yᵢ")
+ xi = value.(x, result = i)
+ yi = objective_value(model, result = i)
+
+ println("f($xi) = $yi")
end
```
@@ -135,15 +133,15 @@ If you think this list is incomplete, consider creating an [Issue](https://githu
## Citing ToQUBO.jl
If you use `ToQUBO.jl` in your work, we kindly ask you to include the following citation:
```tex
-@software{toqubo:2022,
- author = {Pedro Xavier and Tiago Andrade and Joaquim Garcia and David Bernal},
+@software{toqubo:2023,
+ author = {Pedro Maciel Xavier and Pedro Ripper and Tiago Andrade and Joaquim Dias Garcia and David E. Bernal Neira},
title = {{ToQUBO.jl}},
- month = {mar},
- year = {2022},
+ month = {feb},
+ year = {2023},
publisher = {Zenodo},
- version = {v0.1.0},
- doi = {10.5281/zenodo.6387592},
- url = {https://doi.org/10.5281/zenodo.6387592}
+ version = {v0.1.5},
+ doi = {10.5281/zenodo.7644291},
+ url = {https://doi.org/10.5281/zenodo.7644291}
}
```
diff --git a/docs/Project.toml b/docs/Project.toml
index be97a3cb..8b1a1e9f 100644
--- a/docs/Project.toml
+++ b/docs/Project.toml
@@ -4,14 +4,16 @@ DWaveNeal = "870cdf72-5502-4b10-839c-127ceab78f22"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
-MQLib = "16f11440-1623-44c9-850c-358a6c72f3c9"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
-QUBODrivers = "a3f166f7-2cd3-47b6-9e1e-6fbfe0449eb0"
+Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
+PythonPlot = "274fc56d-3b97-40fa-a1cd-1b4a50311bf9"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
+Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
ToQUBO = "9a412ddf-83fa-43b6-9748-7843c851aa65"
[compat]
CSV = "0.10"
+DWaveNeal = "0.4"
DataFrames = "1.3"
Documenter = "0.27"
JuMP = "1"
diff --git a/docs/make.jl b/docs/make.jl
index c9832a7d..101429f1 100644
--- a/docs/make.jl
+++ b/docs/make.jl
@@ -7,24 +7,50 @@ DocMeta.setdocmeta!(
)
makedocs(;
- modules=[ToQUBO],
- doctest=true,
- clean=true,
- format=Documenter.HTML(
- assets = ["assets/extra_styles.css", "assets/favicon.ico"],
- mathengine=Documenter.MathJax2(),
- sidebar_sitename=false,
+ modules = [ToQUBO],
+ doctest = true,
+ clean = true,
+ format = Documenter.HTML(
+ sidebar_sitename = false,
+ mathengine = Documenter.KaTeX(
+ Dict(
+ :macros => Dict(
+ raw"\set" => raw"\left\lbrace{#1}\right\rbrace"
+ )
+ )
+ ),
+ assets = [
+ "assets/extra_styles.css",
+ "assets/favicon.ico",
+ asset("https://tikzjax.com/v1/fonts.css"; class = :css),
+ asset("https://tikzjax.com/v1/tikzjax.js"; class = :js),
+ ],
),
- sitename="ToQUBO.jl",
- authors="Pedro Xavier and Tiago Andrade and Joaquim Garcia and David Bernal",
- pages=[
+ sitename = "ToQUBO.jl",
+ authors = "Pedro Maciel Xavier and Pedro Ripper and Tiago Andrade and Joaquim Dias Garcia and David E. Bernal Neira",
+ pages = [
"Home" => "index.md",
- "Manual" => "manual.md",
+ "Manual" => [
+ "Getting Started" => "manual/1-start.md",
+ "Running a Model" => "manual/2-model.md",
+ "Gathering Results" => "manual/3-results.md",
+ "Compiler Settings" => "manual/4-settings.md",
+ ],
"Examples" => [
- "Knapsack" =>"examples/knapsack.md",
- "Prime Factorization" => "examples/prime_factorization.md",
+ "Knapsack" => "examples/knapsack.md",
+ "Prime Factorization" => "examples/prime_factorization.md",
+ "Portfolio Optimization" => "examples/portfolio_optimization.md",
+ ],
+ "Booklet" => [
+ "Introduction" => "booklet/1-intro.md",
+ "QUBO" => "booklet/2-qubo.md",
+ "PBO" => "booklet/3-pbo.md",
+ "Encoding" => "booklet/4-encoding.md",
+ "Virtual Mapping" => "booklet/5-virtual.md",
+ "The Compiler" => "booklet/6-compiler.md",
+ "Solvers" => "booklet/7-solvers.md",
+ "Appendix" => "booklet/8-appendix.md",
],
- "Booklet" => "booklet.md"
],
workdir="."
)
diff --git a/docs/src/assets/README.md b/docs/src/assets/README.md
deleted file mode 100644
index 900ceebf..00000000
--- a/docs/src/assets/README.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Logo
-
-The ideia behind [ToQUBO](/)'s logo comes from a wordplay in Portuguese and Spanish. The package's main purpose is to assemble QUBO Models, which sounds like *cubo*[¹](#1), the translation for *cube*.
-
-[![ToQUBO.jl](logo.svg)](/docs/src/assets)
-
-## Colors
-
-The colors were chosen according to *Julia's Reference for logo graphics*[²](#2). Text color matches the innermost shape and renders fairly well in both light and dark background themes.
-
-## Typography
-*MADETYPE Sunflower*[³](#3) Font was used. It was converted to a SVG path through the *Google Font to Svg Path*[⁴](#4) online tool.
-
-¹ IPA: \[ˈkubʊ\]
-
-² [github.com/JuliaLang/julia-logo-graphics](https://github.com/JuliaLang/julia-logo-graphics/)
-
-³ [Licensed](/docs/src/assets/fonts/Sunflower%20LICENSE.txt) by the authors for use in this project
-
-⁴ [danmarshall.github.io/google-font-to-svg-path](https://danmarshall.github.io/google-font-to-svg-path/)
-
-# Web Icon [![ToQUBO.jl](favicon.ico)](/docs/src/assets)
-The icon used to decorate the documentation resembles an assembled version of the cube with its blue face making up the background.
\ No newline at end of file
diff --git a/docs/src/assets/extra_styles.css b/docs/src/assets/extra_styles.css
index 760d2ee1..2d249309 100644
--- a/docs/src/assets/extra_styles.css
+++ b/docs/src/assets/extra_styles.css
@@ -1,4 +1,15 @@
.docs-sidebar .docs-logo > img {
max-height: 16rem !important;
margin: auto;
-}
\ No newline at end of file
+}
+
+/* Center images & diagrams */
+p:has(img) {
+ text-align: center;
+ margin: 0 auto;
+}
+
+div.mermaid {
+ text-align: center;
+ margin: 0 auto;
+}
diff --git a/docs/src/assets/figures/quantum-chip.png b/docs/src/assets/figures/quantum-chip.png
new file mode 100644
index 00000000..07629700
Binary files /dev/null and b/docs/src/assets/figures/quantum-chip.png differ
diff --git a/docs/src/assets/fonts/Sunflower LICENSE.txt b/docs/src/assets/fonts/Sunflower-LICENSE.txt
similarity index 100%
rename from docs/src/assets/fonts/Sunflower LICENSE.txt
rename to docs/src/assets/fonts/Sunflower-LICENSE.txt
diff --git a/docs/src/assets/init.js b/docs/src/assets/init.js
new file mode 100644
index 00000000..f3ead049
--- /dev/null
+++ b/docs/src/assets/init.js
@@ -0,0 +1,24 @@
+/* Ref:
+** https://discourse.julialang.org/t/use-javascript-library-with-documenter-jl/34984/8
+*/
+require.config({
+ paths: {
+ mermaid: "https://cdnjs.cloudflare.com/ajax/libs/mermaid/9.4.0/mermaid.min"
+ }
+});
+
+require(['mermaid'], function (mermaid) {
+ mermaid.initialize({
+ startOnLoad : true,
+ theme : 'neutral',
+ // themeVariables: {
+ // primaryColor: '#BB2528',
+ // primaryTextColor: '#fff',
+ // primaryBorderColor: '#7C0000',
+ // lineColor: '#F8B229',
+ // secondaryColor: '#006100',
+ // tertiaryColor: '#aaa',
+ // noteBorderColor: '#ff0',
+ // }
+ })
+});
\ No newline at end of file
diff --git a/docs/src/booklet.md b/docs/src/booklet.md
deleted file mode 100644
index 5eec2071..00000000
--- a/docs/src/booklet.md
+++ /dev/null
@@ -1,121 +0,0 @@
-# ToQUBO.jl Booklet
-This booklet aims to gather the theoretical and practical details behind `ToQUBO` and provide documentation for project internals. The target audience includes, among others, advanced users and those willing to contribute to the project. The latter are advised to read the following sections, as they give a glimpse of the ideas employed up to now.
-
-## QUBO
-```math
-\begin{array}{rl}
- \min & \mathbf{x}^{\intercal} Q\,\mathbf{x} \\
- \text{s.t.} & \mathbf{x} \in \mathbb{B}^{n}
-\end{array}
-```
-
-```@docs
-ToQUBO.isqubo
-ToQUBO.toqubo
-ToQUBO.toqubo!
-```
-
-```@docs
-ToQUBO.toqubo_sense!
-ToQUBO.toqubo_variables!
-ToQUBO.toqubo_constraint
-ToQUBO.toqubo_constraints!
-ToQUBO.toqubo_objective!
-ToQUBO.toqubo_penalties!
-ToQUBO.toqubo_parse!
-ToQUBO.toqubo_build!
-```
-
-## Pseudo-Boolean Optimization
-Internally, problems are represented through a Pseudo-Boolean Optimization (PBO) framework. The main goal is to represent a given problem using a Pseudo-Boolean Function (PBF) since there is an immediate correspondence between quadratic PBFs and QUBO forms.
-
-```@docs
-ToQUBO.PBO.PseudoBooleanFunction
-ToQUBO.PBO.residual
-ToQUBO.PBO.derivative
-ToQUBO.PBO.gradient
-ToQUBO.PBO.gap
-ToQUBO.PBO.sharpness
-ToQUBO.PBO.relaxed_gcd
-```
-
-### A Primer on Submodularity
-A set function ``f : 2^{S} \to \mathbb{R}`` is said to be submodular if
-
-```math
-f(X \cup Y) + f(X \cap Y) \le f(X) + f(Y) \forall X, Y \subset S
-```
-
-holds.
-
-## Quadratization
-In order to successfully achieve a QUBO formulation, sometimes it is needed to quadratize the resulting PBF, i.e., reduce its degree until reaching the quadratic case. There are many quadratization methods available, and `ToQUBO` implements a few of them.
-
-```@docs
-ToQUBO.PBO.quadratize!
-```
-
-## Virtual Mapping
-During reformulation, `ToQUBO` holds two distinct models, namely the *Source Model* and the *Target Model*. The source model is a generic `MOI` model restricted to the supported constraints. The target one is on the QUBO form used during the solving process. Both lie within a *Virtual Model*, which provides the necessary API integration and keeps all variable and constraint mapping tied together.
-
-This is done in a transparent fashion for both agents since the user will mostly interact with the presented model, and the solvers will only access the generated one.
-
-## Virtual Variables
-Every virtual model stores a collection of virtual variables, intended to provide a link between those in the source and those to be created in the target model. Each virtual variable stores enconding information for later expansion and evaluation.
-
-```@docs
-ToQUBO.VirtualVariable
-ToQUBO.encode!
-```
-
-## Variable Encoding
-
-### Linear Encoding Methods
-```@docs
-ToQUBO.LinearEncoding
-ToQUBO.Binary
-ToQUBO.Unary
-ToQUBO.Arithmetic
-ToQUBO.OneHot
-```
-
-### Sequential Encoding Methods
-```@docs
-ToQUBO.SequentialEncoding
-ToQUBO.DomainWall
-```
-
-### Bounded Coefficients
-```@docs
-ToQUBO.Bounded
-```
-
-## Virtual Models
-```@docs
-ToQUBO.VirtualModel
-```
-
-### Annealing & Sampling
-`ToQUBO`'s main goal is to benefit from non-deterministic samplers, especially *Quantum Adiabatic* devices and other *Annealing* machines. A few `MOI`-compliant interfaces for annealers and samplers are bundled within `ToQUBO` via the `Anneal.jl` submodule and package prototype. Some of them are presented below.
-
-### Quantum Annealing
-Interfacing with [D-Wave](https://www.dwavesys.com/)'s quantum computers is one of the milestones we expect to achieve with this package. Like other proprietary optimization resources such as [Gurobi](https://gurobi.com) and [FICO® Xpress](https://www.fico.com/en/products/fico-xpress-solver), this requires licensing and extra steps are needed to get access to it. In a first moment, for those willing to get started, the *Simulated Annealing* optimizer might be enough.
-
-While in `JuMP`, run `using Anneal` and look for `QuantumAnnealer.Optimizer`.
-
-### Simulated Annealing
-Provided by D-Wave's open-source code libraries, this [Simulated Annealing](https://en.wikipedia.org/wiki/Simulated_annealing) engine implements some of the features and configuration you would find using the Quantum API. Its adoption is recommended for basic usage, tests, and during early research steps due to its simplicity and ease of use. It does not implement the most advanced Simulated Annealing algorithm available but performs fairly well on small instances. `Anneal.jl` exports this interface as `SimulatedAnnealer.Optimizer`.
-
-### Random Sampling
-This sampler is implemented for test purposes and simply assigns 0 or 1 to each variable according to a given probability bias ``0 \le p \le 1``, which defaults to ``p = 0.5``. After running the `using Anneal` command, `RandomSampler.Optimizer` will be available.
-
-### Exact Solver (Exaustive Enumeration)
-Also made to be used in tests, the `ExactSolver.Optimizer` interface runs through all possible state configurations, which implies in an exponential time complexity on the number of variables. Thus, only problems with no more than 20 variables should be provided.
-
-## MIQP Solvers
-The most accessible alternative to Annealers and Samplers are Mixed-Integer Quadratic Programming (MIQP) Solvers such as [Gurobi](https://github.com/jump-dev/Gurobi.jl) and [CPLEX](https://github.com/jump-dev/CPLEX.jl). These are not intended to be of regular use alongside `ToQUBO` since reformulation usually makes things harder for these folks. Yet, there are still cases where they may be suitable for tests on small instances.
-
-### Custom Error Types
-```@docs
-ToQUBO.QUBOError
-```
\ No newline at end of file
diff --git a/docs/src/booklet/1-intro.md b/docs/src/booklet/1-intro.md
new file mode 100644
index 00000000..4f15124b
--- /dev/null
+++ b/docs/src/booklet/1-intro.md
@@ -0,0 +1,11 @@
+# ToQUBO.jl Booklet
+
+This booklet aims to gather the theoretical and practical details behind `ToQUBO` and provide documentation for project internals.
+The target audience includes, among others, advanced users and those willing to contribute to the project.
+The latter are advised to read the following sections, as they give a glimpse of the ideas employed up to now.
+
+## Table of Contents
+```@contents
+Pages = ["2-qubo.md", "3-pbo.md", "4-encoding.md", "5-virtual.md", "6-compiler.md", "7-solvers.md", "8-appendix.md"]
+Depth = 2
+```
\ No newline at end of file
diff --git a/docs/src/booklet/2-qubo.md b/docs/src/booklet/2-qubo.md
new file mode 100644
index 00000000..6bec1f28
--- /dev/null
+++ b/docs/src/booklet/2-qubo.md
@@ -0,0 +1,46 @@
+# QUBO
+
+## Definition
+**Q**uadratic **U**nconstrained **B**inary **O**ptimization, as the name suggests, refers to the global minimization or maximization of a quadratic polynomial on binary variables.
+A common presentation, the quadratic matrix form, is written as
+
+```math
+\begin{array}{rl}
+ \min_{\mathbf{x}} & \mathbf{x}' Q\,\mathbf{x} \\
+ \textrm{s.t.} & \mathbf{x} \in \mathbb{B}^{n}
+\end{array}
+```
+
+where ``Q \in \mathbb{R}^{n \times n}`` is symmetric and ``\mathbb{B} = \lbrace{0, 1}\rbrace``.
+Note that, since ``x^{2} = x`` holds for ``x \in \mathbb{B}``, the linear terms of the objective function are stored in the main diagonal of ``Q``.
+
+## OK, but why QUBO?
+Mathematically speaking, there is a notorious equivalence between QUBO and [Max-Cut](https://en.wikipedia.org/wiki/Maximum_cut) problems, e.g. for every QUBO instance there is an information preserving Max-Cut reformulation and vice versa.
+This statement is followed by two immediate implications:
+
+1. In the general case, solving QUBO globally is NP-Hard.
+2. It is a simple yet expressive mathematical programming framework.
+
+Implication 1. tells us that such problems are computationally intractable and that heuristics and metaheuristics are to be employed instead of exact methods.
+No 2. relates to the fact that we are able to represent many other optimization models by means of the QUBO formalism.
+
+The [Ising Model](https://en.wikipedia.org/wiki/Ising_model), on the other hand, is a mathematical abstraction to describe statistical interactions within mechanical systems with interesting properties for encoding combinatorial problems.
+Its _Hamiltonian_ leads to an optimization formulation in terms of the _spin_ values of their states, given by
+
+```math
+\begin{array}{rl}
+ \min_{\mathbf{s}} & \mathbf{h}'\mathbf{s} + \mathbf{s}' J\,\mathbf{s} \\
+ \textrm{s.t.} & \mathbf{s} \in \lbrace{-1,+1}\rbrace^{n}
+\end{array}
+```
+
+with strictly upper triangular ``J \in \mathbb{R}^{n \times n}`` and ``\mathbf{h} \in \mathbb{R}``.
+
+[![D-Wave Washington 1000Q](../assets/figures/quantum-chip.png)](https://commons.wikimedia.org/wiki/File:D-Wave-Washington-1000Q.jpg)
+
+The Ising reformulation alternative draws the bridge between QUBO problems and devices designed to sample global or approximate ground states of the Ising Hamiltonian with high probability[^Mohseni2022].
+Some of the paradigms that stand out in this context are quantum gate-based optimization algorithms (QAOA and VQE), quantum annealers, hardware-accelerated platforms (Coherent Ising Machines and Simulated Bifurcation Machines) and physics-inspired methods (Simulated Annealing, Parallel Tempering).
+The significant advances in these computing systems contributed to the growing popularity of the model across the literature.
+
+[^Mohseni2022]: Mohseni, N., McMahon, P. L. & Byrnes, T. **Ising machines as hardware solvers of combinatorial optimization problems**. _Nat Rev Phys 4_, 363–379 (2022). [{arXiv}](https://arxiv.org/pdf/2204.00276.pdf)
+
\ No newline at end of file
diff --git a/docs/src/booklet/3-pbo.md b/docs/src/booklet/3-pbo.md
new file mode 100644
index 00000000..d7376962
--- /dev/null
+++ b/docs/src/booklet/3-pbo.md
@@ -0,0 +1,54 @@
+# Pseudo-Boolean Optimization
+Internally, problems are represented through a Pseudo-Boolean Optimization (PBO) framework.
+The main goal is to represent a given problem using a Pseudo-Boolean Function (PBF) since there is an immediate correspondence between optimization over quadratic PBFs and the QUBO formalism.
+
+```@docs
+ToQUBO.PBO.PseudoBooleanFunction
+```
+
+## Quadratization
+In order to successfully achieve a QUBO formulation, sometimes it is needed to quadratize the resulting PBF, i.e., reduce its degree until reaching the quadratic case.
+
+A quadratization is a mapping ``\mathcal{Q}: \mathscr{F} \to \mathscr{F}^{2}`` such that
+
+```math
+\forall f \in \mathscr{F}, \forall x \in \{0, 1\}^{n}, \min_{y} \mathcal{Q}\left\lbrace{}f\right\rbrace{}(x; y) = f(x)
+
+```
+
+There are many quadratization methods available[^Dattani2019], and `ToQUBO` implements two of them for now.
+However, using Julia's multiple dispatch paradigm, it's possible to extend the quadratization method coverage with your own algorithms.
+
+```@docs
+ToQUBO.PBO.quadratize!
+```
+
+[^Dattani2019]:
+ Nikesh S. Dattani, **Quadratization in discrete optimization and quantum mechanics**, *ArXiv*, 2019 [{doi}](https://doi.org/10.48550/arXiv.1901.04405)
+
+### Implemented Quadratization Techniques
+
+Currently, `ToQUBO` has two reduction algorithms, one for negative and another for positive terms.
+
+```@docs
+ToQUBO.PBO.NTR_KZFD
+ToQUBO.PBO.PTR_BG
+```
+
+### Stable Quadratization
+
+The quadratization of a PBF does not guarantee that the resulting function will always be the same, as the order of terms can be different each time. This can be an issue in some situations where a deterministic output is required.
+
+With said that, we have introduced the concept of Stable Quadratization, where the terms of the PBF are sorted, guaranteeing that the resulting PBF will be the same every time.
+We have defined it as an attribute of the compiler, with the [`ToQUBO.Attributes.StableQuadratization`](@ref) flag.
+
+
+
+### A Primer on Submodularity
+A set function ``f : 2^{S} \to \mathbb{R}`` is said to be submodular if
+
+```math
+f(X \cup Y) + f(X \cap Y) \le f(X) + f(Y) \forall X, Y \subset S
+```
+
+holds.
diff --git a/docs/src/booklet/4-encoding.md b/docs/src/booklet/4-encoding.md
new file mode 100644
index 00000000..b46d64a8
--- /dev/null
+++ b/docs/src/booklet/4-encoding.md
@@ -0,0 +1,83 @@
+# Encoding Methods
+
+## Variables
+
+As you may already know, QUBO models are comprised only of binary variables.
+So when we are reformulating general optimization problems, one important step is to encode variables into binary ones.
+
+`ToQUBO` currently implements 6 encoding techniques.
+Each method introduces a different number of variables, quadratic terms and linear terms.
+Also, they differ in the magnitude of their coefficients ``\Delta``.
+
+| Encoding | Binary Variables | # Linear terms | # Quadratic terms | ``\Delta`` |
+|:---------------------:|:------------------:|:----------------:|:-------------------:|:----------------:|
+| Binary | ``O(\log n)`` | ``O(\log n)`` | - | ``O(n)`` |
+| Unary | ``O(n)`` | ``O(n)`` | - | ``O(1)`` |
+| One-Hot | ``O(n)`` | ``O(n)`` | ``O(n^2)`` | ``O(n)`` |
+| Domain-Wall | ``O(n)`` | ``O(n)`` | ``O(n)`` | ``O(n)`` |
+| Bounded-Coefficient | ``O(n)`` | ``O(n)`` | - | ``O(1)`` |
+| Arithmetic Prog | ``O(\sqrt{n})`` | ``O(\sqrt{n})`` | - | ``O(\sqrt{n})`` |
+
+### Linear Encoding
+```@docs
+ToQUBO.Unary
+ToQUBO.Binary
+ToQUBO.Arithmetic
+ToQUBO.OneHot
+```
+
+```@docs
+ToQUBO.Mirror
+```
+
+### Sequential Encoding
+```@docs
+ToQUBO.DomainWall
+```
+
+### Bounded Coefficients
+```@docs
+ToQUBO.Bounded
+```
+
+### Encoding Error
+Let ``\set{x_{i}}_{i \in [k]}`` be the collection of ``k`` evenly spaced samples from the discretization of an interval ``[a, b] \subseteq \mathbb{R}``.
+
+The representation error for a given point ``x`` with respect to ``\set{x_{i}}_{i \in [k]}`` is
+
+```math
+e_{k}(x) = \min_{i \in [k]} \left|x - x_{i}\right|
+```
+
+Assuming that ``x`` behaves as a uniformly distributed random variable, the expected absolute encoding error is
+
+```math
+\begin{align*}
+\mathbb{E}\left[{e_{k}(x)}\right] &= \frac{1}{b - a} \int_{a}^{b} e_{k}(x) ~\mathrm{d}x \\
+ &= \frac{1}{4} \frac{b - a}{k - 1}
+\end{align*}
+```
+
+Thus, for encoding methods that rely on the regular division of an interval, it is possible to define the number of samples ``k`` necessary to limit the expected error according to an upper bound ``\tau``, that is,
+
+```math
+\mathbb{E}\left[{e_{k}(x)}\right] \le \tau \implies k \ge 1 + \frac{b - a}{4 \tau}
+```
+
+This allows the compiler to automatically infer the number of bits to allocate for an encoded variable given the tolerance factor.
+
+## Constraints
+
+A QUBO model is unconstrained. So when `ToQUBO` is reformulating a problem, it needs to encode all constraints into the objective function losing as little information as possible.
+
+As constraints are introduced into the objective function, we need to make sure that they won't be violated.
+In order to do that, `ToQUBO` multiplies the encoded constraint by a large penalty ``\rho``, so that any violation would result in a sub-optimal solution to the problem.
+
+Sometimes, the encoding process might introduce higher-order terms, demanding `ToQUBO` to reduce the offending polynomials back to a quadratic form.
+
+As of today, `ToQUBO` provides encoding for the following constraints:
+
+```@docs
+ToQUBO.toqubo_constraint
+```
+
diff --git a/docs/src/booklet/5-virtual.md b/docs/src/booklet/5-virtual.md
new file mode 100644
index 00000000..6ef0b68f
--- /dev/null
+++ b/docs/src/booklet/5-virtual.md
@@ -0,0 +1,29 @@
+# Virtual Mapping
+During reformulation, `ToQUBO` holds two distinct models, namely the *Source Model* and the *Target Model*.
+The source model is a generic `MOI` model restricted to the supported constraints.
+The target one is on the QUBO form used during the solving process.
+Both lie within a *Virtual Model*, which provides the necessary API integration and keeps all variable and constraint mapping tied together.
+
+```@raw html
+
+```
+
+This is done in a transparent fashion for both agents since the user will mostly interact with the presented model, and the solvers will only access the generated one.
+
+## Virtual Model
+```@docs
+ToQUBO.VirtualModel
+```
+
+## Virtual Variables
+Every virtual model stores a collection of virtual variables, intended to provide a link between those in the source and those to be created in the target model.
+Each virtual variable stores encoding information for later expansion and evaluation.
+
+```@docs
+ToQUBO.VirtualVariable
+ToQUBO.encode!
+```
\ No newline at end of file
diff --git a/docs/src/booklet/6-compiler.md b/docs/src/booklet/6-compiler.md
new file mode 100644
index 00000000..2828fd72
--- /dev/null
+++ b/docs/src/booklet/6-compiler.md
@@ -0,0 +1,18 @@
+# The Compiler
+
+!!! warning "Work in progress"
+ We hope to write this part of the documentation soon.
+ Please come back later!
+
+## Compilation Steps
+
+```@docs
+ToQUBO.toqubo_sense!
+ToQUBO.toqubo_variables!
+ToQUBO.toqubo_constraint
+ToQUBO.toqubo_constraints!
+ToQUBO.toqubo_objective!
+ToQUBO.toqubo_penalties!
+ToQUBO.toqubo_parse!
+ToQUBO.toqubo_build!
+```
\ No newline at end of file
diff --git a/docs/src/booklet/7-solvers.md b/docs/src/booklet/7-solvers.md
new file mode 100644
index 00000000..2f504a24
--- /dev/null
+++ b/docs/src/booklet/7-solvers.md
@@ -0,0 +1,29 @@
+# QUBO Solvers
+
+## Solvers, Annealers & Samplers
+[`ToQUBO.jl`](https://github.com/psrenergy/ToQUBO.jl)'s main goal is to make use of parameterized stochastic optimization solvers, particularly those relying on non-conventional hardware such as *Quantum Annealing* and other *Ising Machines*.
+A few `MOI`-compliant interfaces for annealers and samplers are bundled within [`ToQUBO.jl`](https://github.com/psrenergy/ToQUBO.jl) via the [`QUBODrivers.jl`](https://github.com/psrenergy/QUBODrivers.jl) companion package.
+Some of them are presented below.
+
+## Simulated Annealing
+Provided by D-Wave's open-source code libraries, this [Simulated Annealing](https://en.wikipedia.org/wiki/Simulated_annealing) engine implements some of the features and configurations you would find using the Quantum API.
+Its adoption is recommended for basic usage, tests, and research due to its robustness, simplicity and ease of use.
+The [`DWaveNeal.jl`](https://github.com/psrenergy/DWaveNeal.jl) package uses [`QUBODrivers.jl`](https://github.com/psrenergy/QUBODrivers.jl) to deliver an interface to this sampler.
+
+## Quantum Annealing
+Interfacing with [D-Wave](https://www.dwavesys.com/)'s quantum annealer is one of the milestones we expect to achieve with this package.
+Like other proprietary optimization resources such as [Gurobi](https://gurobi.com), [FICO® Xpress](https://www.fico.com/en/products/fico-xpress-solver) and [IBM® CPLEX®](https://www.ibm.com/products/ilog-cplex-optimization-studio/cplex-optimizer), this requires licensing and extra steps are needed to get an access token.
+In a first moment, for those willing to get started, the [`DWaveNeal.jl`](https://github.com/psrenergy/DWaveNeal.jl) optimizer might be enough to learn the ropes.
+
+## Random Sampling
+This sampler is implemented for test purposes and simply assigns 0 or 1 to each variable according to a given probability bias ``0 \le p \le 1``, which defaults to ``p = 0.5``.
+After running the `using QUBODrivers` command, `RandomSampler.Optimizer` will be available.
+
+## Exact Solver (Exhaustive Enumeration)
+Also made to be used in tests, the `ExactSolver.Optimizer` interface runs through all possible state configurations, which implies in an exponential time complexity on the number of variables.
+Thus, only problems with at most ``\approxeq 20`` variables should be provided since visiting ``2^{20} \approxeq 10^{6}`` states can already take up to a few seconds.
+
+## Mixed-Integer Quadratic Programming
+The most accessible alternative to the forementioned methods are Mixed-Integer Quadratic Programming (MIQP) solvers such as [Gurobi](https://github.com/jump-dev/Gurobi.jl), [CPLEX](https://github.com/jump-dev/CPLEX.jl), [SCIP](https://github.com/scipopt/SCIP.jl) and [BARON](https://github.com/jump-dev/BARON.jl).
+These are not intended to be of regular use alongside [`ToQUBO.jl`](https://github.com/psrenergy/ToQUBO.jl) since providing a QUBO reformulation will usually make things harder for non-specialized solvers.
+Yet, there are still a few cases where they may be suitable, such as tests, benchmarks, or any other situation where global optimality is a must.
diff --git a/docs/src/booklet/8-appendix.md b/docs/src/booklet/8-appendix.md
new file mode 100644
index 00000000..c1d5707a
--- /dev/null
+++ b/docs/src/booklet/8-appendix.md
@@ -0,0 +1,35 @@
+# Appendix
+
+## ToQUBO.jl's Assets
+
+### Logo
+
+The ideia behind [ToQUBO.jl](https://github.com/psrenergy/ToQUBO.jl)'s logo comes from a wordplay in Portuguese and Spanish.
+The package's main purpose is to assemble QUBO Models, which sounds like *cubo*[^1], the translation for *cube*.
+
+[![ToQUBO.jl Logo](../assets/logo.svg)]()
+
+### Colors
+
+The colors were picked according to *Julia's Reference for logo graphics*[^2].
+Text color matches the innermost shape and renders fairly well in both light and dark background themes.
+
+### Typography
+
+The *MADETYPE Sunflower*[^3] font was chosen.
+It was converted to a SVG path using the *Google Font to Svg Path*[^4] online tool.
+
+[^1]:
+ IPA: \[ˈkubʊ\]
+
+[^2]:
+ [github.com/JuliaLang/julia-logo-graphics](https://github.com/JuliaLang/julia-logo-graphics/)
+
+[^3]:
+ [Licensed](../../assets/fonts/Sunflower-LICENSE.txt) by the authors for use in this project
+
+[^4]:
+ [danmarshall.github.io/google-font-to-svg-path](https://danmarshall.github.io/google-font-to-svg-path/)
+
+### Web Icon [![ToQUBO.jl Icon](../../assets/favicon.ico)]()
+The icon used to decorate the documentation resembles an assembled version of the cube with its blue face making up the background.
\ No newline at end of file
diff --git a/docs/src/examples/portfolio_optimization.md b/docs/src/examples/portfolio_optimization.md
new file mode 100644
index 00000000..11132a25
--- /dev/null
+++ b/docs/src/examples/portfolio_optimization.md
@@ -0,0 +1,123 @@
+# Portfolio Optimization
+
+In this example, we will be exploring an optimization model for asset distribution where the expected return is maximized while mitigating the financial risk.
+The following approach was inspired by a [JuMP tutorial](https://jump.dev/JuMP.jl/stable/tutorials/nonlinear/portfolio/), where monthly stock prices for three assets are provided, namely `IBM`, `WMT` and `SEHI`.
+
+The modelling presented below aggregates the risk measurement ``\mathbf{x}' \Sigma \mathbf{x}`` as a penalty term to the objective function, thus yielding
+
+```math
+\begin{array}{rll}
+ \max_{\mathbf{x}} & \mathbf{\mu}'\mathbf{x} - \lambda\, \mathbf{x}' \Sigma \mathbf{x} \\
+ \textrm{s.t.} & 0 \le {x}_{i} \le 1 & \forall i \\
+ & \sum_{i} {x}_{i} = 1
+\end{array}
+```
+
+where ``\mu_{i} = \mathbb{E}[r_{i}]`` is the expected return value for each investment ``i``; ``\Sigma`` is the covariance matrix and ``\lambda`` is the risk-aversion penalty factor.
+
+## Stock prices
+```@example portfolio-optimization
+using DataFrames
+using Statistics
+
+assets = [:IBM, :WMT, :SEHI]
+
+df = DataFrames.DataFrame(
+ [
+ 93.043 51.826 1.063
+ 84.585 52.823 0.938
+ 111.453 56.477 1.000
+ 99.525 49.805 0.938
+ 95.819 50.287 1.438
+ 114.708 51.521 1.700
+ 111.515 51.531 2.540
+ 113.211 48.664 2.390
+ 104.942 55.744 3.120
+ 99.827 47.916 2.980
+ 91.607 49.438 1.900
+ 107.937 51.336 1.750
+ 115.590 55.081 1.800
+ ],
+ assets,
+)
+```
+
+## Solving
+```@example portfolio-optimization
+using JuMP
+using ToQUBO
+using DWaveNeal
+
+function solve(
+ config!::Function,
+ df::DataFrame,
+ λ::Float64 = 10.;
+ optimizer = DWaveNeal.Optimizer
+)
+ # Number of assets
+ n = size(df, 2)
+
+ # Relative monthly return
+ r = diff(Matrix(df); dims = 1) ./ Matrix(df[1:end-1, :])
+
+ # Expected monthly return value for each stock
+ μ = vec(Statistics.mean(r; dims = 1))
+
+ # Covariance matrix
+ Σ = Statistics.cov(r)
+
+ # Build model
+ model = Model(() -> ToQUBO.Optimizer(optimizer))
+
+ @variable(model, 0 <= x[1:n] <= 1)
+ @objective(model, Max, μ'x - λ * x' * Σ * x)
+ @constraint(model, sum(x) == 1)
+
+ config!(model)
+
+ optimize!(model)
+
+ return value.(x)
+end
+
+function solve(df::DataFrame, λ::Float64 = 10.; optimizer = DWaveNeal.Optimizer)
+ return solve(identity, df, λ; optimizer)
+end
+```
+
+```@example portfolio-optimization
+solve(df) do model
+ JuMP.set_silent(model)
+ JuMP.set_optimizer_attribute(model, "num_reads", 2_000)
+end
+```
+
+## Penalty Analysis
+To finish our discussion, we are going to sketch some graphics to help our reasoning on how the penalty factor ``\lambda`` affects our investments.
+
+```@example portfolio-optimization
+using Plots; pythonplot()
+
+Λ = collect(0.:5.:50.)
+X = Dict{Symbol,Vector{Float64}}(tag => [] for tag in assets)
+
+for λ = Λ
+ x = solve(df, λ)
+
+ for (i, tag) in enumerate(assets)
+ push!(X[tag], x[i])
+ end
+end
+
+plt = plot(;
+ title="Portfolio Optimization",
+ xlabel=raw"penalty factor ($\lambda$)",
+ ylabel=raw"investment share ($x$)",
+)
+
+for tag in assets
+ plot!(plt, Λ, X[tag]; label=string(tag))
+end
+
+plt
+```
\ No newline at end of file
diff --git a/docs/src/examples/prime_factorization.md b/docs/src/examples/prime_factorization.md
index 86391dce..670cfc84 100644
--- a/docs/src/examples/prime_factorization.md
+++ b/docs/src/examples/prime_factorization.md
@@ -25,7 +25,7 @@ using ToQUBO
using DWaveNeal
function factor(R::Integer; optimizer = DWaveNeal.Optimizer)
- return factor(identity, R; optimizer = optimizer)
+ return factor(identity, R; optimizer)
end
function factor(config!::Function, R::Integer; optimizer = DWaveNeal.Optimizer)
diff --git a/docs/src/index.md b/docs/src/index.md
index e7938866..1dd37f16 100644
--- a/docs/src/index.md
+++ b/docs/src/index.md
@@ -2,7 +2,7 @@
`ToQUBO.jl` is a Julia Package intended to automatically translate models written in [JuMP](https://github.com/jump-dev/JuMP.jl), into the [QUBO](https://en.wikipedia.org/wiki/Quadratic_unconstrained_binary_optimization) mathematical optimization framework.
-## Getting Started
+## Quick Start
### Installation
```julia
@@ -11,40 +11,34 @@ julia> import Pkg
julia> Pkg.add("ToQUBO")
```
-### Running
-```julia
+### Example
+```@example
using JuMP
using ToQUBO
-using Anneal
+using DWaveNeal
-model = Model(() -> ToQUBO.Optimizer(ExactSampler.Optimizer))
+model = Model(() -> ToQUBO.Optimizer(DWaveNeal.Optimizer))
@variable(model, x[1:3], Bin)
-
@objective(model, Max, 1.0*x[1] + 2.0*x[2] + 3.0*x[3])
-
@constraint(model, 0.3*x[1] + 0.5*x[2] + 1.0*x[3] <= 1.6)
optimize!(model)
-for i = 1:result_count(model)
- xᵢ = value.(x, result = i)
- yᵢ = objective_value(model, result = i)
- println("f($xᵢ) = $yᵢ")
-end
+solution_summary(model)
```
## Citing ToQUBO.jl
If you use `ToQUBO.jl` in your work, we kindly ask you to include the following citation:
```tex
-@software{toqubo:2022,
- author = {Pedro Xavier and Tiago Andrade and Joaquim Garcia and David Bernal},
+@software{toqubo:2023,
+ author = {Pedro Maciel Xavier and Pedro Ripper and Tiago Andrade and Joaquim Dias Garcia and David E. Bernal Neira},
title = {{ToQUBO.jl}},
- month = mar,
- year = 2022,
+ month = {feb},
+ year = {2023},
publisher = {Zenodo},
- version = {v0.1.0},
- doi = {10.5281/zenodo.6387592},
- url = {https://doi.org/10.5281/zenodo.6387592}
+ version = {v0.1.5},
+ doi = {10.5281/zenodo.7644291},
+ url = {https://doi.org/10.5281/zenodo.7644291}
}
```
\ No newline at end of file
diff --git a/docs/src/manual.md b/docs/src/manual/1-start.md
similarity index 51%
rename from docs/src/manual.md
rename to docs/src/manual/1-start.md
index bc4c311a..5deae6c3 100644
--- a/docs/src/manual.md
+++ b/docs/src/manual/1-start.md
@@ -19,23 +19,8 @@ optimize!(model)
solution_summary(model)
```
-## Compiler Flags
-
-### Architecture
-```@docs
-ToQUBO.Attributes.Architecture
-```
-
-### Quadratization
-```@docs
-ToQUBO.Attributes.Quadratize
-ToQUBO.Attributes.QuadratizationMethod
-ToQUBO.Attributes.StableQuadratization
-```
-
-### Variable & Constraint Encoding
-```@docs
-ToQUBO.Attributes.VariableEncodingMethod
-ToQUBO.Attributes.VariableEncodingPenalty
-ToQUBO.Attributes.ConstraintEncodingPenalty
+## Table of Contents
+```@contents
+Pages = ["2-model.md", "3-results.md", "4-settings.md"]
+Depth = 2
```
\ No newline at end of file
diff --git a/docs/src/manual/2-model.md b/docs/src/manual/2-model.md
new file mode 100644
index 00000000..41a52791
--- /dev/null
+++ b/docs/src/manual/2-model.md
@@ -0,0 +1,5 @@
+# Running a Model
+
+!!! warning "Work in progress"
+ We hope to write this part of the documentation soon.
+ Please come back later!
\ No newline at end of file
diff --git a/docs/src/manual/3-results.md b/docs/src/manual/3-results.md
new file mode 100644
index 00000000..b3e497d7
--- /dev/null
+++ b/docs/src/manual/3-results.md
@@ -0,0 +1,5 @@
+# Gathering Results
+
+!!! warning "Work in progress"
+ We hope to write this part of the documentation soon.
+ Please come back later!
\ No newline at end of file
diff --git a/docs/src/manual/4-settings.md b/docs/src/manual/4-settings.md
new file mode 100644
index 00000000..65cba01e
--- /dev/null
+++ b/docs/src/manual/4-settings.md
@@ -0,0 +1,35 @@
+# Compiler Settings
+
+## Working with solver architectures
+```@docs
+ToQUBO.Attributes.Architecture
+```
+
+```@docs
+ToQUBO.AbstractArchitecture
+ToQUBO.GenericArchitecture
+```
+
+## Quadratization
+```@docs
+ToQUBO.Attributes.Quadratize
+ToQUBO.Attributes.QuadratizationMethod
+ToQUBO.Attributes.StableQuadratization
+```
+
+## Variable & Constraint Encoding
+```@docs
+ToQUBO.Attributes.VariableEncodingBits
+ToQUBO.Attributes.DefaultVariableEncodingBits
+ToQUBO.Attributes.VariableEncodingATol
+ToQUBO.Attributes.DefaultVariableEncodingATol
+ToQUBO.Attributes.VariableEncodingMethod
+ToQUBO.Attributes.DefaultVariableEncodingMethod
+ToQUBO.Attributes.VariableEncodingPenalty
+ToQUBO.Attributes.ConstraintEncodingPenalty
+```
+
+## Discretization
+```@docs
+ToQUBO.Attributes.Discretize
+```
diff --git a/src/attributes/compiler.jl b/src/attributes/compiler.jl
index b0396078..e7ad3a6a 100644
--- a/src/attributes/compiler.jl
+++ b/src/attributes/compiler.jl
@@ -1,6 +1,15 @@
module Attributes
-import ..ToQUBO
+import ..ToQUBO:
+ ToQUBO,
+ Unary,
+ Binary,
+ Arithmetic,
+ OneHot,
+ DomainWall,
+ Bounded,
+ GenericArchitecture
+
import MathOptInterface as MOI
const MOIU = MOI.Utilities
const VI = MOI.VariableIndex
@@ -26,6 +35,9 @@ export
@doc raw"""
Architecture()
+
+Selects which solver architecture to use.
+Defaults to [`GenericArchitecture`](@ref).
""" struct Architecture <: CompilerAttribute end
function MOI.get(model::ToQUBO.VirtualModel, ::Architecture)::ToQUBO.AbstractArchitecture
@@ -75,7 +87,7 @@ end
QuadratizationMethod()
Defines which quadratization method to use.
-Available options are defined in the [`PBO`](@ref) submodule.
+Available options are defined in the `PBO` submodule.
""" struct QuadratizationMethod <: CompilerAttribute end
function MOI.get(model::ToQUBO.VirtualModel, ::QuadratizationMethod)
@@ -112,6 +124,8 @@ end
@doc raw"""
DefaultVariableEncodingMethod()
+
+Fallback value for [`VariableEncodingMethod`](@ref).
""" struct DefaultVariableEncodingMethod <: CompilerAttribute end
function MOI.get(model::ToQUBO.VirtualModel, ::DefaultVariableEncodingMethod)::ToQUBO.Encoding
@@ -126,6 +140,8 @@ end
@doc raw"""
DefaultVariableEncodingATol()
+
+Fallback value for [`VariableEncodingATol`](@ref).
""" struct DefaultVariableEncodingATol <: CompilerAttribute end
function MOI.get(model::ToQUBO.VirtualModel{T}, ::DefaultVariableEncodingATol)::T where {T}
@@ -293,7 +309,7 @@ end
MOI.is_set_by_optimize(::ConstraintEncodingPenalty) = true
@doc raw"""
- QUBONormalForm
+ QUBONormalForm()
""" struct QUBONormalForm <: CompilerAttribute end
function MOI.get(
diff --git a/src/compiler/architectures.jl b/src/compiler/architectures.jl
index 52c0cefe..d1f1e998 100644
--- a/src/compiler/architectures.jl
+++ b/src/compiler/architectures.jl
@@ -2,7 +2,12 @@
AbstractArchitecture
""" abstract type AbstractArchitecture end
-struct GenericArchitecture <: AbstractArchitecture end
+@doc raw"""
+ GenericArchitecture()
+
+This type is used to reach fallback implementations for [`AbstractArchitecture`](@ref) and, therefore,
+should not have any methods directely related to it.
+""" struct GenericArchitecture <: AbstractArchitecture end
@doc raw"""
""" function infer_architecture end
diff --git a/src/compiler/constraints.jl b/src/compiler/constraints.jl
index e2c435ac..92bf3540 100644
--- a/src/compiler/constraints.jl
+++ b/src/compiler/constraints.jl
@@ -40,20 +40,29 @@ function toqubo_constraint(
end
@doc raw"""
- toqubo_constraint(model::VirtualModel{T}, f::SAF{T}, s::EQ{T}, ::AbstractArchitecture) where {T}
+ toqubo_constraint(
+ model::VirtualModel{T},
+ f::SAF{T},
+ s::EQ{T},
+ ::AbstractArchitecture
+ ) where {T}
Turns constraints of the form
```math
+
\begin{array}{rl}
\text{s.t} & \mathbf{a}'\mathbf{x} - b = 0
\end{array}
+
```
into
```math
-\left\Vertg(\mathbf{x})\right\Vert_{\left\lbrace{0}\right\rbrace} = \left(\mathbf{a}'\mathbf{x} - b\right)^{2}
+
+\left\Vert(\mathbf{x})\right\Vert_{\left\lbrace{0}\right\rbrace} = \left(\mathbf{a}'\mathbf{x} - b\right)^{2}
+
```
"""
function toqubo_constraint(
@@ -81,7 +90,12 @@ function toqubo_constraint(
end
@doc raw"""
- toqubo_constraint(model::VirtualModel{T}, f::SAF{T}, s::LT{T}, ::AbstractArchitecture) where {T}
+ toqubo_constraint(
+ model::VirtualModel{T},
+ f::SAF{T},
+ s::LT{T},
+ ::AbstractArchitecture
+ ) where {T}
Turns constraints of the form
@@ -94,7 +108,8 @@ Turns constraints of the form
into
```math
-\left\Vertg(\mathbf{x})\right\Vert_{\left\lbrace{0}\right\rbrace} = \left(\mathbf{a}'\mathbf{x} - b\right + z)^{2}
+\left\Vert(\mathbf{x})\right\Vert_{\left\lbrace{0}\right\rbrace} = (\mathbf{a}'\mathbf{x} - b + z)^{2}
+
```
by adding a slack variable ``z``.
@@ -131,13 +146,37 @@ function toqubo_constraint(
return g^2
end
+@doc raw"""
+ toqubo_constraint(
+ model::VirtualModel{T},
+ f::SQF{T},
+ s::EQ{T},
+ arch::AbstractArchitecture,
+ ) where {T}
+
+Turns constraints of the form
+
+```math
+\begin{array}{rl}
+\text{s.t} & \mathbf{x}'\mathbf{Q}\mathbf{x} + \mathbf{a}'\mathbf{x} - b = 0
+\end{array}
+```
+
+into
+
+```math
+\left\Vert(\mathbf{x})\right\Vert_{\left\lbrace{0}\right\rbrace} = (\mathbf{x}'\mathbf{Q}\mathbf{x} + \mathbf{a}'\mathbf{x} - b)^{2}
+
+```
+
+"""
function toqubo_constraint(
model::VirtualModel{T},
f::SQF{T},
s::EQ{T},
arch::AbstractArchitecture,
) where {T}
- # Scalar Quadratic Equality Constraint: g(x) = x Q x + a x - b = 0
+ # Scalar Quadratic Equality Constraint: g(x) = x' Q x + a' x - b = 0
g = toqubo_parse(model, f, s, arch)
PBO.discretize!(g)
@@ -158,13 +197,39 @@ function toqubo_constraint(
return g^2
end
+
+@doc raw"""
+ toqubo_constraint(
+ model::VirtualModel{T},
+ f::SQF{T},
+ s::LT{T},
+ arch::AbstractArchitecture,
+ ) where {T}
+
+Turns constraints of the form
+
+```math
+\begin{array}{rl}
+\text{s.t} & \mathbf{x}'\mathbf{Q}\mathbf{x} + \mathbf{a}'\mathbf{x} - b \leq 0
+\end{array}
+```
+
+into
+
+```math
+\left\Vert(\mathbf{x})\right\Vert_{\left\lbrace{0}\right\rbrace} = (\mathbf{x}'\mathbf{Q}\mathbf{x} + \mathbf{a}'\mathbf{x} - b + z)^{2}
+
+```
+
+by adding a slack variable ``z``.
+"""
function toqubo_constraint(
model::VirtualModel{T},
f::SQF{T},
s::LT{T},
arch::AbstractArchitecture,
) where {T}
- # Scalar Quadratic Inequality Constraint: g(x) = x Q x + a x - b ≤ 0
+ # Scalar Quadratic Inequality Constraint: g(x) = x' Q x + a' x - b ≤ 0
g = toqubo_parse(model, f, s, arch)
PBO.discretize!(g)
@@ -193,6 +258,14 @@ function toqubo_constraint(
return g^2
end
+@doc raw"""
+ toqubo_constraint(
+ model::VirtualModel{T},
+ x::MOI.VectorOfVariables,
+ ::MOI.SOS1{T},
+ ::AbstractArchitecture,
+ ) where {T}
+"""
function toqubo_constraint(
model::VirtualModel{T},
x::MOI.VectorOfVariables,
diff --git a/src/compiler/interface.jl b/src/compiler/interface.jl
index 6a1d09df..434fef92 100644
--- a/src/compiler/interface.jl
+++ b/src/compiler/interface.jl
@@ -54,11 +54,12 @@ Copies `MOI.ObjectiveSense` from `model.source_model` to `model.target_model`.
toqubo_constraints!(model::VirtualModel, ::AbstractArchitecture)
""" function toqubo_constraints! end
-@doc raw"""
- toqubo_constraint
+# """
+# toqubo_constraint
-Returns the pseudo-boolean function associated to a given constraint from the source model.
-""" function toqubo_constraint end
+# Returns the pseudo-boolean function associated to a given constraint from the source model.
+# """
+function toqubo_constraint end
@doc raw"""
toqubo_parse!(
@@ -82,6 +83,13 @@ Parses the given MOI function `f` into PBF `g`.
toqubo_build!(model::VirtualModel, ::AbstractArchitecture)
""" function toqubo_build! end
+@doc raw"""
+ toqubo_quadratize!(model::VirtualModel, arch::AbstractArchitecture)
+
+Quadratizes the objective function from a model
+
+""" function toqubo_quadratize! end
+
@doc raw"""
toqubo_empty!(model::VirtualModel, ::AbstractArchitecture)
""" function toqubo_empty! end
\ No newline at end of file
diff --git a/src/lib/pbo/quadratization.jl b/src/lib/pbo/quadratization.jl
index ab14e285..ceae52bd 100644
--- a/src/lib/pbo/quadratization.jl
+++ b/src/lib/pbo/quadratization.jl
@@ -12,7 +12,7 @@ end
@doc raw"""
quadratize!(aux::Function, f::PBF{S, T}, ::Quadratization{Q}) where {S,T,Q}
-Quadratizes a given PBF in-place, i.e. applies a mapping ``Q : \mathscr{F}^{k} \to \mathscr{F}^{2}``.
+Quadratizes a given PBF in-place, i.e. applies a mapping ``\mathcal{Q} : \mathscr{F}^{k} \to \mathscr{F}^{2}``, where ``\mathcal{Q}`` is the quadratization method.
```julia
aux(::Nothing)::S
@@ -23,10 +23,18 @@ aux(::Integer)::Vector{S}
@doc raw"""
Quadratization{NTR_KZFD}(stable::Bool = false)
-NTR-KZFD (Kolmogorov & Zabih, 2004; Freedman & Drineas, 2005)
+Negative Term Reduction NTR-KZFD (Kolmogorov & Zabih, 2004; Freedman & Drineas, 2005)
+
+Let ``f(\mathbf{x}) = x_{1} x_{2} \dots x_{k}``.
+
+```math
+\mathcal{Q}\left\lbrace{f}\right\rbrace(\mathbf{x}; z) = (k - 1) z - \sum_{i = 1}^{k} x_{i} z
+```
+
+where ``\mathbf{x} \in \mathbb{B}^k``
!!! info
- Introduces one new variable and no non-submodular terms.
+ Introduces a new variable ``z`` and no non-submodular terms.
""" struct NTR_KZFD <: QuadratizationMethod end
function quadratize!(
@@ -63,10 +71,19 @@ end
@doc raw"""
Quadratization{PTR_BG}(stable::Bool = false)
-PTR-BG (Boros & Gruber, 2014)
+Positive Term Reduction PTR-BG (Boros & Gruber, 2014)
+
+Let ``f(\mathbf{x}) = x_{1} x_{2} \dots x_{k}``.
+
+```math
+\mathcal{Q}\left\lbrace{f}\right\rbrace(\mathbf{x}; \mathbf{z}) = \left[{
+ \sum_{i = 1}^{k-2} z_{i} \left({ k - i - 1 + x_{i} + \sum_{j = i+1}^{k} x_{j} }\right)
+}\right] + x_{k-1} x_{k}
+```
+where ``\mathbf{x} \in \mathbb{B}^k`` and ``\mathbf{z} \in \mathbb{B}^{k-2}``
!!! info
- Introduces ``k - 2`` new variables and ``k - 1`` non-submodular terms.
+ Introduces ``k - 2`` new variables ``z_{1}, \dots, z_{k-2}`` and ``k - 1`` non-submodular terms.
""" struct PTR_BG <: QuadratizationMethod end
function quadratize!(
@@ -129,6 +146,11 @@ function quadratize!(
return nothing
end
+@doc raw"""
+ quadratize!(aux::Function, f::PBF{S,T}, quad::Quadratization{TERM_BY_TERM}) where {S,T}
+
+ Receives a higher-degree pseudo-Boolean function
+"""
function quadratize!(
aux::Function,
f::PBF{S,T},
@@ -154,6 +176,8 @@ end
@doc raw"""
infer_quadratization(f::PBF)
+
+For a given PBF, returns whether it should be quadratized or not, based on its degree.
"""
function infer_quadratization(f::PBF, stable::Bool = false)
k = degree(f)
diff --git a/src/model/virtual.jl b/src/model/virtual.jl
index 3d938512..beaf999e 100644
--- a/src/model/virtual.jl
+++ b/src/model/virtual.jl
@@ -9,7 +9,8 @@ Maps newly created virtual variable `v` within the virtual model structure. It f
1. Maps `v`'s source to it in the model's `source` mapping.
2. For every one of `v`'s targets, maps it to itself and adds a binary constraint to it.
2. Adds `v` to the end of the model's `varvec`.
-""" function encode! end
+"""
+function encode! end
@doc raw"""
# Variable Expansion methods:
@@ -157,7 +158,8 @@ Every linear encoding ``\xi`` is of the form
\xi(\mathbf{y}) = \alpha + \sum_{i = 1}^{n} \gamma_{i} y_{i}
```
-""" abstract type LinearEncoding <: Encoding end
+"""
+abstract type LinearEncoding <: Encoding end
function VirtualVariable{T}(
e::LinearEncoding,
@@ -188,18 +190,20 @@ function encode!(
end
@doc raw"""
- Mirror
+ Mirror()
Mirrors binary variable ``x \in \mathbb{B}`` with a twin variable ``y \in \mathbb{B}``.
-""" struct Mirror <: LinearEncoding end
+"""
+struct Mirror <: LinearEncoding end
function encode!(model::VirtualModel{T}, e::Mirror, x::Union{VI,Nothing}) where {T}
return encode!(model, e, x, ones(T, 1))
end
@doc raw"""
- Linear
-""" struct Linear <: LinearEncoding end
+ Linear()
+"""
+struct Linear <: LinearEncoding end
function encode!(
model::VirtualModel{T},
@@ -216,12 +220,31 @@ end
@doc raw"""
Unary()
-Let ``x \in [a, b] \subset \mathbb{Z}, n = b - a, \mathbf{y} \in \mathbb{B}^{n}``.
+## Integer
+Let ``x \in [a, b] \subset \mathbb{Z}``, ``n = b - a`` and ``\mathbf{y} \in \mathbb{B}^{n}``.
+
+```math
+\xi{[a, b]}(\mathbf{y}) = a + \sum_{j = 1}^{b - a} y_{j}
+```
+
+## Real
+Given ``n \in \mathbb{N}`` for ``x \in [a, b] \subset \mathbb{R}``,
+
+```math
+\xi{[a, b]}(\mathbf{y}) = a + \frac{b - a}{n} \sum_{j = 1}^{n} y_{j}
+```
+
+### Encoding error
+Given ``\tau > 0``, for the expected encoding error to be less than or equal to ``\tau``, at least
```math
-x \approx \xi(\mathbf{y}) = a + \sum_{j = 1}^{b - a} y_{j}
+n \ge 1 + \frac{b - a}{4 \tau}
```
-""" struct Unary <: LinearEncoding end
+
+binary variables become necessary.
+
+"""
+struct Unary <: LinearEncoding end
function encode!(
model::VirtualModel{T},
@@ -271,18 +294,32 @@ function encode!(
end
@doc raw"""
- Binary
+ Binary()
+
+## Integer
+Let ``x \in [a, b] \subset \mathbb{Z}``, ``n = \left\lceil \log_{2}(b - a) + 1 \right\rceil`` and ``\mathbf{y} \in \mathbb{B}^{n}``.
+
+```math
+\xi{[a, b]}(\mathbf{y}) = a + \left(b - a - 2^{n - 1} + 1\right) y_{n} + \sum_{j = 1}^{n - 1} 2^{j - 1} y_{j}
+```
-Binary Expansion within the closed interval ``[\alpha, \beta]``.
+## Real
+Given ``n \in \mathbb{N}`` for ``x \in [a, b] \subset \mathbb{R}``,
-For a given variable ``x \in [\alpha, \beta]`` we approximate it by
+```math
+\xi{[a, b]}(\mathbf{y}) = a + \frac{b - a}{2^{n} - 1} \sum_{j = 1}^{n} 2^{j - 1} y_{j}
+```
-```math
-x \approx \alpha + \frac{(\beta - \alpha)}{2^{n} - 1} \sum_{i=0}^{n-1} {2^{i}\, y_i}
+### Encoding error
+Given ``\tau > 0``, for the expected encoding error to be less than or equal to ``\tau``, at least
+
+```math
+n \ge \log_{2} \left[1 + \frac{b - a}{4 \tau}\right]
```
-where ``n`` is the number of bits and ``y_i \in \mathbb{B}``.
-""" struct Binary <: LinearEncoding end
+binary variables become necessary.
+"""
+struct Binary <: LinearEncoding end
function encode!(
model::VirtualModel{T},
@@ -338,8 +375,31 @@ function encode!(
end
@doc raw"""
- Arithmetic
-""" struct Arithmetic <: LinearEncoding end
+ Arithmetic()
+
+## Integer
+Let ``x \in [a, b] \subset \mathbb{Z}``, ``n = \left\lceil{ \frac{1}{2} {\sqrt{1 + 8 (b - a)}} - \frac{1}{2} }\right\rceil`` and ``\mathbf{y} \in \mathbb{B}^{n}``.
+
+```math
+\xi{[a, b]}(\mathbf{y}) = a + \left( {b - a - \frac{n (n - 1)}{2}} \right) y_{n} + \sum_{j = 1}^{n - 1} j y_{j}
+```
+
+## Real
+Given ``n \in \mathbb{N}`` for ``x \in [a, b] \subset \mathbb{R}``,
+
+```math
+\xi{[a, b]}(\mathbf{y}) = a + \frac{b - a}{n (n + 1)} \sum_{j = 1}^{n} j y_{j}
+```
+
+### Encoding error
+Given ``\tau > 0``, for the expected encoding error to be less than or equal to ``\tau``, at least
+
+```math
+n \ge \frac{1}{2} \left[ 1 + \sqrt{3 + \frac{(b - a)}{2 \tau})} \right]
+```
+
+"""
+struct Arithmetic <: LinearEncoding end
function encode!(
model::VirtualModel{T},
@@ -393,21 +453,24 @@ end
@doc raw"""
OneHot()
-The one-hot encoding is a linear technique used to represent a variable
-``x \in \left\lbrace{\gamma_{j}}}\right\rbrace_{j \in \left[n\right]``.
+The one-hot encoding is a linear technique used to represent a variable ``x \in \set{\gamma_{j}}_{j \in [n]}``.
-The encoding function is combined with a constraint assuring that only
-one and exactly one of the expansion's variables ``y_{j}`` is activated
-at a time.
+The associated encoding function is combined with a constraint assuring that only one and exactly one of the expansion's variables ``y_{j}`` is activated at a time.
```math
-\begin{array}{rl}
-x = \xi(\mathbf{y}) = & \sum_{j = 1}^{n} \gamma_{j} y_{j} \\
- \mathrm{s.t.} & \sum_{j = 1}^{n} y_{j} = 1
-\end{array}
+\xi[\set{\gamma_{j}}_{j \in [n]}](\mathbf{y}) = \sum_{j = 1}^{n} \gamma_{j} y_{j} ~\textrm{s.t.}~ \sum_{j = 1}^{n} y_{j} = 1
```
-""" struct OneHot <: LinearEncoding end
+When a variable is encoded following this approach, a penalty term of the form
+
+```math
+\rho \left[ \sum_{j = 1}^{n} y_{j} - 1 \right]^{2}
+```
+
+is added to the objective function.
+
+"""
+struct OneHot <: LinearEncoding end
function VirtualVariable{T}(
e::OneHot,
@@ -470,6 +533,17 @@ function encode!(
return encode!(model, e, x, a, b, n)
end
+@doc raw"""
+ SequentialEncoding
+
+A *sequential encoding* is one of the form
+
+```math
+\xi[\set{\gamma_{j}}_{j \in [n]}](\mathbf{y}) = \sum_{j = 1}^{n} \gamma_{j} \left({y_{j + 1} \ast y_{j}}\right)
+```
+
+where ``\mathbf{y} \in \mathbb{B}^{n + 1}`` and ``\ast`` is a binary operator.
+"""
abstract type SequentialEncoding <: Encoding end
function encode!(
@@ -489,17 +563,18 @@ end
@doc raw"""
DomainWall()
-The Domain Wall[^Chancellor2019] encoding method is a sequential approach that requires only
-``n - 1`` bits to represent ``n`` distinct values.
+The Domain Wall[^Chancellor2019] encoding method is a sequential approach that requires ``n - 1`` bits to represent ``n`` distinct values.
+
+```math
+\xi{[\set{\gamma_{j}}_{j \in [n]}]}(\mathbf{y}) = \sum_{j = 1}^{n} \gamma_{j} (y_{j} - y_{j + 1}) ~\textrm{s.t.}~ \sum_{j = 1}^{n} y_{j} \oplus y_{j + 1} = 1, y_{1} = 1, y_{n + 1} = 0
+```
-!!! table "Encoding Analysis"
- | | bits | linear | quadratic | ``\Delta`` |
- | :-: | :--: | :----: | :-------: | :--------: |
- | Domain Wall | ``n - 1`` | ``n`` | | ``O(n)`` |
+where ``\mathbf{y} \in \mathbb{B}^{n + 1}``.
[^Chancellor2019]:
Nicholas Chancellor, **Domain wall encoding of discrete variables for quantum annealing and QAOA**, *Quantum Science Technology 4*, 2019.
-""" struct DomainWall <: SequentialEncoding end
+"""
+struct DomainWall <: SequentialEncoding end
function VirtualVariable{T}(
e::DomainWall,
@@ -551,9 +626,22 @@ function encode!(
end
@doc raw"""
+ Bounded{E,T}(μ::T) where {E<:Encoding,T}
+
+The bounded-coefficient encoding method[^Karimi2019] consists in limiting the magnitude of the coefficients in the encoding expansion to a parameter ``\mu``.
+
+[^Karimi2019]:
+ Karimi, S. & Ronagh, P. **Practical integer-to-binary mapping for quantum annealers**. *Quantum Inf Process 18, 94* (2019). [{doi}](https://doi.org/10.1007/s11128-019-2213-x)
+
+This can be applied to the [`Unary`](@ref), [`Binary`](@ref) and [`Arithmetic`](@ref) encoding schemas, as discussed below.
+
+ Bounded{Unary,T}(μ::T) where {T}
+
+Given ``\mu > 0``, let ``x \in [a, b] \subset \mathbb{Z}`` and ``n = b - a``.
+
Bounded{Binary,T}(μ::T) where {T}
-Let ``x \in [a, b] \subset \mathbb{Z}`` and ``n = b - a``.
+Given ``\mu > 0``, let ``x \in [a, b] \subset \mathbb{Z}`` and ``n = b - a``.
First,
@@ -582,6 +670,15 @@ and
\epsilon = n - 2^{k} + 1 - r \times \mu
```
+Therefore,
+
+```math
+\xi_{\mu}{[a, b]}(\mathbf{y}) = \sum_{j = 1} \gamma_{j} y_{j}
+```
+
+where
+
+```math
\gamma_{j} = \left\lbrace\begin{array}{cl}
2^{j} & \text{if } 1 \le j \le k \\
\mu & \text{if } k < j < r + k \\
@@ -589,10 +686,8 @@ and
\end{array}\right.
```
- Bounded{Unary,T}(μ::T) where {T}
-
-
-""" struct Bounded{E<:LinearEncoding,T} <: LinearEncoding
+"""
+struct Bounded{E<:LinearEncoding,T} <: LinearEncoding
μ::T
function Bounded{E,T}(μ::T) where {E,T}