# Constraint Programming Solver

### The approach
The implementation follows the ideas described in Chapter 12, "Concepts, Techniques, and Models
of Computer Programming" by Peter Van Roy and Seif Haridi.

[An overview of CP implementation in Mozart/Oz.](http://mozart2.org/mozart-v1/doc-1.4.0/fdt/index.html)
### Status

Proof of concept. Not suitable for use in production. Significant API changes and core implementation rewrites are expected.

### Intro

### Implemented constraints

- not_equal
- less_or_equal
- all_different (decomposition to not_equal)
- sum

### Features
- views (linear combinations of variables in constraints)
- solving for satisfaction (CSP) and optimization (COP)
- distributed solving

### Installation
The package can be installed by adding fixpoint to your list of dependencies in mix.exs:

elixir
def deps do
[
{:fixpoint, "~> 0.7.3"}
]
end


### Usage
- [Basic examples](#basic-examples)
- [API](#api)
- [Model specification](#model-specification)
- [Configuring the solver](#solver-options)

- [Examples](#examples)
- [Reindeer Ordering](#reindeer-ordering)
- [SEND+MORE=MONEY](#send_more_money)
- [N-Queens](#n-queens)
- [Sudoku](#sudoku)
- [Graph Coloring](#graph-coloring)
- [Knapsack](#knapsack)

#### Basic examples

***Given two sets of values:***

$x$ $\in$ {1,2}, $y$ $\in$ {0, 1}

***, find all solutions such that*** $x$ $\neq$ $y$

First step is to create a model that describes the problem we want to solve.
The model consists of *variables* and *constraints* over the variables.
In this example, we have 2 variables $x$ and $y$ and a single constraint $x$ $\neq$ $y$

elixir
alias CPSolver.IntVariable
alias CPSolver.Constraint.NotEqual
alias CPSolver.Model
## Variable constructor takes a domain (i.e., set of values), and optional parameters, such as name
x = IntVariable.new([1, 2], name: "x")
y = IntVariable.new([0, 1], name: "y")
## Create NotEqual constraint
neq_constraint =  NotEqual.new(x, y)

Now create a Model instance:
elixir
model = Model.new([x, y], [neq_constraint])

Once we have a model, we pass it to CPSolver.solve/1,2.

We can either solve asynchronously:
elixir
## Asynchronous solving doesn't block
{:ok, solver} = CPSolver.solve(model)
Process.sleep(10)
## We can check for solutions and solver state and/or stats,
## for instance:
## There are 3 solutions: {x = 1, y = 0}, {x = 2,  y = 0}, {x = 2, y = 1}
iex(46)> CPSolver.solutions(solver)
[[1, 0], [2, 0], [2, 1]]

## Solver reports it has found all solutions
iex(47)> CPSolver.status(solver)
:all_solutions

## Some stats
iex(48)> CPSolver.statistics(solver)
%{
elapsed_time: 2472,
solution_count: 3,
active_node_count: 0,
failure_count: 0,
node_count: 5
}


, or use a blocking call:
elixir
iex(49)> {:ok, results} = CPSolver.solve_sync(model)
{:ok,
%{
status: :all_solutions,
statistics: %{
elapsed_time: 3910,
solution_count: 3,
active_node_count: 0,
failure_count: 0,
node_count: 5
},
variables: ["x", "y"],
objective: nil,
solutions: [[2, 1], [1, 0], [2, 0]]
}}


#### API
elixir
#################
# Solving
#################
#
# Asynchronous solving.
# Creates a solver process which runs asynchronously
# and could later be controlled and queried for produced solutions and/or status.
{:ok, solver} = CPSolver.solve(model, solver_opts)

# Synchronous solving.
# Starts the solver and gets the results (solutions and/or solver stats) once the solver finishes.
{:ok, solver_results} = CPSolver.solve_sync(model, solver_opts)


, where
- model - [specification of the model](#model-specification);
- solver_opts (optional) - [solver options](#solver-options).