我正在使用SymPy来创建一个Kakuro求解器,但我无法强制执行符号需要整数。到目前为止,我得到了一个看起来像这样的不等式:
((1 <= x) & (x < 3/2)) | ((3/2 < x) & (x < 2))
符号x
应该等于1,因此表达式是正确的,因为1是唯一可能的整数。
如何强制x
为整数?
我知道SymPy中有可用的丢番图求解器,但这些似乎只能处理方程,而不是不等式。我尝试使用以下方法创建符号:
x = Symbol('x', integer=True)
但没有运气。
答案 0 :(得分:0)
似乎没有内置方式,但我编写了一个函数来简化你提到的那种关系,假设我们使用整数。
有八个重写规则:例如,x <= number
替换为x <= floor(number)
,x < number
替换为x <= ceiling(number) - 1
等。
应用这些规则后,表达式的任何剩余And
部分都会受到reduce_inequalities
的约束。示例:
expr = ((1 <= x) & (x < 3 / 2)) | ((3 / 2 < x) & (x < 2))
simplify_integer_relation(expr) # returns Eq(x, 1)
警告:重写规则假设我们不会在表达式中执行任何类似x/2
的操作,从而创建未知的小数。假设涉及未知的所有内容都是整数。
代码:
def simplify_integer_relation(expr):
rewrite_rules = {
GreaterThan: {
"lhs": lambda z: floor(z),
"rhs": lambda z: ceiling(z),
"rel": GreaterThan,
},
LessThan: {
"lhs": lambda z: ceiling(z),
"rhs": lambda z: floor(z),
"rel": LessThan,
},
StrictGreaterThan: {
"lhs": lambda z: ceiling(z) - 1,
"rhs": lambda z: floor(z) + 1,
"rel": GreaterThan,
},
StrictLessThan: {
"lhs": lambda z: floor(z) + 1,
"rhs": lambda z: ceiling(z) - 1,
"rel": LessThan,
},
}
for rel in rewrite_rules:
rule = rewrite_rules[rel]
for atom in expr.atoms(rel):
if atom.lhs.is_number:
new_atom = rule["rel"](rule["lhs"](atom.lhs), atom.rhs)
expr = expr.subs(atom, new_atom)
elif atom.rhs.is_number:
new_atom = rule["rel"](atom.lhs, rule["rhs"](atom.rhs))
expr = expr.subs(atom, new_atom)
for system in expr.atoms(And):
expr = expr.subs(system, reduce_inequalities(system.args))
return expr