真值表 && 逻辑表达式(二)

前言

之前写的”真值表 && 逻辑表达式“表达有误,代码没有问题,但是化简没有达到最简,另外,代码的输入有点反人类,这里也更新一下

一. 逻辑表达式转真值表(代码更新)

改为采用符号表达,其中以exp = Ad + AcD + acd + abC + abcD为例,s[0]表示a/A,s[1]表示b/B,以此类推。
取反不再使用字母的大小写表达,而是采用取反符号。

import csv

def Write_csv(csv_file,data,encode='utf-8'):
    with open(csv_file, 'w', encoding=encode,newline='') as file_obj:
        writer = csv.writer(file_obj)
        for i in data:
            writer.writerow(i)

def get_data(exp, s):
    num = len(s)
    data_out = []
    for i in range(2**num):
        line = bin(i)
        line = str(line)
        line = line[2:]
        line = '0'*(num-len(line)) + line
        for j in range(num):
            s[j] = eval(line[j])
        #**************************************
        if(eval(exp) != 0):
            line = line + '1'
        else:
            line = line + '0'
        #**************************************
        data_out.append(tuple(line))
    return data_out


if __name__ == "__main__":
    s = [0, 0, 0, 0]#初始化列表
    EXP = "(~s[0])&s[2] | (~s[0])&s[3] | s[2]&s[3] | s[0]&s[1]"
    data = get_data(EXP, s)
    Write_csv('test.csv',data)

二. 真值表转逻辑表达式

2.1 赘述

