4

我在做一些与用 Python 制作真值表相关的作业时遇到了一些麻烦。我试过去办公时间,但他们什么都不知道,所以我得问问你们。

这是问题:

--

在这个问题中,您将实现用于打印带有变量的公式的真值表的函数。您可以使用以下帮助函数,它打印一个制表符分隔的值列表。

def prints(values):
    print("\t".join([str(value) for value in values]))

上面的函数可以如下使用

prints([True, False, True])
True   False  True

您还可以使用以下帮助函数,它返回函数的参数名称列表:

def variables(f):
    return list(f.__code__.co_varnames)

上述函数可按如下方式使用:

def h(x,y,z): return (y or x) and (not(z) <= x)

variables(h)
['x', 'y', 'z']

答:实现一个函数truthtableXY(f),它接受一个函数f(即,一个Python函数对应于一个公式,例如你在上面的问题#2中定义的那些公式)作为它的输入。你可以假设 f 有两个布尔参数 x 和 y。该函数应打印 f 的真值表。

def f(x,y): return x and y

truthtableXY(f)
y      x      formula
True   True   True
True   False  False
False  True   False
False  False  False

B:实现一个递归函数truthtable(f),它的第一个参数是单个函数f(即对应于公式的Python函数)。函数 f 可以采用任何非零数量的参数。该函数应打印 f 的真值表。

def h(x,y,z): return (y or x) and (not(z) <= x)

truthtable(h)
x       y       z       formula
True    True    True    False
True    True    False   False
True    False   True    False
True    False   False   False
False   True    True    True
False   True    False   False
False   False   True    False
False   False   False   False

您的truthtable() 函数应该采用递归回溯方法,并且可以按如下方式组织:

  • 该函数应该有第二个参数值,其默认值为 [],这将是函数建立并最终传递给 f 的值列表;
  • 如果列表值为空,则函数应打印包含所有变量名称的行(每个变量一个列标题);
  • 如果列表值与 f 的变量列表长度相同,则该函数应打印一行包含 values 中所有值的值,以及将 f 应用于该值列表的结果(使用 *-operator将 f 应用于参数列表);
  • 如果列表值比 f 的变量列表短,该函数应该递归调用truthtable(),并适当更改truthtable() 的参数。

C:实现一个函数 rows(f),它的第一个参数是单个函数 f(即,对应于公式的 Python 函数)。该函数应返回 f 的真值表中的行数。

def h(x,y,z): return (y or x) and (not(z) <= x)

rows(h)
8

--

我设法做了A,得到了这个答案:

def truthtableXY(f):
    prints(['y', 'x', 'formula'])
    for x in [True, False]:
        for y in [True, False]:
            prints([x, y, f(x,y)])

哪个有效。但我根本无法弄清楚如何做其他人。

有谁知道/可以找出答案吗?

这是带有作业顺便说一句的原始网站:http ://cs-people.bu.edu/lapets/131/m.php?#2.4 (问题3)

提前谢谢各位!:)

4

3 回答 3

3

对于 B,你想要:

def truthtable(f, values=None):
    if values is None:
        prints(variables(f) + ["formula"])
        values = []
    # print values 
    if len(values) == len(variables(f)):
        prints(values + [f(*values)])
    else:
        for b in [True, False]:
            truthtable(f, values + [b])

这如何符合您的规格:

  • 该函数应该有values一个默认值为 的第二个参数[],它将是函数建立并最终传递给的值列表f;-不完全是,“可变默认参数”在 Python 中是一个糟糕的举动,但我values在第一次调用时将其设为空列表truthtable

  • 如果列表values为空,该函数应打印包含所有变量名称的行(每个变量一个列标题);-在初始化的同时完成value

  • 如果列表values与 的变量列表长度相同f,则函数应打印一行包含 中所有值的值values,以及应用于f该值列表的结果(使用 -运算*符应用于f列表论据);-第二if

  • 如果列表values比 的​​变量列表短f,该函数应该对 进行递归调用 truthtable(),并对 的参数进行适当的更改 truthtable()。- 最后的for循环。

有关最后一部分的更多解释;您需要建立 和 的组合True并将False其作为参数传递给f,因此您首先递归调用(即从自身内部调用函数)truthtableTrue然后使用False,每次添加到列表中,直到您拥有正确数量的参数。取消注释print values以在解释器中观看这种情况。

于 2014-01-27T23:35:08.003 回答
3

