Manage GC data better
Make sure that all cdata references for variables is tracked. This is done by attaching finalizers to Expression and Term objects. Some effort is made to avoid creating tracked temporary objects (esp Terms) now.
This commit is contained in:
@@ -10,7 +10,7 @@ using namespace kiwi;
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template<typename T, typename R, typename... Args>
|
template<typename T, typename R, typename... Args>
|
||||||
inline R to_cref(Args&&... args) {
|
inline R make_cref(Args&&... args) {
|
||||||
static_assert(
|
static_assert(
|
||||||
sizeof(R) >= sizeof(T), //NOLINT(bugprone-sizeof-expression)
|
sizeof(R) >= sizeof(T), //NOLINT(bugprone-sizeof-expression)
|
||||||
"to_cref: R too small for T"
|
"to_cref: R too small for T"
|
||||||
@@ -23,13 +23,13 @@ inline R to_cref(Args&&... args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline decltype(auto) to_var_cref(Args&&... args) {
|
inline decltype(auto) make_var_cref(Args&&... args) {
|
||||||
return to_cref<Variable, KiwiVarRef>(std::forward<Args>(args)...);
|
return make_cref<Variable, KiwiVarRef>(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline decltype(auto) to_constraint_cref(Args&&... args) {
|
inline decltype(auto) make_constraint_cref(Args&&... args) {
|
||||||
return to_cref<Constraint, KiwiConstraintRef>(std::forward<Args>(args)...);
|
return make_cref<Constraint, KiwiConstraintRef>(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class R>
|
template<class T, class R>
|
||||||
@@ -45,7 +45,11 @@ class SharedRef {
|
|||||||
"SharedRef<T,CS> CS too small for T"
|
"SharedRef<T,CS> CS too small for T"
|
||||||
);
|
);
|
||||||
|
|
||||||
void destroy() {
|
R clone() const {
|
||||||
|
return make_cref<T, R>(cref());
|
||||||
|
}
|
||||||
|
|
||||||
|
void release() {
|
||||||
if (cref_) {
|
if (cref_) {
|
||||||
ptr()->~T();
|
ptr()->~T();
|
||||||
cref_ = nullptr;
|
cref_ = nullptr;
|
||||||
@@ -201,11 +205,15 @@ inline KiwiErrPtr wrap_err(P ptr, R ref, F&& f) {
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
KiwiVarRef kiwi_var_new(const char* name) {
|
KiwiVarRef kiwi_var_new(const char* name) {
|
||||||
return to_var_cref(name ? name : "");
|
return make_var_cref(name ? name : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_var_del(KiwiVarRef var) {
|
void kiwi_var_del(KiwiVarRef var) {
|
||||||
VariableRef(var).destroy();
|
VariableRef(var).release();
|
||||||
|
}
|
||||||
|
|
||||||
|
KiwiVarRef kiwi_var_clone(KiwiVarRef var) {
|
||||||
|
return VariableRef(var).clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* kiwi_var_name(KiwiVarRef var) {
|
const char* kiwi_var_name(KiwiVarRef var) {
|
||||||
@@ -252,7 +260,7 @@ kiwi_constraint_new(KiwiExpressionConstPtr expression, enum KiwiRelOp op, double
|
|||||||
terms.emplace_back(var.cref(), t->coefficient);
|
terms.emplace_back(var.cref(), t->coefficient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return to_constraint_cref(
|
return make_constraint_cref(
|
||||||
Expression(std::move(terms), expression->constant),
|
Expression(std::move(terms), expression->constant),
|
||||||
static_cast<RelationalOperator>(op),
|
static_cast<RelationalOperator>(op),
|
||||||
strength
|
strength
|
||||||
@@ -260,7 +268,11 @@ kiwi_constraint_new(KiwiExpressionConstPtr expression, enum KiwiRelOp op, double
|
|||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_constraint_del(KiwiConstraintRef constraint) {
|
void kiwi_constraint_del(KiwiConstraintRef constraint) {
|
||||||
ConstraintRef(constraint).destroy();
|
ConstraintRef(constraint).release();
|
||||||
|
}
|
||||||
|
|
||||||
|
KiwiConstraintRef kiwi_constraint_clone(KiwiConstraintRef constraint) {
|
||||||
|
return ConstraintRef(constraint).clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
double kiwi_constraint_strength(KiwiConstraintRef constraint) {
|
double kiwi_constraint_strength(KiwiConstraintRef constraint) {
|
||||||
@@ -290,7 +302,7 @@ int kiwi_constraint_expression(KiwiConstraintRef constraint, KiwiExpression* out
|
|||||||
|
|
||||||
auto* p = out->terms;
|
auto* p = out->terms;
|
||||||
for (const auto& t : terms) {
|
for (const auto& t : terms) {
|
||||||
*p = KiwiTerm {to_var_cref(t.variable()), t.coefficient()};
|
*p = KiwiTerm {make_var_cref(t.variable()), t.coefficient()};
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
out->term_count = p - out->terms;
|
out->term_count = p - out->terms;
|
||||||
|
|||||||
@@ -56,20 +56,18 @@ typedef struct KiwiSolver* KiwiSolverPtr;
|
|||||||
|
|
||||||
KiwiVarRef kiwi_var_new(const char* name);
|
KiwiVarRef kiwi_var_new(const char* name);
|
||||||
void kiwi_var_del(KiwiVarRef var);
|
void kiwi_var_del(KiwiVarRef var);
|
||||||
|
KiwiVarRef kiwi_var_clone(KiwiVarRef var);
|
||||||
|
|
||||||
const char* kiwi_var_name(KiwiVarRef var);
|
const char* kiwi_var_name(KiwiVarRef var);
|
||||||
|
|
||||||
void kiwi_var_set_name(KiwiVarRef var, const char* name);
|
void kiwi_var_set_name(KiwiVarRef var, const char* name);
|
||||||
|
|
||||||
double kiwi_var_value(KiwiVarRef var);
|
double kiwi_var_value(KiwiVarRef var);
|
||||||
|
|
||||||
void kiwi_var_set_value(KiwiVarRef var, double value);
|
void kiwi_var_set_value(KiwiVarRef var, double value);
|
||||||
|
|
||||||
int kiwi_var_eq(KiwiVarRef var, KiwiVarRef other);
|
int kiwi_var_eq(KiwiVarRef var, KiwiVarRef other);
|
||||||
|
|
||||||
KiwiConstraintRef
|
KiwiConstraintRef
|
||||||
kiwi_constraint_new(KiwiExpressionConstPtr expression, enum KiwiRelOp op, double strength);
|
kiwi_constraint_new(KiwiExpressionConstPtr expression, enum KiwiRelOp op, double strength);
|
||||||
void kiwi_constraint_del(KiwiConstraintRef constraint);
|
void kiwi_constraint_del(KiwiConstraintRef constraint);
|
||||||
|
KiwiConstraintRef kiwi_constraint_clone(KiwiConstraintRef constraint);
|
||||||
|
|
||||||
double kiwi_constraint_strength(KiwiConstraintRef constraint);
|
double kiwi_constraint_strength(KiwiConstraintRef constraint);
|
||||||
|
|
||||||
|
|||||||
181
kiwi.lua
181
kiwi.lua
@@ -58,15 +58,12 @@ typedef struct KiwiSolver* KiwiSolverPtr;
|
|||||||
|
|
||||||
KiwiVarRef kiwi_var_new(const char* name);
|
KiwiVarRef kiwi_var_new(const char* name);
|
||||||
void kiwi_var_del(KiwiVarRef var);
|
void kiwi_var_del(KiwiVarRef var);
|
||||||
|
KiwiVarRef kiwi_var_clone(KiwiVarRef var);
|
||||||
|
|
||||||
const char* kiwi_var_name(KiwiVarRef var);
|
const char* kiwi_var_name(KiwiVarRef var);
|
||||||
|
|
||||||
void kiwi_var_set_name(KiwiVarRef var, const char* name);
|
void kiwi_var_set_name(KiwiVarRef var, const char* name);
|
||||||
|
|
||||||
double kiwi_var_value(KiwiVarRef var);
|
double kiwi_var_value(KiwiVarRef var);
|
||||||
|
|
||||||
void kiwi_var_set_value(KiwiVarRef var, double value);
|
void kiwi_var_set_value(KiwiVarRef var, double value);
|
||||||
|
|
||||||
int kiwi_var_eq(KiwiVarRef var, KiwiVarRef other);
|
int kiwi_var_eq(KiwiVarRef var, KiwiVarRef other);
|
||||||
|
|
||||||
KiwiConstraintRef
|
KiwiConstraintRef
|
||||||
@@ -99,8 +96,8 @@ void free(void *);
|
|||||||
]])
|
]])
|
||||||
|
|
||||||
local strformat = string.format
|
local strformat = string.format
|
||||||
local ffi_cast, ffi_copy, ffi_gc, ffi_istype, ffi_new, ffi_string =
|
local ffi_cast, ffi_gc, ffi_istype, ffi_new, ffi_string =
|
||||||
ffi.cast, ffi.copy, ffi.gc, ffi.istype, ffi.new, ffi.string
|
ffi.cast, ffi.gc, ffi.istype, ffi.new, ffi.string
|
||||||
|
|
||||||
local concat = table.concat
|
local concat = table.concat
|
||||||
local has_table_new, new_tab = pcall(require, "table.new")
|
local has_table_new, new_tab = pcall(require, "table.new")
|
||||||
@@ -164,9 +161,6 @@ kiwi.Expression = Expression
|
|||||||
local Constraint = ffi.typeof("struct KiwiConstraintRefType") --[[@as kiwi.Constraint]]
|
local Constraint = ffi.typeof("struct KiwiConstraintRefType") --[[@as kiwi.Constraint]]
|
||||||
kiwi.Constraint = Constraint
|
kiwi.Constraint = Constraint
|
||||||
|
|
||||||
-- JIT compiler NYI: bad argument type if ffi.sizeof is used with a structure member
|
|
||||||
local SIZEOF_TERM = ffi.sizeof(Term)
|
|
||||||
|
|
||||||
--- Define a constraint with expressions as `a <= b`.
|
--- Define a constraint with expressions as `a <= b`.
|
||||||
---@param a kiwi.Expression|kiwi.Term|kiwi.Var|number
|
---@param a kiwi.Expression|kiwi.Term|kiwi.Var|number
|
||||||
---@param b kiwi.Expression|kiwi.Term|kiwi.Var|number
|
---@param b kiwi.Expression|kiwi.Term|kiwi.Var|number
|
||||||
@@ -194,39 +188,63 @@ function kiwi.eq(a, b, strength)
|
|||||||
return Constraint(a - b, "EQ", strength)
|
return Constraint(a - b, "EQ", strength)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function expr_gc(expr)
|
||||||
|
local terms_ = expr.terms_
|
||||||
|
for i = 0, expr.term_count - 1 do
|
||||||
|
ckiwi.kiwi_var_del(terms_[i].var)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
---@param expr kiwi.Expression
|
---@param expr kiwi.Expression
|
||||||
---@param term kiwi.Term
|
---@param var kiwi.Var
|
||||||
|
---@param coeff number?
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function add_expr_term(expr, term)
|
local function add_expr_term(expr, var, coeff)
|
||||||
local ret = ffi_new(Expression, expr.term_count + 1) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, expr.term_count + 1), expr_gc) --[[@as kiwi.Expression]]
|
||||||
|
for i = 0, expr.term_count - 1 do
|
||||||
|
local st = expr.terms_[i] --[[@as kiwi.Term]]
|
||||||
|
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
||||||
|
dt.var = ckiwi.kiwi_var_clone(st.var)
|
||||||
|
dt.coefficient = st.coefficient
|
||||||
|
end
|
||||||
|
local dt = ret.terms_[expr.term_count]
|
||||||
|
dt.var = ckiwi.kiwi_var_clone(var)
|
||||||
|
dt.coefficient = coeff or 1.0
|
||||||
ret.constant = expr.constant
|
ret.constant = expr.constant
|
||||||
ret.term_count = expr.term_count + 1
|
ret.term_count = expr.term_count + 1
|
||||||
ffi_copy(ret.terms_, expr.terms_, SIZEOF_TERM * expr.term_count) ---@diagnostic disable-line: param-type-mismatch
|
|
||||||
ret.terms_[expr.term_count] = term
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param constant number
|
---@param constant number
|
||||||
---@param term kiwi.Term
|
---@param var kiwi.Var
|
||||||
|
---@param coeff number?
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function new_expr_one(constant, term)
|
local function new_expr_one(constant, var, coeff)
|
||||||
local ret = ffi_new(Expression, 1) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, 1), expr_gc) --[[@as kiwi.Expression]]
|
||||||
|
local dt = ret.terms_[0]
|
||||||
|
dt.var = ckiwi.kiwi_var_clone(var)
|
||||||
|
dt.coefficient = coeff or 1.0
|
||||||
ret.constant = constant
|
ret.constant = constant
|
||||||
ret.term_count = 1
|
ret.term_count = 1
|
||||||
ret.terms_[0] = term
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param constant number
|
---@param constant number
|
||||||
---@param term1 kiwi.Term
|
---@param var1 kiwi.Var
|
||||||
---@param term2 kiwi.Term
|
---@param var2 kiwi.Var
|
||||||
|
---@param coeff1 number?
|
||||||
|
---@param coeff2 number?
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function new_expr_pair(constant, term1, term2)
|
local function new_expr_pair(constant, var1, var2, coeff1, coeff2)
|
||||||
local ret = ffi_new(Expression, 2) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, 2), expr_gc) --[[@as kiwi.Expression]]
|
||||||
|
local dt = ret.terms_[0]
|
||||||
|
dt.var = ckiwi.kiwi_var_clone(var1)
|
||||||
|
dt.coefficient = coeff1 or 1.0
|
||||||
|
dt = ret.terms_[1]
|
||||||
|
dt.var = ckiwi.kiwi_var_clone(var2)
|
||||||
|
dt.coefficient = coeff2 or 1.0
|
||||||
ret.constant = constant
|
ret.constant = constant
|
||||||
ret.term_count = 2
|
ret.term_count = 2
|
||||||
ret.terms_[0] = term1
|
|
||||||
ret.terms_[1] = term2
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -275,6 +293,7 @@ ffi.metatype(Var, {
|
|||||||
__new = function(_, name)
|
__new = function(_, 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,
|
||||||
|
__gc = ckiwi.kiwi_var_del,
|
||||||
|
|
||||||
__mul = function(a, b)
|
__mul = function(a, b)
|
||||||
if type(a) == "number" then
|
if type(a) == "number" then
|
||||||
@@ -296,18 +315,17 @@ ffi.metatype(Var, {
|
|||||||
|
|
||||||
__add = function(a, b)
|
__add = function(a, b)
|
||||||
if ffi_istype(Var, b) then
|
if ffi_istype(Var, b) then
|
||||||
local bt = Term(b)
|
|
||||||
if type(a) == "number" then
|
if type(a) == "number" then
|
||||||
return new_expr_one(a, bt)
|
return new_expr_one(a, b)
|
||||||
else
|
else
|
||||||
return new_expr_pair(0.0, Term(a), bt)
|
return new_expr_pair(0.0, a, b)
|
||||||
end
|
end
|
||||||
elseif ffi_istype(Term, b) then
|
elseif ffi_istype(Term, b) then
|
||||||
return new_expr_pair(0.0, b, Term(a))
|
return new_expr_pair(0.0, b.var, a, b.coefficient)
|
||||||
elseif ffi_istype(Expression, b) then
|
elseif ffi_istype(Expression, b) then
|
||||||
return add_expr_term(b, Term(a))
|
return add_expr_term(b, a)
|
||||||
elseif type(b) == "number" then
|
elseif type(b) == "number" then
|
||||||
return new_expr_one(b, Term(a))
|
return new_expr_one(b, a)
|
||||||
end
|
end
|
||||||
error("Invalid var +")
|
error("Invalid var +")
|
||||||
end,
|
end,
|
||||||
@@ -325,8 +343,8 @@ ffi.metatype(Var, {
|
|||||||
--- Each term is a variable multiplied by a constant coefficient (default 1.0).
|
--- Each term is a variable multiplied by a constant coefficient (default 1.0).
|
||||||
---@class kiwi.Term: ffi.ctype*
|
---@class kiwi.Term: ffi.ctype*
|
||||||
---@overload fun(var: kiwi.Var, coefficient: number?): kiwi.Term
|
---@overload fun(var: kiwi.Var, coefficient: number?): kiwi.Term
|
||||||
---@field coefficient number
|
|
||||||
---@field var kiwi.Var
|
---@field var kiwi.Var
|
||||||
|
---@field coefficient number
|
||||||
---@operator mul(number): kiwi.Term
|
---@operator mul(number): kiwi.Term
|
||||||
---@operator div(number): kiwi.Term
|
---@operator div(number): kiwi.Term
|
||||||
---@operator unm: kiwi.Term
|
---@operator unm: kiwi.Term
|
||||||
@@ -347,14 +365,16 @@ end
|
|||||||
---@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)
|
return new_expr_one(constant or 0.0, self.var, self.coefficient)
|
||||||
end
|
end
|
||||||
|
|
||||||
ffi.metatype(Term, {
|
ffi.metatype(Term, {
|
||||||
__index = Term_cls,
|
__index = Term_cls,
|
||||||
|
|
||||||
__new = function(_, var, coefficient)
|
__new = function(_, var, coefficient)
|
||||||
return ffi_new(Term, var, coefficient or 1.0)
|
return ffi_gc(ffi_new(Term, ckiwi.kiwi_var_clone(var), coefficient or 1.0), function(term)
|
||||||
|
ckiwi.kiwi_var_del(term.var)
|
||||||
|
end)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
__mul = function(a, b)
|
__mul = function(a, b)
|
||||||
@@ -377,17 +397,17 @@ ffi.metatype(Term, {
|
|||||||
|
|
||||||
__add = function(a, b)
|
__add = function(a, b)
|
||||||
if ffi_istype(Var, b) then
|
if ffi_istype(Var, b) then
|
||||||
return new_expr_pair(0.0, a, Term(b))
|
return new_expr_pair(0.0, a.var, b, a.coefficient)
|
||||||
elseif ffi_istype(Term, b) then
|
elseif ffi_istype(Term, b) then
|
||||||
if type(a) == "number" then
|
if type(a) == "number" then
|
||||||
return new_expr_one(a, b)
|
return new_expr_one(a, b.var, b.coefficient)
|
||||||
else
|
else
|
||||||
return new_expr_pair(0.0, a, b)
|
return new_expr_pair(0.0, a.var, b.var, a.coefficient, b.coefficient)
|
||||||
end
|
end
|
||||||
elseif ffi_istype(Expression, b) then
|
elseif ffi_istype(Expression, b) then
|
||||||
return add_expr_term(b, a)
|
return add_expr_term(b, a.var, a.coefficient)
|
||||||
elseif type(b) == "number" then
|
elseif type(b) == "number" then
|
||||||
return new_expr_one(b, a)
|
return new_expr_one(b, a.var, a.coefficient)
|
||||||
end
|
end
|
||||||
error("Invalid term + op")
|
error("Invalid term + op")
|
||||||
end,
|
end,
|
||||||
@@ -397,8 +417,7 @@ ffi.metatype(Term, {
|
|||||||
end,
|
end,
|
||||||
|
|
||||||
__tostring = function(term)
|
__tostring = function(term)
|
||||||
return tostring(term.var:name())
|
return tostring(term.coefficient) .. " " .. term.var:name()
|
||||||
--return tostring(term.coefficient) .. " " .. term.var:name()
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -407,10 +426,15 @@ do
|
|||||||
---@param constant number
|
---@param constant number
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function mul_expr_constant(expr, constant)
|
local function mul_expr_constant(expr, constant)
|
||||||
local ret = ffi_new(Expression, expr.term_count, expr.constant * constant, expr.term_count) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, expr.term_count), expr_gc) --[[@as kiwi.Expression]]
|
||||||
for i = 0, expr.term_count - 1 do
|
for i = 0, expr.term_count - 1 do
|
||||||
ret.terms_[i] = ffi_new(Term, expr.terms_[i].var, expr.terms_[i].coefficient * constant) --[[@as kiwi.Term]]
|
local st = expr.terms_[i] --[[@as kiwi.Term]]
|
||||||
|
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
||||||
|
dt.var = ckiwi.kiwi_var_clone(st.var)
|
||||||
|
dt.coefficient = st.coefficient * constant
|
||||||
end
|
end
|
||||||
|
ret.constant = expr.constant * constant
|
||||||
|
ret.term_count = expr.term_count
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -418,14 +442,24 @@ do
|
|||||||
---@param b kiwi.Expression
|
---@param b kiwi.Expression
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function add_expr_expr(a, b)
|
local function add_expr_expr(a, b)
|
||||||
local ret = ffi_new(
|
local a_count = a.term_count
|
||||||
Expression,
|
local b_count = b.term_count
|
||||||
a.term_count + b.term_count,
|
local ret = ffi_gc(ffi_new(Expression, a_count + b_count), expr_gc) --[[@as kiwi.Expression]]
|
||||||
a.constant + b.constant,
|
|
||||||
a.term_count + b.term_count
|
for i = 0, a_count - 1 do
|
||||||
) --[[@as kiwi.Expression]]
|
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
||||||
ffi_copy(ret.terms_, a.terms_, SIZEOF_TERM * a.term_count) ---@diagnostic disable-line: param-type-mismatch
|
local st = a.terms_[i] --[[@as kiwi.Term]]
|
||||||
ffi_copy(ret.terms_[a.term_count], b.terms_, SIZEOF_TERM * b.term_count) ---@diagnostic disable-line: param-type-mismatch
|
dt.var = ckiwi.kiwi_var_clone(st.var)
|
||||||
|
dt.coefficient = st.coefficient
|
||||||
|
end
|
||||||
|
for i = 0, b_count - 1 do
|
||||||
|
local dt = ret.terms_[a_count + i] --[[@as kiwi.Term]]
|
||||||
|
local st = b.terms_[i] --[[@as kiwi.Term]]
|
||||||
|
dt.var = ckiwi.kiwi_var_clone(st.var)
|
||||||
|
dt.coefficient = st.coefficient
|
||||||
|
end
|
||||||
|
ret.constant = a.constant + b.constant
|
||||||
|
ret.term_count = a_count + b_count
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -433,11 +467,16 @@ do
|
|||||||
---@param constant number
|
---@param constant number
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function new_expr_constant(expr, constant)
|
local function new_expr_constant(expr, constant)
|
||||||
local ret = ffi_new(Expression, expr.term_count) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, expr.term_count), expr_gc) --[[@as kiwi.Expression]]
|
||||||
|
|
||||||
|
for i = 0, expr.term_count - 1 do
|
||||||
|
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
||||||
|
local st = expr.terms_[i] --[[@as kiwi.Term]]
|
||||||
|
dt.var = ckiwi.kiwi_var_clone(st.var)
|
||||||
|
dt.coefficient = st.coefficient
|
||||||
|
end
|
||||||
ret.constant = constant
|
ret.constant = constant
|
||||||
ret.term_count = expr.term_count
|
ret.term_count = expr.term_count
|
||||||
|
|
||||||
ffi_copy(ret.terms_, expr.terms_, SIZEOF_TERM * expr.term_count) ---@diagnostic disable-line: param-type-mismatch
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -473,7 +512,8 @@ do
|
|||||||
function Expression_cls:terms()
|
function Expression_cls:terms()
|
||||||
local terms = new_tab(self.term_count, 0)
|
local terms = new_tab(self.term_count, 0)
|
||||||
for i = 0, self.term_count - 1 do
|
for i = 0, self.term_count - 1 do
|
||||||
terms[i + 1] = self.terms_[i]
|
local t = self.terms_[i] --[[@as kiwi.Term]]
|
||||||
|
terms[i + 1] = Term(t.var, t.coefficient)
|
||||||
end
|
end
|
||||||
return terms
|
return terms
|
||||||
end
|
end
|
||||||
@@ -488,7 +528,15 @@ do
|
|||||||
__index = Expression_cls,
|
__index = Expression_cls,
|
||||||
|
|
||||||
__new = function(_, terms, constant)
|
__new = function(_, terms, constant)
|
||||||
return ffi_new(Expression, #terms, constant or 0.0, #terms, terms)
|
local e = ffi_gc(ffi_new(Expression, #terms), expr_gc) --[[@as kiwi.Expression]]
|
||||||
|
for i, t in ipairs(terms) do
|
||||||
|
local dt = e.terms_[i - 1] --[[@as kiwi.Term]]
|
||||||
|
dt.var = ckiwi.kiwi_var_clone(t.var)
|
||||||
|
dt.coefficient = t.coefficient
|
||||||
|
end
|
||||||
|
e.constant = constant or 0.0
|
||||||
|
e.term_count = #terms
|
||||||
|
return e
|
||||||
end,
|
end,
|
||||||
|
|
||||||
__mul = function(a, b)
|
__mul = function(a, b)
|
||||||
@@ -511,7 +559,7 @@ do
|
|||||||
|
|
||||||
__add = function(a, b)
|
__add = function(a, b)
|
||||||
if ffi_istype(Var, b) then
|
if ffi_istype(Var, b) then
|
||||||
return add_expr_term(a, Term(b))
|
return add_expr_term(a, b)
|
||||||
elseif ffi_istype(Expression, b) then
|
elseif ffi_istype(Expression, b) then
|
||||||
if type(a) == "number" then
|
if type(a) == "number" then
|
||||||
return new_expr_constant(b, a + b.constant)
|
return new_expr_constant(b, a + b.constant)
|
||||||
@@ -519,7 +567,7 @@ do
|
|||||||
return add_expr_expr(a, b)
|
return add_expr_expr(a, b)
|
||||||
end
|
end
|
||||||
elseif ffi_istype(Term, b) then
|
elseif ffi_istype(Term, b) then
|
||||||
return add_expr_term(a, b)
|
return add_expr_term(a, b.var, b.coefficient)
|
||||||
elseif type(b) == "number" then
|
elseif type(b) == "number" then
|
||||||
return new_expr_constant(a, a.constant + b)
|
return new_expr_constant(a, a.constant + b)
|
||||||
end
|
end
|
||||||
@@ -569,9 +617,9 @@ function Constraint_cls:expression()
|
|||||||
local n = ckiwi.kiwi_constraint_expression(self, expr, SZ)
|
local n = ckiwi.kiwi_constraint_expression(self, expr, SZ)
|
||||||
if n > SZ then
|
if n > SZ then
|
||||||
expr = ffi_new(Expression, n) --[[@as kiwi.Expression]]
|
expr = ffi_new(Expression, n) --[[@as kiwi.Expression]]
|
||||||
ckiwi.kiwi_constraint_expression(self, expr, n)
|
n = ckiwi.kiwi_constraint_expression(self, expr, n)
|
||||||
end
|
end
|
||||||
return expr
|
return ffi_gc(expr, expr_gc) --[[@as kiwi.Expression]] ---@diagnostic disable-line: param-type-mismatch
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a constraint between a pair of variables with ratio.
|
--- Create a constraint between a pair of variables with ratio.
|
||||||
@@ -586,11 +634,7 @@ end
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
function kiwi.new_pair_ratio_constraint(left, coeff, right, constant, op, strength)
|
function kiwi.new_pair_ratio_constraint(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))
|
||||||
return Constraint(
|
return Constraint(new_expr_pair(-(constant or 0.0), right, left, -coeff), op, strength)
|
||||||
new_expr_pair(-(constant or 0.0), Term(left), Term(right, -coeff)),
|
|
||||||
op,
|
|
||||||
strength
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a constraint between a pair of variables with ratio.
|
--- Create a constraint between a pair of variables with ratio.
|
||||||
@@ -604,11 +648,7 @@ end
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
function kiwi.new_pair_constraint(left, right, constant, op, strength)
|
function kiwi.new_pair_constraint(left, right, constant, op, strength)
|
||||||
assert(ffi_istype(Var, left) and ffi_istype(Var, right))
|
assert(ffi_istype(Var, left) and ffi_istype(Var, right))
|
||||||
return Constraint(
|
return Constraint(new_expr_pair(-(constant or 0.0), right, left, -1.0), op, strength)
|
||||||
new_expr_pair(-(constant or 0.0), Term(left), Term(right, -1.0)),
|
|
||||||
op,
|
|
||||||
strength
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a single term constraint
|
--- Create a single term constraint
|
||||||
@@ -621,7 +661,7 @@ end
|
|||||||
---@nodiscard
|
---@nodiscard
|
||||||
function kiwi.new_single_constraint(var, constant, op, strength)
|
function kiwi.new_single_constraint(var, constant, op, strength)
|
||||||
assert(ffi_istype(Var, var))
|
assert(ffi_istype(Var, var))
|
||||||
return Constraint(new_expr_one(-(constant or 0.0), Term(var)), op, strength)
|
return Constraint(new_expr_one(-(constant or 0.0), var), op, strength)
|
||||||
end
|
end
|
||||||
|
|
||||||
local Strength = kiwi.Strength
|
local Strength = kiwi.Strength
|
||||||
@@ -701,7 +741,6 @@ local function try_solver(f, solver, item, ...)
|
|||||||
local kind = err.kind
|
local kind = err.kind
|
||||||
local message = err.message ~= nil and ffi_string(err.message) or ""
|
local message = err.message ~= nil and ffi_string(err.message) or ""
|
||||||
if err.must_free then
|
if err.must_free then
|
||||||
print("FEEE")
|
|
||||||
C.free(err)
|
C.free(err)
|
||||||
end
|
end
|
||||||
error(new_error(kind, message, solver, item))
|
error(new_error(kind, message, solver, item))
|
||||||
|
|||||||
Reference in New Issue
Block a user