Restyle and limit scopes for quicker navigation
This commit is contained in:
@@ -88,7 +88,7 @@ print(right_edge:value()) -- 500
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
In addition to the expression builder there are convenience constructors: `new_pair_ratio_constraint`, `new_pair_constraint`, and `new_single_constraint` to allow efficient construction of the most common simple expression types for GUI layout.
|
In addition to the expression builder there is a convenience constraints submodule with: `pair_ratio`, `pair`, and `single` to allow efficient construction of the most common simple expression types for GUI layout.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
WIP - However the API is fully annotated and will work with lua-language-server. Documentation can also be generated with lua-language-server.
|
WIP - However the API is fully annotated and will work with lua-language-server. Documentation can also be generated with lua-language-server.
|
||||||
|
|||||||
617
kiwi.lua
617
kiwi.lua
@@ -198,7 +198,7 @@ end
|
|||||||
---@param coeff number?
|
---@param coeff number?
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function new_expr_one(constant, var, coeff)
|
local function new_expr_one(constant, var, coeff)
|
||||||
return ffi_gc(new_expr_one_temp(constant, var, coeff), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]] ---@diagnostic disable-line: param-type-mismatch
|
return ffi_gc(new_expr_one_temp(constant, var, coeff), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param constant number
|
---@param constant number
|
||||||
@@ -227,6 +227,7 @@ local REQUIRED = Strength.REQUIRED
|
|||||||
---@param rhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
---@param rhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
||||||
---@param op kiwi.RelOp
|
---@param op kiwi.RelOp
|
||||||
---@param strength? number
|
---@param strength? number
|
||||||
|
---@nodiscard
|
||||||
local function rel(lhs, rhs, op, strength)
|
local function rel(lhs, rhs, op, strength)
|
||||||
local function to_expr(o)
|
local function to_expr(o)
|
||||||
if ffi_istype(Expression, o) then
|
if ffi_istype(Expression, o) then
|
||||||
@@ -264,7 +265,7 @@ end
|
|||||||
---@param lhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
---@param lhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
||||||
---@param rhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
---@param rhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
||||||
---@param strength? number
|
---@param strength? number
|
||||||
---@return kiwi.Constraint
|
---@nodiscard
|
||||||
function kiwi.le(lhs, rhs, strength)
|
function kiwi.le(lhs, rhs, strength)
|
||||||
return rel(lhs, rhs, "LE", strength)
|
return rel(lhs, rhs, "LE", strength)
|
||||||
end
|
end
|
||||||
@@ -273,7 +274,7 @@ end
|
|||||||
---@param lhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
---@param lhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
||||||
---@param rhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
---@param rhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
||||||
---@param strength? number
|
---@param strength? number
|
||||||
---@return kiwi.Constraint
|
---@nodiscard
|
||||||
function kiwi.ge(lhs, rhs, strength)
|
function kiwi.ge(lhs, rhs, strength)
|
||||||
return rel(lhs, rhs, "GE", strength)
|
return rel(lhs, rhs, "GE", strength)
|
||||||
end
|
end
|
||||||
@@ -282,20 +283,21 @@ end
|
|||||||
---@param lhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
---@param lhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
||||||
---@param rhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
---@param rhs kiwi.Expression|kiwi.Term|kiwi.Var|number
|
||||||
---@param strength? number
|
---@param strength? number
|
||||||
---@return kiwi.Constraint
|
---@nodiscard
|
||||||
function kiwi.eq(lhs, rhs, strength)
|
function kiwi.eq(lhs, rhs, strength)
|
||||||
return rel(lhs, rhs, "EQ", strength)
|
return rel(lhs, rhs, "EQ", strength)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Variables are the values the constraint solver calculates.
|
do
|
||||||
---@class kiwi.Var: ffi.ctype*
|
--- Variables are the values the constraint solver calculates.
|
||||||
---@overload fun(name: string): kiwi.Var
|
---@class kiwi.Var: ffi.cdata*
|
||||||
---@operator mul(number): kiwi.Term
|
---@overload fun(name: string): kiwi.Var
|
||||||
---@operator div(number): kiwi.Term
|
---@operator mul(number): kiwi.Term
|
||||||
---@operator unm: kiwi.Term
|
---@operator div(number): kiwi.Term
|
||||||
---@operator add(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
---@operator unm: kiwi.Term
|
||||||
---@operator sub(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
---@operator add(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
||||||
local Var_cls = {
|
---@operator sub(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
||||||
|
local Var_cls = {
|
||||||
le = kiwi.le,
|
le = kiwi.le,
|
||||||
ge = kiwi.ge,
|
ge = kiwi.ge,
|
||||||
eq = kiwi.eq,
|
eq = kiwi.eq,
|
||||||
@@ -311,55 +313,59 @@ local Var_cls = {
|
|||||||
--- Set the value of the variable.
|
--- Set the value of the variable.
|
||||||
---@type fun(self: kiwi.Var, value: number)
|
---@type fun(self: kiwi.Var, value: number)
|
||||||
set = ckiwi.kiwi_var_set_value,
|
set = ckiwi.kiwi_var_set_value,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Get the name of the variable.
|
--- Get the name of the variable.
|
||||||
---@return string
|
---@return string
|
||||||
function Var_cls:name()
|
---@nodiscard
|
||||||
|
function Var_cls:name()
|
||||||
return ffi_string(ckiwi.kiwi_var_name(self))
|
return ffi_string(ckiwi.kiwi_var_name(self))
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a term from this variable.
|
--- Create a term from this variable.
|
||||||
---@param coefficient number?
|
---@param coefficient number?
|
||||||
---@return kiwi.Term
|
---@return kiwi.Term
|
||||||
function Var_cls:toterm(coefficient)
|
---@nodiscard
|
||||||
return Term(self, coefficient or 1.0)
|
function Var_cls:toterm(coefficient)
|
||||||
end
|
return Term(self, coefficient)
|
||||||
|
end
|
||||||
|
|
||||||
--- Create a term from this variable.
|
--- Create a term from this variable.
|
||||||
---@param coefficient number?
|
---@param coefficient number?
|
||||||
---@param constant number?
|
---@param constant number?
|
||||||
---@return kiwi.Expression
|
---@return kiwi.Expression
|
||||||
function Var_cls:toexpr(coefficient, constant)
|
---@nodiscard
|
||||||
|
function Var_cls:toexpr(coefficient, constant)
|
||||||
return new_expr_one(constant or 0.0, self, coefficient)
|
return new_expr_one(constant or 0.0, self, coefficient)
|
||||||
end
|
end
|
||||||
|
|
||||||
ffi.metatype(Var, {
|
local Var_mt = {
|
||||||
__index = Var_cls,
|
__index = Var_cls,
|
||||||
|
}
|
||||||
|
|
||||||
__new = function(_, name)
|
function Var_mt:__new(name)
|
||||||
return ffi_gc(ckiwi.kiwi_var_new(name), ckiwi.kiwi_var_del)
|
return ffi_gc(ckiwi.kiwi_var_new(name), ckiwi.kiwi_var_del)
|
||||||
end,
|
end
|
||||||
|
|
||||||
__mul = function(a, b)
|
function Var_mt.__mul(a, b)
|
||||||
if type(a) == "number" then
|
if type(a) == "number" then
|
||||||
return Term(b, a)
|
return Term(b, a)
|
||||||
elseif type(b) == "number" then
|
elseif type(b) == "number" then
|
||||||
return Term(a, b)
|
return Term(a, b)
|
||||||
end
|
end
|
||||||
error("Invalid var *")
|
error("Invalid var *")
|
||||||
end,
|
end
|
||||||
|
|
||||||
__div = function(a, b)
|
function Var_mt.__div(a, b)
|
||||||
assert(type(b) == "number", "Invalid var /")
|
assert(type(b) == "number", "Invalid var /")
|
||||||
return Term(a, 1.0 / b)
|
return Term(a, 1.0 / b)
|
||||||
end,
|
end
|
||||||
|
|
||||||
__unm = function(var)
|
function Var_mt:__unm()
|
||||||
return Term(var, -1.0)
|
return Term(self, -1.0)
|
||||||
end,
|
end
|
||||||
|
|
||||||
__add = function(a, b)
|
function Var_mt.__add(a, b)
|
||||||
if ffi_istype(Var, b) then
|
if ffi_istype(Var, b) then
|
||||||
if type(a) == "number" then
|
if type(a) == "number" then
|
||||||
return new_expr_one(a, b)
|
return new_expr_one(a, b)
|
||||||
@@ -374,74 +380,77 @@ ffi.metatype(Var, {
|
|||||||
return new_expr_one(b, a)
|
return new_expr_one(b, a)
|
||||||
end
|
end
|
||||||
error("Invalid var +")
|
error("Invalid var +")
|
||||||
end,
|
end
|
||||||
|
|
||||||
__sub = function(a, b)
|
function Var_mt.__sub(a, b)
|
||||||
return a + -b
|
return Var_mt.__add(a, -b)
|
||||||
end,
|
end
|
||||||
|
|
||||||
__tostring = function(var)
|
function Var_mt:__tostring()
|
||||||
return var:name() .. "(" .. var:value() .. ")"
|
return self:name() .. "(" .. self:value() .. ")"
|
||||||
end,
|
end
|
||||||
})
|
|
||||||
|
|
||||||
--- Terms are the components of an expression.
|
ffi.metatype(Var, Var_mt)
|
||||||
--- Each term is a variable multiplied by a constant coefficient (default 1.0).
|
end
|
||||||
---@class kiwi.Term: ffi.ctype*
|
|
||||||
---@overload fun(var: kiwi.Var, coefficient: number?): kiwi.Term
|
do
|
||||||
---@field var kiwi.Var
|
--- Terms are the components of an expression.
|
||||||
---@field coefficient number
|
--- Each term is a variable multiplied by a constant coefficient (default 1.0).
|
||||||
---@operator mul(number): kiwi.Term
|
---@class kiwi.Term: ffi.cdata*
|
||||||
---@operator div(number): kiwi.Term
|
---@overload fun(var: kiwi.Var, coefficient: number?): kiwi.Term
|
||||||
---@operator unm: kiwi.Term
|
---@field var kiwi.Var
|
||||||
---@operator add(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
---@field coefficient number
|
||||||
---@operator sub(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
---@operator mul(number): kiwi.Term
|
||||||
local Term_cls = {
|
---@operator div(number): kiwi.Term
|
||||||
|
---@operator unm: kiwi.Term
|
||||||
|
---@operator add(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
||||||
|
---@operator sub(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
||||||
|
local Term_cls = {
|
||||||
le = kiwi.le,
|
le = kiwi.le,
|
||||||
ge = kiwi.ge,
|
ge = kiwi.ge,
|
||||||
eq = kiwi.eq,
|
eq = kiwi.eq,
|
||||||
}
|
}
|
||||||
|
|
||||||
---@return number
|
---@return number
|
||||||
function Term_cls:value()
|
---@nodiscard
|
||||||
|
function Term_cls:value()
|
||||||
return self.coefficient * self.var:value()
|
return self.coefficient * self.var:value()
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create an expression from this term.
|
--- Create an expression from this term.
|
||||||
---@param constant number?
|
---@param constant number?
|
||||||
---@return kiwi.Expression
|
---@return kiwi.Expression
|
||||||
function Term_cls:toexpr(constant)
|
function Term_cls:toexpr(constant)
|
||||||
return new_expr_one(constant or 0.0, self.var, self.coefficient)
|
return new_expr_one(constant or 0.0, self.var, self.coefficient)
|
||||||
end
|
end
|
||||||
|
|
||||||
ffi.metatype(Term, {
|
local Term_mt = { __index = Term_cls }
|
||||||
__index = Term_cls,
|
|
||||||
|
|
||||||
__new = function(_, var, coefficient)
|
function Term_mt.__new(T, var, coefficient)
|
||||||
return ffi_gc(ffi_new(Term, ckiwi.kiwi_var_clone(var), coefficient or 1.0), function(term)
|
return ffi_gc(ffi_new(T, ckiwi.kiwi_var_clone(var), coefficient or 1.0), function(term)
|
||||||
ckiwi.kiwi_var_del(term.var)
|
ckiwi.kiwi_var_del(term.var)
|
||||||
end)
|
end)
|
||||||
end,
|
end
|
||||||
|
|
||||||
__mul = function(a, b)
|
function Term_mt.__mul(a, b)
|
||||||
if type(b) == "number" then
|
if type(b) == "number" then
|
||||||
return Term(a.var, a.coefficient * b)
|
return Term(a.var, a.coefficient * b)
|
||||||
elseif type(a) == "number" then
|
elseif type(a) == "number" then
|
||||||
return Term(b.var, b.coefficient * a)
|
return Term(b.var, b.coefficient * a)
|
||||||
end
|
end
|
||||||
error("Invalid term *")
|
error("Invalid term *")
|
||||||
end,
|
end
|
||||||
|
|
||||||
__div = function(term, denom)
|
function Term_mt.__div(a, b)
|
||||||
assert(type(denom) == "number", "Invalid term /")
|
assert(type(b) == "number", "Invalid term /")
|
||||||
return Term(term.var, term.coefficient / denom)
|
return Term(a.var, a.coefficient / b)
|
||||||
end,
|
end
|
||||||
|
|
||||||
__unm = function(term)
|
function Term_mt:__unm()
|
||||||
return Term(term.var, -term.coefficient)
|
return Term(self.var, -self.coefficient)
|
||||||
end,
|
end
|
||||||
|
|
||||||
__add = function(a, b)
|
function Term_mt.__add(a, b)
|
||||||
if ffi_istype(Var, b) then
|
if ffi_istype(Var, b) then
|
||||||
return new_expr_pair(0.0, a.var, b, a.coefficient)
|
return new_expr_pair(0.0, a.var, b, a.coefficient)
|
||||||
elseif ffi_istype(Term, b) then
|
elseif ffi_istype(Term, b) then
|
||||||
@@ -456,18 +465,37 @@ ffi.metatype(Term, {
|
|||||||
return new_expr_one(b, a.var, a.coefficient)
|
return new_expr_one(b, a.var, a.coefficient)
|
||||||
end
|
end
|
||||||
error("Invalid term + op")
|
error("Invalid term + op")
|
||||||
end,
|
end
|
||||||
|
|
||||||
__sub = function(a, b)
|
function Term_mt.__sub(a, b)
|
||||||
return a + -b
|
return Term_mt.__add(a, -b)
|
||||||
end,
|
end
|
||||||
|
|
||||||
__tostring = function(term)
|
function Term_mt:__tostring()
|
||||||
return tostring(term.coefficient) .. " " .. term.var:name()
|
return tostring(self.coefficient) .. " " .. self.var:name()
|
||||||
end,
|
end
|
||||||
})
|
|
||||||
|
ffi.metatype(Term, Term_mt)
|
||||||
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
|
--- Expressions are a sum of terms with an added constant.
|
||||||
|
---@class kiwi.Expression: ffi.cdata*
|
||||||
|
---@overload fun(terms: kiwi.Term[], constant: number?): kiwi.Expression
|
||||||
|
---@field constant number
|
||||||
|
---@field package term_count number
|
||||||
|
---@field package terms_ ffi.cdata*
|
||||||
|
---@operator mul(number): kiwi.Expression
|
||||||
|
---@operator div(number): kiwi.Expression
|
||||||
|
---@operator unm: kiwi.Expression
|
||||||
|
---@operator add(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
||||||
|
---@operator sub(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
||||||
|
local Expression_cls = {
|
||||||
|
le = kiwi.le,
|
||||||
|
ge = kiwi.ge,
|
||||||
|
eq = kiwi.eq,
|
||||||
|
}
|
||||||
|
|
||||||
---@param expr kiwi.Expression
|
---@param expr kiwi.Expression
|
||||||
---@param constant number
|
---@param constant number
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
@@ -526,23 +554,6 @@ do
|
|||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Expressions are a sum of terms with an added constant.
|
|
||||||
---@class kiwi.Expression: ffi.ctype*
|
|
||||||
---@overload fun(terms: kiwi.Term[], constant: number?): kiwi.Expression
|
|
||||||
---@field constant number
|
|
||||||
---@field package term_count number
|
|
||||||
---@field package terms_ ffi.cdata*
|
|
||||||
---@operator mul(number): kiwi.Expression
|
|
||||||
---@operator div(number): kiwi.Expression
|
|
||||||
---@operator unm: kiwi.Expression
|
|
||||||
---@operator add(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
|
||||||
---@operator sub(kiwi.Expression|kiwi.Term|kiwi.Var|number): kiwi.Expression
|
|
||||||
local Expression_cls = {
|
|
||||||
le = kiwi.le,
|
|
||||||
ge = kiwi.ge,
|
|
||||||
eq = kiwi.eq,
|
|
||||||
}
|
|
||||||
|
|
||||||
---@return number
|
---@return number
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function Expression_cls:value()
|
function Expression_cls:value()
|
||||||
@@ -570,11 +581,12 @@ do
|
|||||||
return new_expr_constant(self, self.constant)
|
return new_expr_constant(self, self.constant)
|
||||||
end
|
end
|
||||||
|
|
||||||
ffi.metatype(Expression, {
|
local Expression_mt = {
|
||||||
__index = Expression_cls,
|
__index = Expression_cls,
|
||||||
|
}
|
||||||
|
|
||||||
__new = function(_, terms, constant)
|
function Expression_mt.__new(T, terms, constant)
|
||||||
local e = ffi_gc(ffi_new(Expression, #terms), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
local e = ffi_gc(ffi_new(T, #terms), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
for i, t in ipairs(terms) do
|
for i, t in ipairs(terms) do
|
||||||
local dt = e.terms_[i - 1] --[[@as kiwi.Term]]
|
local dt = e.terms_[i - 1] --[[@as kiwi.Term]]
|
||||||
dt.var = ckiwi.kiwi_var_clone(t.var)
|
dt.var = ckiwi.kiwi_var_clone(t.var)
|
||||||
@@ -583,27 +595,27 @@ do
|
|||||||
e.constant = constant or 0.0
|
e.constant = constant or 0.0
|
||||||
e.term_count = #terms
|
e.term_count = #terms
|
||||||
return e
|
return e
|
||||||
end,
|
end
|
||||||
|
|
||||||
__mul = function(a, b)
|
function Expression_mt.__mul(a, b)
|
||||||
if type(a) == "number" then
|
if type(a) == "number" then
|
||||||
return mul_expr_constant(b, a)
|
return mul_expr_constant(b, a)
|
||||||
elseif type(b) == "number" then
|
elseif type(b) == "number" then
|
||||||
return mul_expr_constant(a, b)
|
return mul_expr_constant(a, b)
|
||||||
end
|
end
|
||||||
error("Invalid expr *")
|
error("Invalid expr *")
|
||||||
end,
|
end
|
||||||
|
|
||||||
__div = function(expr, denom)
|
function Expression_mt.__div(a, b)
|
||||||
assert(type(denom) == "number", "Invalid expr /")
|
assert(type(b) == "number", "Invalid expr /")
|
||||||
return mul_expr_constant(expr, 1.0 / denom)
|
return mul_expr_constant(a, 1.0 / b)
|
||||||
end,
|
end
|
||||||
|
|
||||||
__unm = function(expr)
|
function Expression_mt:__unm()
|
||||||
return mul_expr_constant(expr, -1.0)
|
return mul_expr_constant(self, -1.0)
|
||||||
end,
|
end
|
||||||
|
|
||||||
__add = function(a, b)
|
function Expression_mt.__add(a, b)
|
||||||
if ffi_istype(Var, b) then
|
if ffi_istype(Var, b) then
|
||||||
return add_expr_term(a, b)
|
return add_expr_term(a, b)
|
||||||
elseif ffi_istype(Expression, b) then
|
elseif ffi_istype(Expression, b) then
|
||||||
@@ -618,29 +630,31 @@ do
|
|||||||
return new_expr_constant(a, a.constant + b)
|
return new_expr_constant(a, a.constant + b)
|
||||||
end
|
end
|
||||||
error("Invalid expr +")
|
error("Invalid expr +")
|
||||||
end,
|
|
||||||
|
|
||||||
__sub = function(a, b)
|
|
||||||
return a + -b
|
|
||||||
end,
|
|
||||||
|
|
||||||
__tostring = function(expr)
|
|
||||||
local tab = new_tab(expr.term_count + 1, 0)
|
|
||||||
for i = 0, expr.term_count - 1 do
|
|
||||||
tab[i + 1] = tostring(expr.terms_[i])
|
|
||||||
end
|
end
|
||||||
tab[expr.term_count + 1] = expr.constant
|
|
||||||
|
function Expression_mt.__sub(a, b)
|
||||||
|
return Expression_mt.__add(a, -b)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Expression_mt:__tostring()
|
||||||
|
local tab = new_tab(self.term_count + 1, 0)
|
||||||
|
for i = 0, self.term_count - 1 do
|
||||||
|
tab[i + 1] = tostring(self.terms_[i])
|
||||||
|
end
|
||||||
|
tab[self.term_count + 1] = self.constant
|
||||||
return concat(tab, " + ")
|
return concat(tab, " + ")
|
||||||
end,
|
end
|
||||||
})
|
|
||||||
|
ffi.metatype(Expression, Expression_mt)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- A constraint is a linear inequality or equality with associated strength.
|
do
|
||||||
--- Constraints can be built with arbitrary left and right hand expressions. But
|
--- A constraint is a linear inequality or equality with associated strength.
|
||||||
--- ultimately they all have the form `expression [op] 0`.
|
--- Constraints can be built with arbitrary left and right hand expressions. But
|
||||||
---@class kiwi.Constraint: ffi.ctype*
|
--- ultimately they all have the form `expression [op] 0`.
|
||||||
---@overload fun(lhs: kiwi.Expression, rhs: kiwi.Expression?, op: kiwi.RelOp?, strength: number?): kiwi.Constraint
|
---@class kiwi.Constraint: ffi.cdata*
|
||||||
local Constraint_cls = {
|
---@overload fun(lhs: kiwi.Expression, rhs: kiwi.Expression?, op: kiwi.RelOp?, strength: number?): kiwi.Constraint
|
||||||
|
local Constraint_cls = {
|
||||||
--- The strength of the constraint.
|
--- The strength of the constraint.
|
||||||
---@type fun(self: kiwi.Constraint): number
|
---@type fun(self: kiwi.Constraint): number
|
||||||
strength = ckiwi.kiwi_constraint_strength,
|
strength = ckiwi.kiwi_constraint_strength,
|
||||||
@@ -652,12 +666,12 @@ local Constraint_cls = {
|
|||||||
--- Whether the constraint is violated in the current solution.
|
--- Whether the constraint is violated in the current solution.
|
||||||
---@type fun(self: kiwi.Constraint): boolean
|
---@type fun(self: kiwi.Constraint): boolean
|
||||||
violated = ckiwi.kiwi_constraint_violated,
|
violated = ckiwi.kiwi_constraint_violated,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- The reduced expression defining the constraint.
|
--- The reduced expression defining the constraint.
|
||||||
---@return kiwi.Expression
|
---@return kiwi.Expression
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function Constraint_cls:expression()
|
function Constraint_cls:expression()
|
||||||
local SZ = 8
|
local SZ = 8
|
||||||
local expr = ffi_new(Expression, SZ) --[[@as kiwi.Expression]]
|
local expr = ffi_new(Expression, SZ) --[[@as kiwi.Expression]]
|
||||||
local n = ckiwi.kiwi_constraint_expression(self, expr, SZ)
|
local n = ckiwi.kiwi_constraint_expression(self, expr, SZ)
|
||||||
@@ -665,20 +679,52 @@ function Constraint_cls:expression()
|
|||||||
expr = ffi_new(Expression, n) --[[@as kiwi.Expression]]
|
expr = ffi_new(Expression, n) --[[@as kiwi.Expression]]
|
||||||
n = ckiwi.kiwi_constraint_expression(self, expr, n)
|
n = ckiwi.kiwi_constraint_expression(self, expr, n)
|
||||||
end
|
end
|
||||||
return ffi_gc(expr, ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]] ---@diagnostic disable-line: param-type-mismatch
|
return ffi_gc(expr, ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
|
end
|
||||||
|
|
||||||
|
local Constraint_mt = {
|
||||||
|
__index = Constraint_cls,
|
||||||
|
}
|
||||||
|
|
||||||
|
function Constraint_mt:__new(lhs, rhs, op, strength)
|
||||||
|
return ffi_gc(
|
||||||
|
ckiwi.kiwi_constraint_new(lhs, rhs, op or "EQ", strength or REQUIRED),
|
||||||
|
ckiwi.kiwi_constraint_del
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Constraint_mt:__tostring()
|
||||||
|
local ops = { [0] = "<=", ">=", "==" }
|
||||||
|
local strengths = {
|
||||||
|
[Strength.REQUIRED] = "required",
|
||||||
|
[Strength.STRONG] = "strong",
|
||||||
|
[Strength.MEDIUM] = "medium",
|
||||||
|
[Strength.WEAK] = "weak",
|
||||||
|
}
|
||||||
|
local strength = self:strength()
|
||||||
|
local strength_str = strengths[strength] or tostring(strength)
|
||||||
|
local op = ops[tonumber(self:op())]
|
||||||
|
return strformat("%s %s 0 | %s", tostring(self:expression()), op, strength_str)
|
||||||
|
end
|
||||||
|
|
||||||
|
ffi.metatype(Constraint, Constraint_mt)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a constraint between a pair of variables with ratio.
|
do
|
||||||
--- The constraint is of the form `left [op|==] coeff right + [constant|0.0]`.
|
local constraints = {}
|
||||||
---@param left kiwi.Var
|
kiwi.constraints = constraints
|
||||||
---@param coeff number right side term coefficient
|
|
||||||
---@param right kiwi.Var
|
--- Create a constraint between a pair of variables with ratio.
|
||||||
---@param constant number? constant (default 0.0)
|
--- The constraint is of the form `left [op|==] coeff right + [constant|0.0]`.
|
||||||
---@param op kiwi.RelOp? relational operator (default "EQ")
|
---@param left kiwi.Var
|
||||||
---@param strength number? strength (default REQUIRED)
|
---@param coeff number right side term coefficient
|
||||||
---@return kiwi.Constraint
|
---@param right kiwi.Var
|
||||||
---@nodiscard
|
---@param constant number? constant (default 0.0)
|
||||||
function kiwi.new_pair_ratio_constraint(left, coeff, right, constant, op, strength)
|
---@param op kiwi.RelOp? relational operator (default "EQ")
|
||||||
|
---@param strength number? strength (default REQUIRED)
|
||||||
|
---@return kiwi.Constraint
|
||||||
|
---@nodiscard
|
||||||
|
function constraints.pair_ratio(left, coeff, right, constant, op, strength)
|
||||||
assert(ffi_istype(Var, left) and ffi_istype(Var, right))
|
assert(ffi_istype(Var, left) and ffi_istype(Var, right))
|
||||||
local lhs = ffi_new(Expression, 2) --[[@as kiwi.Expression]]
|
local lhs = ffi_new(Expression, 2) --[[@as kiwi.Expression]]
|
||||||
local dt = lhs.terms_[0]
|
local dt = lhs.terms_[0]
|
||||||
@@ -689,86 +735,71 @@ function kiwi.new_pair_ratio_constraint(left, coeff, right, constant, op, streng
|
|||||||
dt.coefficient = -coeff
|
dt.coefficient = -coeff
|
||||||
lhs.constant = -(constant or 0.0)
|
lhs.constant = -(constant or 0.0)
|
||||||
lhs.term_count = 2
|
lhs.term_count = 2
|
||||||
return Constraint(lhs, nil, op, strength)
|
|
||||||
end
|
|
||||||
|
|
||||||
local new_pair_ratio_constraint = kiwi.new_pair_ratio_constraint
|
|
||||||
|
|
||||||
--- Create a constraint between a pair of variables with ratio.
|
|
||||||
--- The constraint is of the form `left [op|==] right + [constant|0.0]`.
|
|
||||||
---@param left kiwi.Var
|
|
||||||
---@param right kiwi.Var
|
|
||||||
---@param constant number? constant (default 0.0)
|
|
||||||
---@param op kiwi.RelOp? relational operator (default "EQ")
|
|
||||||
---@param strength number? strength (default REQUIRED)
|
|
||||||
---@return kiwi.Constraint
|
|
||||||
---@nodiscard
|
|
||||||
function kiwi.new_pair_constraint(left, right, constant, op, strength)
|
|
||||||
return new_pair_ratio_constraint(left, 1.0, right, constant, op, strength)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Create a single term constraint
|
|
||||||
--- The constraint is of the form `var [op|==] [constant|0.0]`.
|
|
||||||
---@param var kiwi.Var
|
|
||||||
---@param constant number? constant (default 0.0)
|
|
||||||
---@param op kiwi.RelOp? relational operator (default "EQ")
|
|
||||||
---@param strength number? strength (default REQUIRED)
|
|
||||||
---@return kiwi.Constraint
|
|
||||||
---@nodiscard
|
|
||||||
function kiwi.new_single_constraint(var, constant, op, strength)
|
|
||||||
assert(ffi_istype(Var, var))
|
|
||||||
local lhs = ffi_new(Expression, 1) --[[@as kiwi.Expression]]
|
|
||||||
local dt = lhs.terms_[0]
|
|
||||||
dt.var = var
|
|
||||||
dt.coefficient = 1.0
|
|
||||||
lhs.constant = -(constant or 0.0)
|
|
||||||
lhs.term_count = 1
|
|
||||||
return Constraint(lhs, nil, op, strength)
|
|
||||||
end
|
|
||||||
|
|
||||||
ffi.metatype(Constraint, {
|
|
||||||
__index = Constraint_cls,
|
|
||||||
|
|
||||||
__new = function(_, lhs, rhs, op, strength)
|
|
||||||
return ffi_gc(
|
return ffi_gc(
|
||||||
ckiwi.kiwi_constraint_new(lhs, rhs, op or "EQ", strength or REQUIRED),
|
ckiwi.kiwi_constraint_new(lhs, nil, op or "EQ", strength or REQUIRED),
|
||||||
ckiwi.kiwi_constraint_del
|
ckiwi.kiwi_constraint_del
|
||||||
)
|
) --[[@as kiwi.Constraint]]
|
||||||
end,
|
end
|
||||||
|
|
||||||
__tostring = function(self)
|
local pair_ratio = constraints.pair_ratio
|
||||||
local ops = {
|
|
||||||
[0] = "<=",
|
|
||||||
">=",
|
|
||||||
"==",
|
|
||||||
}
|
|
||||||
local strengths = {
|
|
||||||
[Strength.REQUIRED] = "required",
|
|
||||||
[Strength.STRONG] = "strong",
|
|
||||||
[Strength.MEDIUM] = "medium",
|
|
||||||
[Strength.WEAK] = "weak",
|
|
||||||
}
|
|
||||||
local strength = self:strength()
|
|
||||||
return strformat(
|
|
||||||
"%s %s 0 | %s",
|
|
||||||
tostring(self:expression()),
|
|
||||||
ops[tonumber(self:op())],
|
|
||||||
strengths[strength] or tostring(strength)
|
|
||||||
)
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
||||||
local Error_mt = {
|
--- Create a constraint between a pair of variables with ratio.
|
||||||
|
--- The constraint is of the form `left [op|==] right + [constant|0.0]`.
|
||||||
|
---@param left kiwi.Var
|
||||||
|
---@param right kiwi.Var
|
||||||
|
---@param constant number? constant (default 0.0)
|
||||||
|
---@param op kiwi.RelOp? relational operator (default "EQ")
|
||||||
|
---@param strength number? strength (default REQUIRED)
|
||||||
|
---@return kiwi.Constraint
|
||||||
|
---@nodiscard
|
||||||
|
function constraints.pair(left, right, constant, op, strength)
|
||||||
|
return pair_ratio(left, 1.0, right, constant, op, strength)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Create a single term constraint
|
||||||
|
--- The constraint is of the form `var [op|==] [constant|0.0]`.
|
||||||
|
---@param var kiwi.Var
|
||||||
|
---@param constant number? constant (default 0.0)
|
||||||
|
---@param op kiwi.RelOp? relational operator (default "EQ")
|
||||||
|
---@param strength number? strength (default REQUIRED)
|
||||||
|
---@return kiwi.Constraint
|
||||||
|
---@nodiscard
|
||||||
|
function constraints.single(var, constant, op, strength)
|
||||||
|
assert(ffi_istype(Var, var))
|
||||||
|
return ffi_gc(
|
||||||
|
ckiwi.kiwi_constraint_new(
|
||||||
|
new_expr_one_temp(-(constant or 0.0), var, 1.0),
|
||||||
|
nil,
|
||||||
|
op or "EQ",
|
||||||
|
strength or REQUIRED
|
||||||
|
),
|
||||||
|
ckiwi.kiwi_constraint_del
|
||||||
|
) --[[@as kiwi.Constraint]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local C = ffi.C
|
||||||
|
|
||||||
|
---@class kiwi.KiwiErr: ffi.cdata*
|
||||||
|
---@field package kind kiwi.ErrKind
|
||||||
|
---@field package message ffi.cdata*
|
||||||
|
---@field package must_free boolean
|
||||||
|
---@overload fun(): kiwi.KiwiErr
|
||||||
|
local KiwiErr = ffi.typeof("struct KiwiErr") --[[@as kiwi.KiwiErr]]
|
||||||
|
|
||||||
|
local Error_mt = {
|
||||||
__tostring = function(self)
|
__tostring = function(self)
|
||||||
return strformat("%s: (%s, %s)", self.message, self.solver, self.item)
|
return strformat("%s: (%s, %s)", self.message, self.solver, self.item)
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
---@param kind kiwi.ErrKind
|
---@param kind kiwi.ErrKind
|
||||||
---@param message string
|
---@param message string
|
||||||
---@param solver kiwi.Solver
|
---@param solver kiwi.Solver
|
||||||
---@param item any
|
---@param item any
|
||||||
local function new_error(kind, message, solver, item)
|
local function new_error(kind, message, solver, item)
|
||||||
---@class kiwi.Error
|
---@class kiwi.Error
|
||||||
---@field kind kiwi.ErrKind
|
---@field kind kiwi.ErrKind
|
||||||
---@field message string
|
---@field message string
|
||||||
@@ -780,21 +811,12 @@ local function new_error(kind, message, solver, item)
|
|||||||
solver = solver,
|
solver = solver,
|
||||||
item = item,
|
item = item,
|
||||||
}, Error_mt)
|
}, Error_mt)
|
||||||
end
|
end
|
||||||
|
|
||||||
local C = ffi.C
|
---@param f fun(solver: kiwi.Solver, item: any, ...): kiwi.KiwiErr?
|
||||||
|
---@param solver kiwi.Solver
|
||||||
---@class kiwi.KiwiErr: ffi.ctype*
|
---@param item any
|
||||||
---@field package kind kiwi.ErrKind
|
local function try_solver(f, solver, item, ...)
|
||||||
---@field package message ffi.cdata*
|
|
||||||
---@field package must_free boolean
|
|
||||||
---@overload fun(): kiwi.KiwiErr
|
|
||||||
local KiwiErr = ffi.typeof("struct KiwiErr") --[[@as kiwi.KiwiErr]]
|
|
||||||
|
|
||||||
---@param f fun(solver: kiwi.Solver, item: any, ...): kiwi.KiwiErr?
|
|
||||||
---@param solver kiwi.Solver
|
|
||||||
---@param item any
|
|
||||||
local function try_solver(f, solver, item, ...)
|
|
||||||
local err = f(solver, item, ...)
|
local err = f(solver, item, ...)
|
||||||
if err ~= nil then
|
if err ~= nil then
|
||||||
local kind = err.kind
|
local kind = err.kind
|
||||||
@@ -804,11 +826,11 @@ local function try_solver(f, solver, item, ...)
|
|||||||
end
|
end
|
||||||
error(new_error(kind, message, solver, item))
|
error(new_error(kind, message, solver, item))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
---@class kiwi.Solver: ffi.ctype*
|
---@class kiwi.Solver: ffi.cdata*
|
||||||
---@overload fun(): kiwi.Solver
|
---@overload fun(): kiwi.Solver
|
||||||
local Solver_cls = {
|
local Solver_cls = {
|
||||||
--- Test whether a constraint is in the solver.
|
--- Test whether a constraint is in the solver.
|
||||||
---@type fun(self: kiwi.Solver, constraint: kiwi.Constraint): boolean
|
---@type fun(self: kiwi.Solver, constraint: kiwi.Constraint): boolean
|
||||||
has_constraint = ckiwi.kiwi_solver_has_constraint,
|
has_constraint = ckiwi.kiwi_solver_has_constraint,
|
||||||
@@ -834,73 +856,74 @@ local Solver_cls = {
|
|||||||
--- Dump a representation of the solver to stdout.
|
--- Dump a representation of the solver to stdout.
|
||||||
---@type fun(self: kiwi.Solver)
|
---@type fun(self: kiwi.Solver)
|
||||||
dump = ckiwi.kiwi_solver_dump,
|
dump = ckiwi.kiwi_solver_dump,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Adds a constraint to the solver.
|
--- Adds a constraint to the solver.
|
||||||
--- Raises
|
--- Raises
|
||||||
--- KiwiErrDuplicateConstraint: The given constraint has already been added to the solver.
|
--- KiwiErrDuplicateConstraint: The given constraint has already been added to the solver.
|
||||||
--- KiwiErrUnsatisfiableConstraint: The given constraint is required and cannot be satisfied.
|
--- KiwiErrUnsatisfiableConstraint: The given constraint is required and cannot be satisfied.
|
||||||
---@param constraint kiwi.Constraint
|
---@param constraint kiwi.Constraint
|
||||||
function Solver_cls:add_constraint(constraint)
|
function Solver_cls:add_constraint(constraint)
|
||||||
try_solver(ckiwi.kiwi_solver_add_constraint, self, constraint)
|
try_solver(ckiwi.kiwi_solver_add_constraint, self, constraint)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes a constraint from the solver.
|
--- Removes a constraint from the solver.
|
||||||
--- Raises
|
--- Raises
|
||||||
--- KiwiErrUnknownConstraint: The given constraint has not been added to the solver.
|
--- KiwiErrUnknownConstraint: The given constraint has not been added to the solver.
|
||||||
---@param constraint kiwi.Constraint
|
---@param constraint kiwi.Constraint
|
||||||
function Solver_cls:remove_constraint(constraint)
|
function Solver_cls:remove_constraint(constraint)
|
||||||
try_solver(ckiwi.kiwi_solver_remove_constraint, self, constraint)
|
try_solver(ckiwi.kiwi_solver_remove_constraint, self, constraint)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Adds an edit variable to the solver.
|
--- Adds an edit variable to the solver.
|
||||||
---
|
---
|
||||||
--- This method should be called before the `suggestValue` method is
|
--- This method should be called before the `suggestValue` method is
|
||||||
--- used to supply a suggested value for the given edit variable.
|
--- used to supply a suggested value for the given edit variable.
|
||||||
--- Raises
|
--- Raises
|
||||||
--- KiwiErrDuplicateEditVariable: The given edit variable has already been added to the solver.
|
--- KiwiErrDuplicateEditVariable: The given edit variable has already been added to the solver.
|
||||||
--- KiwiErrBadRequiredStrength: The given strength is >= required.
|
--- KiwiErrBadRequiredStrength: The given strength is >= required.
|
||||||
---@param var kiwi.Var the variable to add as an edit variable
|
---@param var kiwi.Var the variable to add as an edit variable
|
||||||
---@param strength number the strength of the edit variable (must be less than `Strength.REQUIRED`)
|
---@param strength number the strength of the edit variable (must be less than `Strength.REQUIRED`)
|
||||||
function Solver_cls:add_edit_var(var, strength)
|
function Solver_cls:add_edit_var(var, strength)
|
||||||
try_solver(ckiwi.kiwi_solver_add_edit_var, self, var, strength)
|
try_solver(ckiwi.kiwi_solver_add_edit_var, self, var, strength)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove an edit variable from the solver.
|
--- Remove an edit variable from the solver.
|
||||||
--- Raises
|
--- Raises
|
||||||
--- KiwiErrUnknownEditVariable: The given edit variable has not been added to the solver
|
--- KiwiErrUnknownEditVariable: The given edit variable has not been added to the solver
|
||||||
---@param var kiwi.Var the edit variable to remove
|
---@param var kiwi.Var the edit variable to remove
|
||||||
function Solver_cls:remove_edit_var(var)
|
function Solver_cls:remove_edit_var(var)
|
||||||
try_solver(ckiwi.kiwi_solver_remove_edit_var, self, var)
|
try_solver(ckiwi.kiwi_solver_remove_edit_var, self, var)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Suggest a value for the given edit variable.
|
--- Suggest a value for the given edit variable.
|
||||||
--- This method should be used after an edit variable has been added to the solver in order
|
--- This method should be used after an edit variable has been added to the solver in order
|
||||||
--- to suggest the value for that variable. After all suggestions have been made,
|
--- to suggest the value for that variable. After all suggestions have been made,
|
||||||
--- the `update_vars` methods can be used to update the values of the external solver variables.
|
--- the `update_vars` methods can be used to update the values of the external solver variables.
|
||||||
--- Raises
|
--- Raises
|
||||||
--- KiwiErrUnknownEditVariable: The given edit variable has not been added to the solver.
|
--- KiwiErrUnknownEditVariable: The given edit variable has not been added to the solver.
|
||||||
---@param var kiwi.Var the edit variable to suggest a value for
|
---@param var kiwi.Var the edit variable to suggest a value for
|
||||||
---@param value number the suggested value
|
---@param value number the suggested value
|
||||||
function Solver_cls:suggest_value(var, value)
|
function Solver_cls:suggest_value(var, value)
|
||||||
try_solver(ckiwi.kiwi_solver_suggest_value, self, var, value)
|
try_solver(ckiwi.kiwi_solver_suggest_value, self, var, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Dump a representation of the solver to a string.
|
--- Dump a representation of the solver to a string.
|
||||||
---@return string
|
---@return string
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function Solver_cls:dumps()
|
function Solver_cls:dumps()
|
||||||
local cs = ckiwi.kiwi_solver_dumps(self)
|
local cs = ckiwi.kiwi_solver_dumps(self)
|
||||||
local s = ffi_string(cs)
|
local s = ffi_string(cs)
|
||||||
C.free(cs)
|
C.free(cs)
|
||||||
return s
|
return s
|
||||||
end
|
end
|
||||||
|
|
||||||
kiwi.Solver = ffi.metatype("struct KiwiSolver", {
|
kiwi.Solver = ffi.metatype("struct KiwiSolver", {
|
||||||
__index = Solver_cls,
|
__index = Solver_cls,
|
||||||
__new = function(_)
|
__new = function(_)
|
||||||
return ffi_gc(ckiwi.kiwi_solver_new(), ckiwi.kiwi_solver_del)
|
return ffi_gc(ckiwi.kiwi_solver_new(), ckiwi.kiwi_solver_del)
|
||||||
end,
|
end,
|
||||||
}) --[[@as kiwi.Solver]]
|
}) --[[@as kiwi.Solver]]
|
||||||
|
end
|
||||||
|
|
||||||
return kiwi
|
return kiwi
|
||||||
|
|||||||
Reference in New Issue
Block a user