这是一个 Swift 版本的 cassowary1 单纯形求解器,其灵感来自 C++ 实现 Kiwi2。
Cassowary 支持线性方程和非严格不等式。此外,可以为系统中的每个约束赋予一个强度,控制其对系统整体解决方案的重要性。
变量是求解器尝试解析的值。这些值对应于实现中的 Variable
类型。变量可用于创建构成系统约束的表达式。这些表达式必须添加到求解器的实例中。
import cassowary
let simplex: Solver = Solver()
let x_l: Variable = Variable("x_l")
let x_r: Variable = Variable("x_r")
let x_m: Variable = Variable("x_m")
simplex.add(constraint: 2.0 * x_m == x_l + x_r)
simplex.add(constraint: x_l + 10.0 <= x_r)
simplex.add(constraint: x_l >= -10.0)
simplex.add(constraint: x_r <= 100.0)
这将创建一个具有三个变量 (xl, xr, xm) 的系统,表示线段上的点。 xm 被约束为 xl 和 xr 之间的中点,xl 被约束为至少在 xr 左侧 10 个单位,并且所有变量都必须位于 [-10, 100] 范围内。所有约束都必须满足,并且被 cassowary 算法认为是 required
(必需的)。
注意 同一个约束不能以相同的形式多次添加到求解器。 支持 cassowary 规范中的冗余约束。 也就是说,以下约束集可以添加到求解器中
x == 10
x + y == 30
y == 20
Cassowary 支持非必需但会尽力处理的约束。 这种约束被建模为具有 required
(必需的)以外的强度。 这些约束按照其强度的值顺序进行考虑。 默认情况下定义了三种标准强度
strong (强)
medium (中)
weak (弱)
我们可以向之前的示例添加一个约束,通过添加一个新的 weak
(弱)约束将 xm 放置在 50
simplex.add(constraint: x_m == 50.0, strength: .weak)
到目前为止描述的系统是静态的。 为了找到 xm 的特定值的解决方案,Cassowary 提供了编辑变量的概念,允许您在评估系统之前为变量建议值。 这些变量可以具有除 required
(必需的)之外的任何强度。
继续我们的示例,我们可以使 xm 可编辑,并为其建议一个值为 60
。
simplex.add(variable: x_m, .strong)
simplex.suggest(value: 60.0, for: x_m)
此实现每次添加或删除约束,或者为编辑变量建议新值时都会求解系统。 但是,变量值不会自动更新,您必须请求求解器更新值。
simplex.suggest(value: 90, for: x_m)
simplex.update()
1 https://constraints.cs.washington.edu/solvers/cassowary-tochi.pdf ↩
2 https://github.com/nucleic/kiwi ↩