基于sympy计算离散数学命题逻辑表达式的真值表、合取/析取范式以及随机生成真值表并由真值表中真值分布求取对应的真值函数或决策函数——在特征组合分类获取特征函数时有用

from sympy import symbols, satisfiable, simplify_logic, true, false, And, Or, Not
from sympy.logic.boolalg import ANFform, truth_table, BooleanTrue, to_cnf, to_dnf
# Sum Of Production Form积和式, Production of Sum Form和积式
from sympy.logic import SOPform, POSform 
import numpy as np
from itertools import combinations

# 逻辑运算符:~否定,&合取,|析取,!=异或,>>蕴含,==等价

# 定义符号变量
p, q, r = symbols('p q r')
# 定义命题逻辑表达式
exp = (p | q >> r) >> p

# 用真值表法输出表达式的所有值
table = truth_table(exp, [p, q, r])
print('真值表')
print('p q r -> exp')
print('-' * 15)
for t in table:
    [pv, qv, rv], rst = t
    print(pv, qv, rv, '->', int(rst == true))
    
# 判断表达式的可满足性并求解
print('逻辑表达式可满足性判别并求解')
models = satisfiable(exp, all_models=True)
if models:
    rst = list(models)
    data = []
    varNames = []
    for dv in rst:
        if len(varNames) == 0:
            varNames = list(dv.keys())
        data.append([int(v) for v in list(dv.values())])
        #rst.append([dv[p], dv[q], dv[r]])
    print([ch for ch in varNames])
    print('-' * 15)
    data = np.array(data, int)    
    print(data)

# 获取表达式的合取范式和析取范式(非标准)    
# conjunctive normal form 和 disjunctive normal form
print('合取范式cnf=', simplify_logic(exp, 'cnf'))
print('析取范式dnf=', simplify_logic(exp, 'dnf'))
print('合取范式cnf=', to_cnf(exp))
print('析取范式dnf=', to_dnf(exp))

# 由随机真值表确定响应的真值函数——决策函数
# 动态定义4个变量——A,B,C,D
nVars = 4
vars = [chr(97 + i) for i in range(nVars)]
code = ','.join(vars) + " = symbols('" + ' '.join(vars) + "')"
print('code=', code)
exec(code)      #运行生成的代码code,以动态创建变量
# 生成变量的2 ** nVars个01的值组合
tbl = []
for i in range(2**nVars):
    bins = bin(i)[2:]
    bins = '0' * (nVars - len(bins)) + bins
    bins = [int(v) for v in bins]
    tbl.append(bins)
tbl = np.array(tbl, int)
# 随机生成y值表,并记录值为True的行号
yTrueIdx = [i for i, v in enumerate(np.random.randint(0, 2, (2 ** nVars))) if v == 1]
# 由真值表获得对应的赋值项
minterms = []
for rowno in yTrueIdx:
    minterms.append(list(tbl[rowno, :]))
print('最小项', minterms)
dontcares = []  #不关心项
# 取得由真值表所确定的真值决策函数表达式字符串
f1 = SOPform(vars, minterms, dontcares) #积和式
print('函数SOP形=', f1)
f2 = POSform(eval(','.join(vars)), minterms, dontcares) #积和式
print('函数POS形=', f2)

# 把变量名转换为数组索引
f3 = str(f1)
# 把f3中的个体变量名都更新为xs的数组下标表示
for i, var in enumerate(vars):
    f3 = f3.replace(vars[i], 'xs[%d]' % (i))
# 注意:由于sympy中的~逻辑运算在python中是位运算,故~-1=-2,导致不是严密的逻辑运算    
# 因此,需要把sympy中的逻辑运算符替换为python语言的逻辑运算符
f3 = f3.replace('~', ' not ')    
f3 = f3.replace('&', ' and ')    
f3 = f3.replace('|', ' or ')    
print('数组表示的f3=', f3)    
# 由f3结合lambda表达式以动态创建函数 
# f3= (xs[1]  and  xs[3]  and   not xs[2])  or  (xs[3]  and   not xs[0]  and   not xs[2])  or  (xs[1]  and  xs[2]  and   not xs[0]  and   not xs[3])
F3 = eval('lambda  xs : ' + str(f3))
# 把minterms中的项代入计算,检查是否不等于0
for no, row in enumerate(tbl):    
    value = True if no in yTrueIdx else False
    val = F3(row)
    print(no, row, int(value), int(val), 'Ok' if int(value) == int(val) else 'Err')

运行结果:

真值表
p q r -> exp
---------------
0 0 0 -> 0
0 0 1 -> 0
0 1 0 -> 1
0 1 1 -> 0
1 0 0 -> 1
1 0 1 -> 1
1 1 0 -> 1
1 1 1 -> 1
逻辑表达式可满足性判别并求解
[r, p, q]
---------------
[[0 1 1]
 [0 1 0]
 [0 0 1]
 [1 1 1]
 [1 1 0]]
合取范式cnf= (p | q) & (p | ~r)
析取范式dnf= p | (q & ~r)
合取范式cnf= (p | q) & (p | ~p) & (p | ~r)
析取范式dnf= p | (q & ~p & ~r)
code= a,b,c,d = symbols('a b c d')
最小项 [[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 0, 1, 1], [0, 1, 0, 1], [0, 1, 1, 0], [1, 0, 1, 0], [1, 1, 0, 1]]
函数SOP形= (~a & ~b) | (b & d & ~c) | (c & ~a & ~d) | (c & ~b & ~d)
函数POS形= (b | c | ~a) & (c | d | ~b) & (b | ~a | ~d) & (d | ~a | ~b) & (~b | ~c | ~d)
数组表示的f3= ( not xs[0]  and   not xs[1])  or  (xs[1]  and  xs[3]  and   not xs[2])  or  (xs[2]  and   not xs[0]  and   not xs[3])  or  (xs[2]  and   not xs[1]  and   not xs[3])
0 [0 0 0 0] 1 1 Ok
1 [0 0 0 1] 1 1 Ok
2 [0 0 1 0] 1 1 Ok
3 [0 0 1 1] 1 1 Ok
4 [0 1 0 0] 0 0 Ok
5 [0 1 0 1] 1 1 Ok
6 [0 1 1 0] 1 1 Ok
7 [0 1 1 1] 0 0 Ok
8 [1 0 0 0] 0 0 Ok
9 [1 0 0 1] 0 0 Ok
10 [1 0 1 0] 1 1 Ok
11 [1 0 1 1] 0 0 Ok
12 [1 1 0 0] 0 0 Ok
13 [1 1 0 1] 1 1 Ok
14 [1 1 1 0] 0 0 Ok
15 [1 1 1 1] 0 0 Ok

总结:

使用sympy实施命题逻辑变量的定义及表达式的可满足性求解;

进一步,随机生成真值表,利用sympy的积和形或和积形表达方式获取对应真值表的决策函数符号表达式(其本质相当于实现了二值分类)——相当于决策表算法;利用这一特性,可对多元特征的选取提供简练选择方法.

方法特点在于简练——进一步用途,需要读者深入思考.

你可能感兴趣的:(Python,人工智能,机器学习,python,人工智能,程序人生,离散数学,逻辑决策优化函数)