Q-M法,python自动化简逻辑表达式,卡诺图化简。

 Q-M算法:算法思路主要是将卡诺图中的找相邻项暴力处理为遍历所有最小项,找到所有只有一个变量不同的项,进而避免图表的处理。

如果算法有错误欢迎留言,我会及时修改。

下面代码将用Q-M算法实现:

      下面代码提供3个主函数:

def logic_random_mini(n):随机生成一个n个逻辑变量的真值表,真值表由,使逻辑函数取真的所有最小项的编号组成的列表,描述。
def logic_func_to_mini(mu):将一个书面逻辑函数转化成真值表。比如“-A+B+C-B”,除‘-’和‘+’外,所有符号(包括汉字)都被视作逻辑函数中出现的变量名,‘-’表示对右边第一个的变量的布尔值取反

def logic_mini_to_simplify_func(mini, key):根据真值表生成最简洁的书面逻辑函数,输出形式与第二个函数的输入形式一致。

Q-M融合是指:两个项只有一个逻辑变量的取值不同,就可以合并成一个项。新的项具体为老的项的那个相互不同的逻辑变量取‘-’,也就是随便0或1

然后这整段代码运行效果是:

最开始等待一次键盘输入,如果输入了一个数字,则随机随机生成一个n个逻辑变量的真值表,接着进行求解。否则根据输入的字符串生成真值表,接着求解。

求解过程中,每一轮的Q-M融合循环中。程序会打印出有资格参加下一轮Q-M融合循环的项,每一轮的Q-M融合循环的间隙,程序也会打印剩下的还有可能Q-M融合的项的个数,和不可能再Q-M融合的项的个数。

最后输出最简洁的书面逻辑函数。

程序结束

import random


# logic_random_mini()用于随机生成一个n个逻辑变量的真值表,真值表由,使逻辑函数取真的所有最小项的编号组成的列表,描述。
def logic_random_mini(n):  # n表示逻辑函数变量个数
    ans = []
    for i in range(2 ** n):
        if random.random() < 0.5:
            ans.append(i)
    st = ord('A')
    ans1 = []
    for i in range(n):
        ans1.append(chr(st))
        st += 1
    return ans, ans1  # ans:使逻辑函数取真的所有最小项的编号组成的列表,ans1:顺序排列的变量名组成的列表,这里设定从字母表里按顺序取。


# logic_func_to_mini()用于把书面的逻辑函数,转化成真值表,并用使逻辑函数取真的所有最小项的编号的列表来表示。并记录逻辑函数中出现的变量名。
def logic_func_to_mini(mu):  # mu:书面的逻辑函数字符串,比如“-A+B+C-B”,除‘-’和‘+’外,所有符号都被视作逻辑函数中出现的变量名,‘-’表示对右边第一个的变量的布尔值取反
    key = ['-', '+']
    for i in mu:
        if i not in key:
            key.append(i)
    key = key[2:]
    val = {}
    for i in key:
        val[i] = False
    n = len(key)
    p = 2 ** n
    ans = []

    def calcu():  # 以目前val中储存的所有逻辑变量的取值,计算mu描述的逻辑函数的值,并返回
        pre = False
        new = True
        gv = False
        for i in mu:
            if i == '-':
                gv = True
            elif i == '+':
                pre = pre or new
                new = True
            else:
                if gv:
                    new = not (val[i]) and new
                    gv = False
                else:
                    new = val[i] and new
        return pre or new

    def step():  # 按2进制步进的形式改变所有逻辑变量的取值,如“0000’-->'1000'-->'0100'-->'1100'-->'0010'-->-->--->'1111'(最终)
        def jj(a):
            if a >= n:
                return
            if val[key[a]]:
                val[key[a]] = False
                jj(a + 1)
            else:
                val[key[a]] = True

        jj(0)

    def load():  # 将当前val中储存的所有的逻辑变量的取值情况,转化成对应的最小项的序号,储存进ans中。
        pp = 0
        for i in range(n - 1, -1, -1):
            pp *= 2
            if val[key[i]]:
                pp += 1
        ans.append(pp)

    while p > 0:
        if calcu():
            load()
        step()
        p -= 1
    return ans, key  # ans:使逻辑函数取真的所有最小项的编号组成的列表,ans1:顺序排列的变量名组成的列表。


