【形式化方法】Part A:线性算术基础理论

在这节课中,我们讨论了线性算法(以下简称LA)和线性规划(以下简称LP)的理论。算术约束在形式推理和(困难的)问题解决的每个方面都是普遍存在的,LA和LP都是建立这些模型和解决问题的非常有力的工具。

从计算机科学的观点来看,大多数LA和LP问题都可以通过专用软件或库来解决,IBM非常流行的CPLEX就是一个例子。然而,通过在整数、有理数或实数域上合并调优的LA/LP决策过程,大多数现代求解器/验证器对LA/LP理论也有足够的支持。以Z3为例,它对LA和LP都有很好的支持。

在这个作业中,你将熟悉LA/LP的背景理论,LA/LP在现实世界(困难)问题中的重要应用(通过使用Z3),以及现代求解器/求解器解决这些问题的基础算法。

这个作业被分为三个部分,每个部分都包含一些教程和问题。第一部分介绍了LA/LP理论的基本背景和知识;第二部分通过解决一些np -完全困难问题,讨论了LA/LP理论的应用;第三部分介绍了傅里叶-莫兹金变量消去、单纯形算法的实现。有些问题与锻炼联系在一起,你应该解决这些问题。还有一些问题被贴上了挑战的标签,这些问题是可选的。下载这个代码模板开始。

在开始这项作业之前,确保你已经完成了作业1中的软件设置,并且在你的电脑(或笔记本电脑)上正确安装了Z3和Python(3.7+推荐)。如有任何问题,请随时与我们联系寻求帮助。

Part A:线性算术基础理论

 

在本节中,我们将通过求解器Z3来讨论LA/LP的基本理论。

基本的线性运算
回忆一下刚才的课,LA的语法是

求解器Z3完全支持这种语法,Z3可以非常有效地求解一组等式/不等式。假设我们可以有两个数字ℝ,以下约束:

然后我们可以声明两个Z3变量,并在Z3中构建求解器:

   x, y = Reals('x y')
    solver = Solver()
    solver.add([x + y = 0.8, x - y = 0.2])
    res = solver.check()
    if res == sat:
        print(solver.model())

如果上述约束条件满足,Z3将输出找到的模型。

Exercise1:阅读我们在la-theory.py Python文件中给出的这个练习的代码,我们已经给出了这个练习的所有代码。确保你理解代码,并运行代码,输出是什么?

x, y = Reals('x y')
solver = Solver()
solver.add(x + y == 0.8, x - y == 0.2)
res = solver.check()
print("result for problem 1:")
if res == sat:
    model = solver.model()
    print(model)
else:
    print(res)
# exercise 1: run the above code and check the result, is the result correct?
# you don't need to write any code, just make sure you understand the output.

# answer exercise 1: 输出的结果是 y = 3/10 ,x = 1/2 满足x + y = 0.8 x - y = 0.2

当然,并不是所有的约束条件都是可以满足的,例如,考虑以下两个变量约束ℝ:

显然,这些约束是不能满足的。

 

 Exercise 2:阅读我们在la-theory.py Python文件中给出的这个练习的代码。通过填充缺失的代码来完成这个练习。如果你的实现是正确的,你的代码应该输出“unsat”。

x, y = Reals('x y')
solver.add(x + y == 0.8, x + y == 0.2)
res = solver.check()
print("result for problem 2:")
if res == sat:
    model = solver.model()
    print(model)
else:
    print(res)

运行结果:

除了域名真正ℝ(“实数”),Z3也有不错的支持整数域ℤ。例如,两个整数变量ℤ,这段代码

x, y = Ints('x y')

在Z3中声明两个整数。类似地,我们可以让Z3检查整数上的这些约束,例如,给定以下约束:

并给出了模型。

Exercise 3:阅读我们在la-theory.py Python文件中给出的这个练习的代码。通过填充缺失的代码来完成这个练习。输出是什么?

x, y = Ints('x y')
solver = Solver()
solver.add(x + y == 8, x - y == 2)
res = solver.check()
print("result for problem 3:")
if res == sat:
    model = solver.model()
    print(model)
else:
    print(res)

 输出结果:

这里要注意的重要一点是:当我们谈论的可满足性约束,我们必须清楚域(ℝ、ℤℚ还是其他?)我们正在做,因为约束的可满足性依赖于底层域。为了理解这一点,让我们考虑下面的例子,给定这些约束:

我们可以得出这样的结论:这些约束在域ℝ可以满足的,但不是在域ℤ。

练习4:阅读我们在la-theory.py Python文件中给出的这个练习的代码。在填写缺失的代码来完成这个练习检查域ℝ上面的约束是可以满足的,但不是在域ℤ。