经过之前(https://blog.csdn.net/wxkhturfun/article/details/129533156?spm=1001.2014.3001.5501)的尝试,发现基于韦恩图的化简,难以处理,并且不利于计算(本人又不想用原始的卡诺图),于是在将韦恩图盯着看一上午后,将曲线变为直线,为了便于分析,本人利用坐标系抽象出一个立方体:如下
其中左图是平面直角坐标系,右图是对应的8421编码的值
在这里插入图片描述

2.2 数学原理

声明:以下数学原理毫无根据,纯属个人猜想,有错指出,无错请证明
将所有真值表为1的值,用数字表示,例如:
以3维体系为例:
expression = abc + ABc ,表示坐标中的(1,1,1)和(0,0,1)这两个点,则对应的数值为7和1,

  1. 如果两个点可以合并,表示存在一条立方体的边,该边的端点为这两个点

  2. 如果两条边可以合并,表示存在立方体的一个面,该正方形可以这两条边形成,例如(4,5)和(6,7)可以合并成面:(4,5,7,6),但是(0,1)和(6,7)不可以合并成面(0,1,6,7),因为该面穿越了立方体,不在立方体的表面

  3. 推论1:在N维情况下,如果两个点可以合并,意味着其8421编码对应的各个位的二进制之和中,恰好有(N-1)个0或 2 1 2^1 21。例如:

    当N=3时,(4)和(6)可以合并,因为4=100(2),6=110(2)
    第0位相加 =1+1 =2 (等于 2 1 2^1 21,这里是2的1次幂,因为两个点合并,两个点是1维)
    第1位相加 = 0+1=1 (等于1,即不是0,也不是 2 1 2^1 21
    第2位相加 = 0+0=2 (等于 2 1 2^1 21,这里是2的1次幂,因为两个点合并,两个点是1维)
    所以结果是0的个数和 2 1 2^1 21的个数共有2个,恰好为(N-1)=3-1=2,因此两个点可以合并

    同理,我们检验下(0)和(6)
    0 = 000(2),6=110(2)
    0+1=1
    0+1=1
    0+0=0
    0和 2 1 2^1 21的个数共有1个,不是(N-1)= 2,因此两个点不可以合并

  4. 推论2:在N维情况下,如果两条线可以合并,意味着其8421编码对应的二进制之和恰好有(N-2)个0或 2 2 2^2 22

  5. 推论3:在N维情况下,如果两个m维(为点是m=1,为线是m=2,…)可以合并,意味着其8421编码对应的0和1之和恰好有(N-1)个0或 2 m 2^m 2m

重复一遍:以上理论都是猜的,有误请指出,无误给证明

2.3 Python处理过程

  1. 因为在化简的过程中,无法确定顺序A->B->C->…的顺序,因为对某些表达式来讲存在一种可能,仅在该顺序下可以化到最简(本人bug出来的)
  2. 最初我想把A->B的线段当作一个矢量,对矢量进行处理,但是2、3、4维不好处理(计算上不好处理)
  3. 想到常用的chmod 755这个例子,决定按二进制进行处理
  4. 在采用二进制后,虽说带有权重了,但是不能直接化简,因为有吸收律:a+ab->a,但是何时将b吸收进a,还是吸收进可能的c,需要考虑,因此不能直接吸收
  5. 在使用8421编码后,不能直接相减,例如(5,4,3,2)这四个虽然共面,但是不存在于立方体的表面,因此该组数据不能统一化简

2.4 源码

我的思路是:点 → \rightarrow 线 → \rightarrow → \rightarrow → \rightarrow 4维 → \rightarrow

  1. 首先将所有真值表中值为1的点进行互连,得到线段,将穿越面、穿越体、穿越时间等的线段进行剔除,得到“合理”的线段
  2. 在线段的基础上,得到“合理”的面
  3. 在面的基础上,得到合理的“体”
  4. …直到最高维度
  5. 将所有的线、面、体、…的集合(python这里我用的是一个列表)进行化简,因为之前得到的线、面、体、…肯定有重复的,可以剔除的
  6. 剔除方法为:从低维向高进行剔除,因为有的线已经构成面了,因此将所有的面中的元素进行合并,判断该线段是否在合并的列表中,在则剔除。
  7. 同理剔除多余的面、体、…
  8. 最后进行同维度的剔除,比如线段ab、bc、cd,其实只需要ab、cd就够了,不需要bc了,因为b点和c点已经包含在ab、cd中了,这是同维度的剔除。
  9. 同理进行其余维度的同维度剔除

最后代码如下:
本人水平有限,如有错误,感谢指正

import csv

#input:csv file
#out1:元素个数
#out2:把结果为1的值读进data
def Read_csv_True(csv_file,encode='utf-8'):
    data = []
    column = 0
    with open(csv_file, 'r', encoding=encode) as file_obj:
        reader = csv.reader(file_obj)
        for row in reader:
            element = row[-1]
            if(0 == int(element)):
                continue
            tmp = row[:-1]
            for i in range(len(tmp)):
                tmp[i] = int(tmp[i])
            data.append(tmp)
    column = len(row)-1

    result = []
    for i in data:
        num = 0
        for j in range(len(i)):
            num += i[j] * (2**(column-1-j))
        result.append([num])
    return column,result


# 判断是否共线、共面、共体、...
def Cmp(A, B, N):
    result = A + B
    result.sort(reverse=False)
    if(len(result) != len(set(result))):
        return None
    
    cmp = []
    flag = A[0] >= B[0]
    for i in range(len(A)):
        if(flag):
            cmp.append(A[i] - B[i])
        else:
            cmp.append(B[i] - A[i])

    cmp = list(set(cmp))
    cmp.sort(reverse=False)
    #print("++++++++++++++++++++++++++++++++++")
    #print(cmp)
    #print(len(A))
    #print("----------------------------------")
    #if(len(cmp) == 1):
    if(len(cmp) == 1):
        for i in range(N):
            if(cmp[0] == 2**i):
                #if(result == [11,12,13,14]):
                cnt = [0] * N
                for i in result:
                    num = bin(i)[2:]
                    num = '0'*(N-len(num)) + num
                    for j in range(N):
                        cnt[j] += eval(num[j])
                cnt_2 = 0
                for i in cnt:
                    if(i == 0 or i == 2*len(A)):
                        cnt_2 += 1
                if(cnt_2 == N-len(A)):
                    return result
                else:
                    return None
    return None


# dot是所有值为1的点的集合,
# N是超几何空间的维度
def Expansion(dot, N):
    data_update = dot
    data_update.sort(reverse=False)
    data = []
    data.append(data_update)

    for i in range(N):
        tmp = []
        for j in range(len(data_update)):
            if (len(data_update) == 1):
                tmp = []
                break
            for k in range(j+1, len(data_update)):
                cmp_data = Cmp(data_update[j], data_update[k], N)
                if (cmp_data != None):
                    tmp.append(cmp_data)
        #if(tmp == [[0,2,5,7]]):
        #    print("+++++++++++++++++++++++++++++++++++")
        #    print(data_update)
        #    print("-----------------------------------")
        ####################################################################
        # 去重
        #print(tmp)
        tmp.sort(reverse=False)
        unique_list = []
        [unique_list.append(i) for i in tmp if not i in unique_list]
        ####################################################################
        data = data + [unique_list]
        # data.append(unique_list)
        data_update = unique_list
    return data


def Include(high, low):
    return set(low).issubset(set(high))


def Simplify(data):
    result = data
    scatter = []
    ################################
    for i in result:
        tmp = []
        for j in i:
            for k in j:
                tmp.append(k)
        scatter.append(tmp)
    ################################
    for i in range(len(data) - 1):
        for j in range(len(data[i])-1, -1, -1):
            if (Include(scatter[i+1], data[i][j])):
                del (result[i][j])

    # 同级去重
    final_result = []
    for i in result:
        final_result.append(Level_simply(i))
    return final_result


def Level_simply(data):
    result = []
    NUM = sum_List(data)
    i = 0
    while(i <len(data)):
        tmp = data.copy()
        del(tmp[i])
        if(NUM != sum_List(tmp)):
            result.append(data[i])
        else:
            del(data[i])
            i -= 1
        del(tmp)
        if(i == len(data)-1):
            break
        i += 1
    return result

def sum_List(data):
    scatter = []
    for i in data:
        for j in i:
            scatter.append(j)
    scatter = list(set(scatter))
    return len(scatter)

def Get_Exp(data, N):
    result = []
    for i in range(len(data)):
        for j in data[i]:
            if (j != []):
                result.append(Num_2_Symbol(j, i, N))
    return result

def Print_Exp(data):
    line = ""
    for i in data:
        #line += i + " + "
        line += str(i) + " | "
    line = line[:-3]
    return line

def Num_2_Symbol(data, l, N):
    level = 2**l
    #print("+++++++++++++++++++++++++++++++++++++++")
    #print(data)
    #print(level)
    #print("---------------------------------------")
    flag = [0]*N
    line = ""
    

    if (len(data) > 1):
        for i in range(len(data)):
            num = bin(data[i])[2:]
            num = '0'*(N-len(num)) + num
            for j in range(N):
                flag[j] = flag[j] + eval(num[j])
        #######################################
        for i in range(N):
            if (flag[i] == 0):
                line += "(~s[" + str(i) + "])&"
            elif (flag[i] == level):
                line += "s[" + str(i) + "]&"
        line = line[:-1]
    else:
        # 进入else说明只有1个元素
        num = bin(data[0])[2:]
        num = '0'*(N-len(num)) + num
        for i in range(len(num)):
            if (eval(num[i]) == 0):
                line += "(~s[" + str(i) + "])&"
            else:
                line += "s[" + str(i) + "]&"
        line = line[:-1]
    #print("++++++++++++++++++++++++++++++")
    #print(data)
    #print(level)
    #print(flag)
    #print(line)
    #print("--------------------------------")
    return line



if __name__ == "__main__":
    #a = [[3], [7], [5], [4], [1]]
    #a = [[0], [7], [5],[2]]
    #r = Expansion(a, 3)
    #f = Simplify(r)
    #s = Get_Exp(f, 3)
    #t = Print_Exp(r)
    #print(r)

    #N指字母个数
    N,a = Read_csv_True('test.csv','utf-8')
    r = Expansion(a, N)
    f = Simplify(r)
    s = Get_Exp(f, N)
    t = Print_Exp(s)
    print(t)

2.5 2024-4-17更新

晚上在看《Digital System Test and Testable Design》的时候,看到一张让我眼前一亮的图():
在这里插入图片描述
原书内容:We use circuit of Fig. 6.8 as a primitive that will be described in cubical form. The Karnaugh
map and the cubical representation of this function are also shown and will be used for describing
cubes for this function.

### 回答1: 在Python中,可以通过真值表来判断一个逻辑表达式的真假。首先,我们需要定义逻辑表达式的各个变量和对应的可能取值。然后,根据真值表中的每一行,将变量赋予不同的取值,并计算逻辑表达式的结果。 假设逻辑表达式是由n个变量组成,那么对于每一个变量,可以用0和1来表示其可能的取值。通过计算不同的取值组合,可以生成真值表。例如,如果表达式为A and B,则其真值表如下所示: A B Result 0 0 0 0 1 0 1 0 0 1 1 1 在Python中,可以使用循环嵌套来遍历所有的取值组合。首先,定义变量的取值范围和表达式。然后,使用两个嵌套的for循环来生成不同的取值组合,并将其赋给变量。在每一轮循环中,计算逻辑表达式的结果,并将结果输出。 以下是一个实现的示例代码: ```python variables = ['A', 'B'] expression = '(A and B)' # 生成真值表的表头 header = '\t'.join(variables + ['Result']) print(header) # 遍历所有取值组合 for i in range(2): for j in range(2): # 将当前取值组合赋给变量 values = [i, j] # 计算逻辑表达式的结果 result = int(eval(expression, dict(zip(variables, values)))) # 将取值组合和计算结果转换为字符串,以制表符分隔 row = '\t'.join(map(str, values + [result])) print(row) ``` 通过以上代码,可以得到逻辑表达式真值表。根据实际需要,可以修改变量和表达式的值,以及输出的格式。这种方法可以用来处理任何逻辑表达式的真值判断。 ### 回答2: 要基于Python实现通过真值表判断一个逻辑表达式,可以采取以下步骤: 1. 定义逻辑表达式:首先,可以通过字符串的方式输入逻辑表达式,例如:"A and B or C"。在这个例子中,我们使用了逻辑运算符"and"和"or",以及变量"A"、"B"和"C"。这里假设所有变量的值只有两种可能,即True和False。 2. 生成真值表:接下来,可以通过遍历所有可能的变量取值组合,生成真值表。对于变量"A"、"B"和"C"来说,共有2^3=8种可能的取值组合,可以用进制表示为000, 001, 010, 011, 100, 101, 110, 111。将这些进制数字转换为True和False的组合,就可以得到真值表。 3. 解析逻辑表达式:将逻辑表达式转换为可以计算的形式,例如将"and"转换为"and"操作符,将"or"转换为"or"操作符。可以使用Python中的eval函数来实现此功能。例如,eval("True and False")的结果为False。 4. 计算结果:对于真值表中的每一行,根据逻辑表达式的计算规则,将变量替换为相应的取值,用步骤3中的方法计算逻辑表达式的结果。将结果保存在一个列表中,即可以得到逻辑表达式对于每个取值组合的结果。 5. 输出结果:最后,可以根据结果列表生成输出,例如打印出每个取值组合和对应的结果。 整个过程可以通过编写Python函数来实现,并在主程序中调用该函数进行测试。此外,为了提高程序的可读性和可扩展性,还可以考虑加入输入校验、异常处理和模块化设计等。 ### 回答3: 首先,在Python中实现通过真值表判断一个逻辑表达式,可以采用以下步骤: 1. 创建一个真值表真值表是一个维列表,其中每一行表示一个输入的组合,每一列表示对应输入组合下的输出值。根据逻辑表达式中的变量个数来确定真值表的行数,根据变量可能的取值(True和False)来确定真值表的列数。例如,如果逻辑表达式有两个变量,那么真值表将有4行(2^2)。 2. 获取逻辑表达式:从用户或其他来源获取逻辑表达式,可以通过输入或直接在代码中定义。 3. 解析逻辑表达式:将逻辑表达式解析成运算符和变量的组合。可以使用库函数或自己编写解析函数。 4. 根据解析后的逻辑表达式,计算真值表中每一行对应的输出。 5. 比较计算得到的输出与真值表中的输出,判断逻辑表达式的真值。 以下是通过Python实现上述步骤的示例代码: ```python import itertools def evaluate_expression(expression, values): # 表达式求解逻辑,根据需要自行实现 def get_truth_table(variables): # 根据变量个数获取真值表 n = len(variables) truth_table = list(itertools.product([True, False], repeat=n)) return truth_table def main(): variables = input("请输入逻辑表达式中的变量,以逗号分隔: ").split(",") truth_table = get_truth_table(variables) expression = input("请输入逻辑表达式(使用逻辑运算符): ") for row in truth_table: values = dict(zip(variables, row)) output = evaluate_expression(expression, values) print("输入:{},输出:{}".format(values, output)) if __name__ == "__main__": main() ``` 上述代码示例中,`evaluate_expression`函数实现了表达式求解的逻辑,根据具体的逻辑运算符定义并计算输出值。`get_truth_table`函数用于生成真值表,采用`itertools.product`函数生成变量可能的取值组合。`main`函数获取用户输入的变量和逻辑表达式,并通过循环计算真值表中的每一行对应的输出值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Greate AUK

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值