# logic_mini_to_simplify_func()用于将一个使逻辑函数取真的所有最小项的编号的列表和一个变量名列表,还原成最简洁的书面逻辑函数。恒为0将返回‘_0_',恒为1将返回‘_1_'
def logic_mini_to_simplify_func(mini, key):  # mini:使逻辑函数取真的所有最小项的编号的列表,key:变量名列表
    ku = []
    n = len(key)

    def mini_to_num(a):  # 将最小项的编号转化成真值表变量的0或1,用列表表示。
        rr = []
        b = n
        while b > 0:
            if a % 2 == 1:
                rr.append(True)
            else:
                rr.append(False)
            a = a // 2
            b -= 1
        return rr

    for i in mini:  # 将mini转化成二维的bool类型的数组,来表示所有使逻辑函数取真的变量的取值情况。保存在ku中。
        ku.append(mini_to_num(i))

    def circel():  # 使ku中的项,按Q-M法合并。(不懂Q-M法的,百度一下)
        def check(i, j):  # 检查ku中第i个和第j个项,是否只有一个变量不同。是的话,返回唯一不同的变量下表。不是的话,返回-1.
            ord = -1
            for k in range(n):
                if ku[i][k] == ku[j][k]:
                    continue
                else:
                    if ord >= 0:
                        return -1
                    else:
                        ord = k
            return ord

        lp = len(ku)
        last = [True for i in range(lp)]
        oih = []
        uh = False
        for i in range(lp - 1):  # 将ku中的所有项相互检查是否只有一个变量不一样,是的话将只有一个变量不一样两个项融合后的结果不重复地保存在oih中。(这是程序主要的时间花费,这里可以设置成并行运行,或者彻底改变合并筛查算法,来提高效率。本人写的是最低级最暴力的遍历,最浪费时间。)
            oij = True
            for j in range(i + 1, lp):
                op = check(i, j)
                if op == -1:
                    continue
                else:
                    last[i] = False
                    last[j] = False
                    jiji = ku[i].copy()
                    jiji[op] = '-'
                    if jiji not in oih:
                        oih.append(jiji)
                        print(jiji, end='', flush=True)
                    oij = False
            if oij:
                pass
            else:
                uh = True
        for i in range(lp):
            if last[i]:
                oldlady.append(ku[i])  # 将没人要的项保存在oldlady中,不再参与循环,因为错过了同龄人,就不可能有人要了。
                print(ku[i], end='', flush=True)
        ku.clear()
        ku.extend(oih)  # 将oih取代原来的ku,准备新的一轮
        return uh  # 如果一次circle()没有任何项能够融合,说明已经化简到最简洁。返回False,打破循环。

    def read(zu):  # 将ku中一个项,根据key中变量的顺序,转化成书面形式。
        ret = ''
        for i in range(n):
            if zu[i] == '-':
                continue
            elif zu[i] == 1:
                ret = ret + key[i]
            else:
                ret = ret + '-' + key[i]
        return ret

    oldlady = []
    while circel():  # 使ku中的项,按Q-M法合并。(不懂Q-M法的,百度一下)
        print()
        print(len(ku), len(oldlady), sep='+')
    oldlady.extend(ku)
    ans = ""
    for i in oldlady:  # 将剩下的无法融合的项,即最终答案,转化为书面形式输出
        ans = ans + read(i) + '+'
    print("\n")
    if ans[:-1] == '':
        return "_1_"
    return ans[:-1]  # 输出最简洁书面逻辑函数


pp = input()
try:
    a, b = logic_random_mini(int(pp))
except ValueError:
    a, b = logic_func_to_mini(pp)
print(a, b)
print(logic_mini_to_simplify_func(a, b))

  • 15
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值