Documentation
¶
Overview ¶
Package dcsolve implements a solver for linear systems of inequalities of the form x - y ≤ c or x - y < c, with c an integer constant, and z, y are positive, real-valued variables.
Example ¶
This example shows the basic usage of the package: create a new constraint system (DCS), add some variables and some constraints between them, then output a feasible solution.
package main
import (
"fmt"
"github.com/dalzilio/dcsolver"
)
func main() {
// Create a new DCS and add variables x, y and z.
cg := dcsolver.NewDCS()
cg.AddVars("x", "y", "z")
// Each variable can be manipulated using its index. Since every system has
// a reserved, default variable called "start" (with index 0), that stands
// for the initial date, variables x, y, z have index 1, 2 and 3
// respectively.
fmt.Printf("list of variables: %v\n", cg.Names)
// We can add constraints using one of the five supported operations: LTHAN
// (less-than, <), LTEQ (less-tha or equal, ≤), EQ (equal, =), GTHAN
// (greater-than, >), and GTEQ (greater-than or equal, ≥). By default, we
// have the constraint that every variable, say x, is positive: x ≥ 0.
//
// For instance, to add the constraint z - x > 5 and z > y ≥ x (that can be
// encoded as y - z < 0 and x - y ≤ 0):
cg.Add(1, 3, dcsolver.GTHAN, 5)
cg.Add(3, 2, dcsolver.LTHAN, 0)
cg.Add(2, 1, dcsolver.LTEQ, 0)
// The constraint z = 6 can be encoded as z - start = 6:
cg.Add(0, 3, dcsolver.EQ, 6)
// It is possible to print a human-readable representation of the system.
fmt.Print(cg.PrintSystem())
// You can check if the system is satisfiable by looking at the value of
// [cg.SAT]. Since we use an incremental method, we stop updating a DCS as
// soon as it is unsatisfiable. If SAT, you can output one feasible
// solution. A valuation of the form "x: 1⁻" stands for the fact that the
// value of x is of the form 1 ± ε, for ε a small positive value.
fmt.Printf("Feasible solution: %s\n", cg.PrintFeasible())
}
Output: list of variables: [start x y z] 0 ≤ x 0 ≤ y 0 ≤ y - x 6 ≤ z ≤ 6 5 < z - x 0 < z - y Feasible solution: [x: 1⁻, y: 6⁻, z: 6]
Index ¶
- func BCompare(a, b Bound) int
- func Equal(cg1, cg2 CGraph) bool
- type Arc
- type Bound
- type CGraph
- func (cg *CGraph) Add(start int, end int, op Operation, n int) bool
- func (cg *CGraph) AddNVar(n int)
- func (cg *CGraph) AddVars(names ...string) error
- func (cg CGraph) Clone() CGraph
- func (cg *CGraph) CompareVarWith(n int, op Operation, d int) bool
- func (cg *CGraph) ExecZ3() (bool, string)
- func (cg CGraph) PrintFeasible() string
- func (cg CGraph) PrintSMTLIB() string
- func (cg CGraph) PrintSystem() string
- func (cg CGraph) Truncate(n int) CGraph
- func (cg CGraph) Unique() Key
- type Key
- type Operation
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BCompare ¶
BCompare returns an integer comparing two bounds. The result will be 0 if a and b are equal, negative if a < b, and positive otherwise. We return the difference between the bounds values, with some exceptions. We always return +1 when a and b have same values, but a is LTEQ whereas b is LTHAN. For intance, the bound ≤ 3 is considered strictly greater than < 3 with our choice. We return -1 in the symetric cases.
Types ¶
type Arc ¶
Arc is the type of constraints between variables in the DCS, encoding constraints of the form: End - Start ≤ Length.Value. The comparison is strict if the Bound operation is (and reciprocally). The only operation we use in edges are LTHAN (strict inequality) and LTEQ (weak inequality).
type Bound ¶
Bound is the type of bounds in a time interval.
func BSubstract ¶
BSubstract computes the diference, b1 - b2, between two bounds.
func (Bound) PrintLowerBound ¶
PrintLowerBound returns a textual representation of a bound used as a lower bound constraint, such as "4 <" or "5 ≤".
func (Bound) PrintUpperBound ¶
PrintUpperBound is the dual of PrintLowerBound and returns a representation of a bound used as a lower bound constraint.
type CGraph ¶
type CGraph struct {
SAT bool // true if system is satisfiable
Names []string // Name of variables; 0 is for the start variables.
D []Bound // Feasible solution.
Edges map[int][]Arc // Edges[i][j] = c represents the constraint zj - zi ≤ c.
}
CGraph is the type of DCS encoded using directed graph between variables. We check satisifability by looking at the shortest distance between every node. We rely on the fact that the system is satisifable if and only if there are no cycles of negative length. We consider a "virtual" node (src) that is at distance 0 from every vertex and compute the minimal distance from src. Hence, this distance will be a negative integer -d in practice. This value is recorded in the slice D and can be interpreted as a feasible solution that maximize each variable.
func NewDCS ¶
func NewDCS() CGraph
NewDCS returns a new system containing only the (default) start variable and no constraints.
func ReadSMTLIB ¶
ReadSMTLIB parses an input SMT specification incrementally and adds constraints in a DCS. It also keeps an association list between variables names and their index to check that we do not declare the same variable twice. If the strict parameter is true, the function stops as soon as the system is not satisfiable. If false, we parse the entirety of the specification.
func (*CGraph) Add ¶
Add adds a constraint (end - start op n) to the graph, where op is one of {<, <=, =, >=, >}, and returns false if the resulting system is not satisfiable. We assume that start and end are both valid variable indices.
func (*CGraph) AddNVar ¶
AddNVar adds n new variables with names z(i) ... z(i+n), where i is the index of the first fresh variable. We start counting from 1, meaning that the first variable added is z(1), with the convention that z(0) is an alias for the start variable. Like with AddVars, we add the constraint that their values are all positive.
func (*CGraph) AddVars ¶
AddVars adds new (top) variables with the constraint that their value is positive. We assume that the names are different from each other, and different from the variables already defined in [cg.Names].
func (*CGraph) CompareVarWith ¶ added in v0.9.1
CompareVarWith returns true if the system cg is satisifiable after adding the constraint "z(n) op d", but does not modify cg. For instance, when the operation is LTEQ, this function returns true if it is possible for z(n) to be less or equal than d in a feasible solution. We assume that n is a valid variable index.
func (*CGraph) ExecZ3 ¶
ExecZ3 executes the command z3 on a SMT script generated from cg. We assume that z3 is installed locally and can be resolved by exec.LookPath (see documentation for exec.Command). We return true if the system is satisfiable, by a call to "(check-sat)", and false otherwise. When satisifiable, the second returned value is a string representation of the feasible solution, by a call to "(get-model)". Otherwise it is the error message returned by z3.
func (CGraph) PrintFeasible ¶
func (CGraph) PrintSMTLIB ¶
func (CGraph) PrintSystem ¶
func (CGraph) Truncate ¶
Truncate returns a new DCS obtained from cg by deleting every variables except the last n. The remaining variable with the smallest index taking the role of start. We return an empty DCS if n is nul and we return a deep copy of cg if n is larger than the number of variables in cg. Otherwise, the result is a system with exactly n variables.
type Key ¶
Key is a unique identifier for each DCS generated using the unique package from the standard loibrary.
type Operation ¶
type Operation uint8
Operation is the type of possible comparison operators. We only use < and ≤ in our encoding into graph, and when printing a system, but allow the use of the other operators when defining the set of constraints. For instance, we allow equality constraints (that can be expressed as a conjunction of two comparison), but we do not support "distinct" (≠), since it would require a disjunction.
func ReadOperation ¶
ReadOperation parses an operation names and returns the right value. It returns an error if the operator is not one of <, <=, >, >= or =.