[数电]用python实现卡诺图化简,自动化简逻辑表达式

化简逻辑表达式时使用的卡诺图,如果通过手工化简,在变量较多时会变得难以处理,容易出错。故笔者编写了如下的自动化简卡诺图脚本,让大家脱离手工化简的苦海。

使用方法:执行后调用AutoKarnaugh(item,bitlen)函数 item:表示使逻辑函数取真的所有最小项的编号的list bitlen:表示逻辑函数变量个数,返回此函数的最简表达式 '-X'表示X取反

如:

>>> AutoKarnaugh([0,1,2,3,4],4)
'-A-C-D+-A-B'

表示此函数最简表达式为\lnot A\lnot C\lnot D+\lnot A\lnot B

算法思路主要是将卡诺图中的找相邻项暴力处理为遍历所有最小项,找到所有只有一个变量不同的项,进而避免图表的处理。写完后发现这个算法其实已经有人发现过了,叫Q-M算法,也体验到了一把跟先辈思路对上了的快乐。

def greyCode(n):
  if n == 1:
     return ['0','1']
  retv=greyCode(n-1)
  retv=retv+list(reversed(retv))
  l=2**(n-1)
  for i in range(l):
    retv[i]='0'+retv[i]
    retv[l+i]='1'+retv[l+i]
  return retv
def code2int(code):
  assert isinstance(code, str)
  ans=0
  cnt=0
  for x in reversed(code):
    ans=ans+(2**cnt if x == '1' else 0)
    cnt+=1
  return ans
def getInput(lis,bitlen):
  assert lis and bitlen<26
  l=len(lis)
  greyDict={}
  codes=[]
  for x in greyCode(bitlen):
    greyDict[code2int(x)]=x
  for x in lis:
    codes.append(greyDict[x])
  return codes
def isNeighbor(a,b):
  assert len(a)==len(b)
  l=len(a)
  cnt=0
  ass=None
  for i in range(l):
    if a[i]=='x' or b[i]=='x':
      if not a[i]==b[i]:
        return None
      continue
    if a[i]!=b[i]:
      cnt+=1
      ass=i
    if cnt>1:
      return None
  return ass
def outputCode(code):
  alphaBeta='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  cnt=0
  ans=''
  for x in code:
    if x=='x':
      cnt+=1
      continue
    if x=='1':
      ans+=alphaBeta[cnt]
    if x=='0':
      ans+='-'+alphaBeta[cnt]
    cnt+=1
  return ans  
def simpify(codes):
  def firstSim(codes):
    if not codes:
      return []
    l=len(codes)
    vis=[False for i in range(l)]
    newcodes=[]
    for i in range(l):
      for j in range(l):
        k=isNeighbor(codes[i], codes[j])
        if k is not None:
          vis[i]=True
          vis[j]=True
          newcodes.append(codes[i][0:k]+'x'+codes[i][k+1:])
    retv=[]
    for i in range(l):
      if not vis[i]:
        retv.append(codes[i])
    return list(set(retv+firstSim(list(set(newcodes)))))
  def secondSim(simpifiedCodes):
    def getCovereds(code):
      retv=[]
      if not 'x' in code:
        return [code]
      for i in range(len(code)):
        if code[i]=='x':
          retv+=getCovereds(code[:i]+'0'+code[i+1:])+getCovereds(code[:i]+'1'+code[i+1:])
      return retv
    coverList=[getCovereds(code) for code in simpifiedCodes]
    isPrime=[False for x in simpifiedCodes] #标记每个蕴含项是否是实质蕴含项
    retv=[] #最终返回的化简项
    for i in range(len(simpifiedCodes)): #找出所有的实质蕴含项
      othercovered=sum(coverList[:i]+coverList[i+1:],[])
      if any([x not in othercovered for x in coverList[i]]): #是实质蕴含项
        retv.append(simpifiedCodes[i]) #加入返回值
        isPrime[i]=True
    primecover=[]
    for i in range(len(isPrime)):
      if isPrime[i]:
        primecover+=coverList[i] #得出所有被实质蕴含项覆盖的最小项
    notcovered=[]
    for x in codes:
      if x not in primecover:
        notcovered.append(x)#得出所有没有被实质蕴含项覆盖的最小项
    nprimecodes=[]#所有非实质蕴含项的质蕴含项的编号
    for i in range(len(isPrime)):
      if not isPrime[i]:
        nprimecodes.append(i)
    def genSubset(lis):
      subset = [[]]
      for x in lis:
          subset.extend([item + [x] for item in subset]) 
      return sorted(subset,key=lambda a:len(a))
    for nprime in genSubset(nprimecodes):
      cover=[]
      for x in nprime:
        cover+=coverList[x]
      if all([item in cover for item in notcovered]):
        retv+=[simpifiedCodes[x] for x in nprime]
        return retv
  return secondSim(firstSim(codes))
    
    
def convertcodes(codes):
  ans=''
  for x in codes:
    ans=ans+outputCode(x)+'+'
  ans=ans[:-1]
  return ans
  
def AutoKarnaugh(items,bitlen):
  '''item:表示使逻辑函数取真的所有最小项的编号的list bitlen:表示逻辑函数变量个数,返回此函数的最简表达式 '-X'表示X取反'''
  return convertcodes(simpify(getInput(items, bitlen)))        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值