Packages
fixpoint
0.9.12
0.22.1
0.21.5
0.21.4
0.21.3
0.21.2
0.21.1
0.21.0
0.20.6
0.20.5
0.20.4
0.20.3
0.20.2
0.20.1
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.18.2
0.18.1
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.16.5
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.9
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.13.5
0.13.4
0.13.2
0.13.1
0.12.9
0.12.8
0.12.7
0.12.6
0.12.5
0.12.4
0.12.2
0.12.1
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.10.7
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.46
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.28
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.12
0.5.11
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.1.3
0.1.2
0.1.1
0.1.0
Constraint Programming Solver
Current section
Files
Jump to
Current section
Files
lib/solver/variables/view.ex
defmodule CPSolver.Variable.View do
@moduledoc """
View is a variable with attached `mapper` function.
`mapper` is a bijection of the domain of original variable to the domain of the view
"""
alias CPSolver.Variable
alias CPSolver.DefaultDomain, as: Domain
alias __MODULE__, as: View
defstruct [:mapper, :variable]
@type t :: %__MODULE__{
mapper: function(),
variable: Variable.t()
}
@doc """
Configures (ax + b) view on variable x.
`mapper_fun` maps view values back to the source variable;
returns nil if there is no mapping.
"""
@spec new(Variable.t(), neg_integer() | pos_integer(), integer()) :: View.t()
def new(variable, a, b) when is_struct(variable, Variable) do
%View{variable: variable, mapper: make_mapper_fun(a, b)}
end
def new(%{mapper: mapper} = view, a, b) when is_struct(view, View) do
Map.put(view, :mapper, chained_mapper(a, b, mapper))
end
defp make_mapper_fun(a, b) do
fn
## Given value from variable domain, returns mapped value from view domain
value when is_integer(value) ->
a * value + b
## Given value from view domain, returns mapped value from variable domain,
## or nil, if no mapping exists.
{value, :inverse} when is_integer(value) ->
(rem(value - b, a) == 0 && div(value - b, a)) || nil
## (Used by removeAbove and removeBelow operations)
## Given value from view domain, computes the closest integer value
## implied by mapping function, and the operation to be applied.
{value, :above} when a > 0 ->
{floor((value - b) / a), :removeAbove}
{value, :above} when a < 0 ->
{ceil((value - b) / a), :removeBelow}
{value, :below} when a > 0 ->
{ceil((value - b) / a), :removeBelow}
{value, :below} when a < 0 ->
{floor((value - b) / a), :removeAbove}
## Used by min and max to decide if the operation has to be flipped
:flip? ->
a < 0
:get_params ->
{a, b}
end
end
defp chained_mapper(a, b, mapper)
when is_integer(a) and is_integer(b) and is_function(mapper) do
{current_a, current_b} = mapper.(:get_params)
make_mapper_fun(a * current_a, a * current_b + b)
end
def domain(%{mapper: mapper_fun, variable: variable} = _view) do
Variable.domain(variable)
|> Domain.map(mapper_fun)
end
def size(%{variable: variable} = _view) do
Variable.size(variable)
end
def fixed?(%{variable: variable} = _view) do
Variable.fixed?(variable)
end
def min(%{mapper: mapper_fun, variable: variable} = _view) do
domain_value = (mapper_fun.(:flip?) && Variable.max(variable)) || Variable.min(variable)
mapper_fun.(domain_value)
end
def max(%{mapper: mapper_fun, variable: variable} = _view) do
domain_value = (mapper_fun.(:flip?) && Variable.min(variable)) || Variable.max(variable)
mapper_fun.(domain_value)
end
def contains?(%{mapper: mapper_fun, variable: variable} = _view, value) do
source_value = mapper_fun.({value, :inverse})
source_value && Variable.contains?(variable, source_value)
end
def remove(%{mapper: mapper_fun, variable: variable} = _view, value) do
source_value = mapper_fun.({value, :inverse})
(source_value && Variable.remove(variable, source_value)) || :no_change
end
def fix(%{mapper: mapper_fun, variable: variable} = _view, value) do
source_value = mapper_fun.({value, :inverse})
(source_value && Variable.fix(variable, source_value)) || :fail
end
def removeAbove(%{mapper: mapper_fun, variable: variable} = _view, value) do
{source_value, operation} = mapper_fun.({value, :above})
apply(Variable, operation, [variable, source_value])
end
def removeBelow(%{mapper: mapper_fun, variable: variable} = _view, value) do
{source_value, operation} = mapper_fun.({value, :below})
apply(Variable, operation, [variable, source_value])
end
end
defmodule CPSolver.Variable.View.Factory do
import CPSolver.Variable.View
alias CPSolver.IntVariable
def minus(var) do
mul(var, -1)
end
def mul(var, coefficient) do
linear(var, coefficient, 0)
end
def inc(var, c) when is_integer(c) do
linear(var, 1, c)
end
def linear(_var, 0, offset) do
IntVariable.new(offset)
end
def linear(var, coefficient, offset)
when is_integer(coefficient) and
is_integer(offset) do
new(var, coefficient, offset)
end
def negation(var) do
linear(var, -1, 1)
end
end