def check_cons(constraints):
    solver = Solver()
    solver.add(constraints)
    res = solver.check()
    if res == sat:
        model = solver.model()
        # print(model)
        return res, model
    else:
        # print(res)
        return res, None


def print_model(res, model):
    if res == sat:
        print(model)
        return
    print(res)
    return

x, y = Reals('x, y')
cons = [x + y == 8, x - y == 1]
# raise Todo("exercise 4: please fill in the missing code.")
print('result for problem 4:')
res, model = check_cons(cons)
print_model(res, model)

输出结果:

 

0-1整数线性运算

有一个重要的特殊情况拉域ℤ,称为线性0 - 1整数算术(或0 - 1马尼拉)。在这种情况下,所有整数变量只能有两个值:或者,在这种意义上,它们完全对应布尔值(真或假)。

0-1整数LA(以及我们将在下面讨论的0-1整数线性规划)有许多很好的性质和许多重要的应用,我们将在下面讨论一些。但是现在,让我们先考虑一个有趣的问题,让我们欣赏0-1 ILA的简单和强大。

问题是:假设我们有一列整数我们被要求编写一个程序,来检查列表中是否至少有一个0。当然,不是写一个简单的Python程序来解决这个问题。但是为了我们的目的,让我们考虑一下如何用0-1整数LA来解这个问题。为此,我们首先声明一个辅助0-1整型变量列表X:满足:并且满足非正式地说,名单上只有一个。对于给定的输入整数列表(正在搜索s):我们要求:

 

Exercise 5:为什么使用上述约束条件?能否保证输入列表中至少有一个整数?您不需要编写代码,只需说服自己这些约束的正确性。

answer exercise 5: 需要使用这些约束条件。因为我们的目标是在列表中至少找到一个0,所以让xi只能取0或1,并且xi之和只能为1。说明xi某个值为1,其他值为0。所以需要满足式子x_1 + x_2 + ... + x_n = 1
[e_1, e_2, ..., e_n]是输入列表,如果没有0的话,约束条件x_1*e_1 + x_2*e_2 + ... + x_n*e_n = 0的为unsat,若至少有一个0的话,
约束条件x_1*e_1 + x_2*e_2 + ... + x_n*e_n = 0为sat。因为可以找到某个xi = 1,与 ei =0相乘,再与其他数相加是0.

def check_zero_la(l):
    # create a list of auxiliary variables:
    # [x_0, ..., x_{n-1}]
    vars = [Int('x_%d' % i) for i in range(len(l))]
    # create the first group of constraints:
    #   all "vars" are 0-1 integers:
    cons_0_or_1 = []
    for i in range(len(vars)):
        # print(vars[i])
        cons_0_or_1.append(Or(vars[i] == 0, vars[i] == 1))
        # print(cons_0_or_1[i])


    # create the second group of constraints:
    #   x_1 + x2 + ... + xn = 1
    cons_sum = [sum(vars) == 1]
    # create the second group of constraints:
    #   x_1*e_1 + x_2*e_2 + ... + x_n*e_n = 0
    cons_exp=[]
    # exercise 6: fill in the missing code to generate the above constraint,
    # and store it in the "cons_exp" variable.
    # Make sure your code passes all the following unit test.
    # raise Todo("exercise 6: please fill in the missing code.")
    i = 0
    con_e = []
    for e in l:
        con_e.append(vars[i]*e)
        i = i + 1

    cons_exp = [sum(con_e) == 0]

    # check these constraints:
    res, model = check_cons(cons_0_or_1 + cons_sum + cons_exp)
    if res == sat:
        print('sat:')
        print(model)
        return True
    print('unsat')
    return False


# # # unit test the above function:
print('problem 6  ---l1:')
assert (not check_zero_la(l1))
print('problem 6 ---l2 :')
assert (check_zero_la(l2))
print('problem 6  ---l3:')
assert (check_zero_la(l3))
print('problem 6 end')

 

x = Real('x')
res, model = check_cons([x * x == 2])
if res == sat:
    print(model)
else:
    print(res)

# exercise 7: write some code to check that this non-linear constraint,
# on two real numbers x and y, is unsat:
#   x*x + y*y < 0
# raise Todo("exercise 7: please fill in the missing code.")
print('result for problem 7:')

x, y = Reals('x y')
res, model = check_cons([x * x + y * y < 0])
if res == sat:
    print(model)
else:
    print(res)

 

#中科大软院-hbj形式化课程笔记-欢迎留言与私信交流

#随手点赞,我会更开心~~^_^

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值