首先,我们不使用该功能,而是使用该模块variables定义自己的功能。inspect这样,我们就不必访问内部特定于实现的属性:

import inspect
def variables (f):
    return inspect.getargspec(f).args

对于真值表,我们需要一些组合,所以我们使用itertools模块:

from itertools import product, repeat
def truthtable (f):
    vars = variables(f)

    # print the header
    prints(vars + ['formula'])

    # get all combinations
    for args in product(*repeat((True, False), len(vars))):
        result = f(*args)
        prints(args + (result,))

使用后,我们得到以下结果:

>>> truthtable(f)
x   y   formula
True    True    True
True    False   False
False   True    False
False   False   False
>>> truthtable(h)
x   y   z   formula
True    True    True    False
True    True    False   False
True    False   True    False
True    False   False   False
False   True    True    True
False   True    False   False
False   False   True    False
False   False   False   False

我将把递归函数的实现留给你。毕竟这是你的功课,说明实际上很好地解释了你需要做什么。

至于最后一个任务,这是简单的组合数学。对于每个变量,我们有两个可能的值。对于我们添加到一组组合中的每个变量,我们必须将所有这些组合组合一次True和一次,False这样我们就会得到两倍的结果。对于只有一个变量的情况,我们只有两种可能性。所以对于n变量,我们有2 ** n可能的组合。


好的,让我们逐一阅读说明以使此递归解决方案起作用:

该函数应该有第二个参数值,其默认值为 [],这将是函数建立并最终传递给 f 的值列表

好的,所以我们的函数将如下所示:

def truthtable (f, values=[]):
    # …

但取而代之的是,我们实际上将设置默认值None并明确地将其设置为函数内部的一个空列表。你可能会为此打你的教练,因为这是一个非常常见的错误

def truthtable (f, values=None):
    if values is None:
        values = []
    # …

如果列表值为空,该函数应打印包含所有变量名称的行(每个变量一个列标题)

好的,这只是调用prints(variables(f)),所以这部分看起来像这样:

if values == []:
    prints(variables(f))

如果列表值与 f 的变量列表长度相同,则该函数应打印一行包含 values 中所有值的值,以及将 f 应用于该值列表的结果(使用 *-operator将 f 应用于参数列表)

同样,这也是直截了当的:

if len(values) == len(variables(f)):
    result = f(*values)
    prints(values + [result])

如果列表值比 f 的变量列表短,该函数应该递归调用truthtable(),并适当更改truthtable() 的参数。

所以这里是递归发生的地方,所以让我们考虑一下。我们从一个空的值列表开始,我们想要达到一个值与变量一样多的点。所以很明显我们想在values递归调用函数时向列表中添加值。现在我们要添加哪些值?我们知道的仅有的两个值:TrueFalse。所以调用看起来像这样:

truthtable(f, values + [True])
truthtable(f, values + [False])

现在我们把所有这些放在一起:

def truthtable (f, values=None):
    if values is None:
        values = []

    if values == []:
        prints(variables(f))

    if len(values) == len(variables(f)):
        result = f(*values)
        prints(values + [result])
    else:
        truthtable(f, values + [True])
        truthtable(f, values + [False])

就是这样。现在,我从一开始就说过,关于values这个函数的可变默认值并不完全正确,因为我们从不直接修改列表,而只是通过将其与其他列表连接来创建一个新列表;所以我们可以再次恢复。但无论如何我都会留下它,因为您应该始终牢记这一点,否则您迟早会遇到问题。

于 2014-01-27T23:19:35.300 回答
2

好吧,C 部分是微不足道的,那就是2 ** len(variables(h)). 对于 B 部分,我建议对变量的所有可能分配使用枚举器。对于赋值,我的意思是一个与变量数组长度相同的布尔值数组,因此每个变量都有一个布尔值。

然后,您可以在 Python 中使用以下技巧:

>>> def f(x, y, z): return (y or x) and (not(z) <= x)
>>> assignment = [True, False, True]
>>> f(*assignment)
False

这是使用列表中的参数调用函数的技巧。

您现在可以看到,您可以枚举分配,并检查每个分配的函数值。

要枚举分配,您还可以使用布尔值只是整数计数器的位这一事实。如果您真的希望它回溯,请使用:

def enumerate_bools(length):
    if length == 0:
        yield []
        return
    for rest in enumerate_bools(length - 1):
        yield [False] + rest
        yield [True]  + rest
于 2014-01-27T23:06:49.440 回答