CNF_py

L3

domain.pddl

(define (problem line-0)
(:domain line)
(:objects 
    L1 - location
    L2 - location
    L3 - location
)
(:init
    (person-at L1)

    (road L1 L2)
    (road L2 L1)
    (road L3 L2)
    (road L2 L3)
)
(:goal (person-at L3))
)

problem 3 grid move right

; Stupid Examples for me to understand this programe 

(define (domain line)
  (:requirements :typing)
  (:types location)
  (:predicates (person-at ?loc - location)
               (road ?from - location ?to - location)
  )            
  (:action move-right
    :parameters (?from - location ?to - location)
    :precondition (and (person-at ?from) (road ?from ?to))
    :effect (and (person-at ?to) (not (person-at ?from)))
  )
)
/src$ python  main.py ../mystupidroad/domain.pddl  ../mystupidroad/stupid.pddl -strong 1 -policy 1

观察传入my_task的数据结构都有什么输入:

p.generate_task(name_sas_file) #读取sas文件,保存数据
>>> my_task = p.translate_to_atomic() #存进my_task类的实例对象my_task中,自动输出界面的内容
Setting atoms
# Atoms: 3
Setting initial
Setting goal
Setting actions
# Actions: 4
        Setting other actions
(0, '/', 4)
        Setting action card
Setting mutexes
Setting relevant actions
Setting splitting
Setting compatible actions
(0, '/', 4)
0.00387597084045

查看my_task类中的局部变量

class MyTask():
    def __init__(self):
        self.atoms = None # Set
        self.initial = None # Set of atoms
        self.goal = None # Set of atoms
        self.actions = None # Dictionary, name --> [precs, adds, dels]
        self.action_nondet = {} # name --> list other actions
        self.action_cardinality = {} # name --> number
        self.mutex_groups = None # list of list; each sub-list has atoms belonging to the same mutex group
        self.compatible_actions = {} # action name --> set of compatible actions
        self.mutex_groups_set = [] # list of sets of mutex groups
        self.relevant_actions_atom = {} # dictionary: atom --> relevant actions
        self.relevant_actions_atom_aname = {} # dictionary: (atom, a_name) --> relevant actions
        self.action_names = None # set
        self.other_actions_name = {} # Dictionary name --> list of other actions
        self.action_name_to_actions = {} # action_name --> list of actions
        ......
    def is_fair(self):
        for a in self.actions:
            if '_unfair_' in a:
                return False
        return True
        ......

在Parser类的方法中翻译成,保存成mytask类的数据,可以根据myTask.py定义的方法

    def print_task(self):
        print('ATOMS ================================================')
        for a in self.atoms:
            print(a)
        print('INITIAL ==============================================')
        for a in self.initial:
            print(a)
        print('GOAL =================================================')
        for a in self.goal:
            print(a)
        print('ACTIONS ==============================================')
        for a in self.actions:
            print(a, self.get_other_actions(a))
            print(a, self.actions[a])

打印出来看

>>> my_task.print_task()
ATOMS ================================================
(var0=1)
(var0=2)
(var0=0)
INITIAL ==============================================
(var0=0)
GOAL =================================================
(var0=2)
ACTIONS ==============================================
('move-right(l2,l3)', [])
('move-right(l2,l3)', [['(var0=1)'], ['(var0=2)'], ['(var0=1)']])
('move-right(l2,l1)', [])
('move-right(l2,l1)', [['(var0=1)'], ['(var0=0)'], ['(var0=1)']])
('move-right(l1,l2)', [])
('move-right(l1,l2)', [['(var0=0)'], ['(var0=1)'], ['(var0=0)']])
('move-right(l3,l2)', [])
('move-right(l3,l2)', [['(var0=2)'], ['(var0=1)'], ['(var0=2)']])

>>> print(my_task.action_nondet)
{'move-right(l1,l2)': [], 'move-right(l3,l2)': [], 'move-right(l2,l3)': [], 'move-right(l2,l1)': []}
>>> print(my_task.action_cardinality)
{'move-right(l1,l2)': 1, 'move-right(l3,l2)': 1, 'move-right': 1, 'move-right(l2,l3)': 1, 'move-right(l2,l1)': 1}
>>> print(my_task.mutex_groups)
[['(var0=0)', '(var0=1)', '(var0=2)']]
>>> print(my_task.compatible_actions)
{'move-right(l1,l2)': set([]), 'move-right(l3,l2)': set([]), 'move-right(l2,l3)': set(['move-right(l2,l1)']), 'move-right(l2,l1)': set(['move-right(l2,l3)'])}
>>> print(my_task.mutex_groups_set)
[set(['(var0=1)', '(var0=2)', '(var0=0)'])]
>>> print(my_task.relevant_actions_atom)
{'(var0=1)': set(['move-right(l1,l2)', 'move-right(l3,l2)', 'move-right(l2,l3)', 'move-right(l2,l1)']), '(var0=2)': set(['move-right(l2,l3)', 'move-right(l3,l2)']), '(var0=0)': set(['move-right(l1,l2)', 'move-right(l2,l1)'])}
>>> print(my_task.relevant_actions_atom_aname)
{}
>>> print(my_task.action_names)
set(['move-right'])
>>> print(my_task.other_actions_name)
{'move-right': []}
>>> print(my_task.action_name_to_actions)
{'move-right': ['move-right(l2,l3)', 'move-right(l2,l1)', 'move-right(l1,l2)', 'move-right(l3,l2)']}
parser.py中p.translate_to_atomic函数就是生成上述my_task数据结构对象的元凶

    task = MyTask()
    debug = False#这个应该是开发的时候方便调试可以设置True
    print('Setting atoms')#原子命题
    task.set_atoms(self.get_atoms(), debug)
    print('Setting initial')#初态
    task.set_initial(self.get_initial_atomic(), debug)
    print('Setting goal')#终态
    task.set_goal(self.get_goal_atomic(), debug)
    print('Setting actions')#设定动作
    task.set_actions_atomic(self.get_actions_atomic(), debug)
    print('Setting mutexes')#设定互斥量?
    task.set_mutex_groups(self.get_mutex_groups_atomic(), debug)
    print('Setting relevant actions')#设置相关动作
    task.set_relevant_actions(debug)
    print('Setting splitting')#分裂
    task.initialize_splitting(debug)
    start = timer()
    print('Setting compatible actions')#设置相容可以并存的动作
    task.create_compatible_actions(debug)
    print(timer() - start)
    return task

然后就是main.py大循环就是高潮部分:留意重点:

solver_time = []
for i in range(1000):
    cnf = CNF(name_formula_file, name_formula_file_extra, fair, strong)#文件formula-temp.txt这时候是空白的,formula-extra-temp此时空白,仅仅是传入地址方便最终结果存入数据
    ......
    cnf.reset()
    start_g = timer()
    cnf.generate_clauses(my_task, 'n0', 'ng', controllerStates, len(controllerStates), p, show_gen_info)#生成子句Clauses和写入cnf文件合取范式的核心代码!!!
传入字符'n0', 终态'ng'
>>> print(controllerStates)
['n0', 'n1', 'ng']这个是3格的情况,2格的时候是['n0','ng']
>>> len(controllerStates)
3
>>> print(show_gen_info)
False懒得显示这部分,因为和我要关心的重点没关系
这里的p是Parser实例,可能用里面的方法,因为基本看着都是私有变量
    ......
    command = './minisat %s %s' % (name_formula_file, name_output_satsolver)#调用minisat
    ......
    result = cnf.parseOutput(name_output_satsolver, controllerStates, p, print_policy)#读取文件name_output_satsolver : outsat-temp.txt输出结果
    ......

CNF

重要的是再来一遍,main.py大循环就是高潮部分:留意重点:

solver_time = []
for i in range(1000):
    cnf = CNF(name_formula_file, name_formula_file_extra, fair, strong)#文件formula-temp.txt这时候是空白的,formula-extra-temp此时空白,仅仅是传入地址方便最终结果存入数据
    ......
    cnf.reset()
    start_g = timer()
    #唯一重点,一行代码
    cnf.generate_clauses(my_task, 'n0', 'ng', controllerStates, len(controllerStates), p, show_gen_info)
    #生成子句Clauses和写入cnf文件合取范式的核心代码!!!
    ......
    command = './minisat %s %s' % (name_formula_file, name_output_satsolver)#调用minisat
    ......
    result = cnf.parseOutput(name_output_satsolver, controllerStates, p, print_policy)#读取文件name_output_satsolver : outsat-temp.txt输出结果
    ......

运行结果是>>> print(result) True

然后是cnf对象的数据结构和变量,函数,类和方法

class CNF:
    type1 = 'Atom-Controller'
    type2 = 'Action-Controller'
    type3 = 'Triplet'
    type4 = 'Reachable-I'
    type5 = 'Reachable-G'
    type6 = 'Replacement-Goal'
    type7 = 'Controller-Controller'
    type8 = 'Replacement-Equality'
    type9 = 'Inequality-CSCS'
    type10 = 'Replacement-Goal'
    num_types = 18#这些静态变量定义完了
    print_types = [1, 2, 3, 7]#?代表参数选项,想打印出来什么结果吗

    def __init__(self, n_file, n_file_extra, fair, strong):
        self.disjunctions = [] # list of disjunctions
        self.maxKey = 1
        self.mapVariableNumber = {}
        self.mapNumberVariable = {}
        self.mapVariableType = {}
        self.clauseSizeCounter = {}
        self.name_file_formula = n_file
        self.name_file_formula_extra = n_file_extra
        self.file_formula = open(n_file, 'w')
        self.file_formula_extra = open(n_file_extra, 'w')
        self.file_formula.close()
        self.file_formula_extra.close()
        self.number_clauses = 0
        self.fair   = fair
        self.strong = strong

    def reset(self):
        self.disjunctions = [] # list of disjunctions
        self.maxKey = 1
        self.mapVariableNumber = {}
        self.mapNumberVariable = {}
        self.mapVariableType = {}
        self.clauseSizeCounter = {}
        self.file_formula = open(self.name_file_formula, 'w')
        self.file_formula.write('p cnf 1 1\n')
        self.file_formula_extra = open(self.name_file_formula_extra, 'a')
        # File formula extra is not used, can be ignored
        self.number_clauses = 0
    ......

然后看看运行完结果,其实加断点可以看第一次循环的结果,

结果就是第二遍循环之后的这些量是多少:

>>> print(cnf.disjunctions)
[]
>>> print(cnf.maxKey)
67
>>> print(cnf.mapVariableNumber)
{'reachableG(ng,0)': 49, '(var0=2)(ng)': 3, 'YR1-n1-ng-1': 66, '(n1,move-right(l1,l2))': 12, 'reachableG(ng,1)': 50, '(ng,move-right,n0)': 31, '(n1,move-right,ng)': 30, '(ng,move-right(l1,l2))': 19, 'YR1-n0-n0-0': 55, '(n1,move-right,n1)': 29, '(ng,ng)': 42, 'reachableG(n1,1)': 54, '(n0,move-right)': 22, '(n0,move-right(l2,l3))': 4, '(var0=1)(n1)': 10, '(ng,move-right(l2,l1))': 18, 'YR1-n0-n0-1': 61, '(ng,move-right(l2,l3))': 16, '(n1,move-right,n0)': 28, 'YR1-n1-n0-0': 58, '(n0,move-right,n1)': 26, '(n1,move-right(l3,l2))': 14, 'reachableI(ng)': 45, '(n1,n1)': 38, '(n1,ng)': 39, '(var0=0)(n1)': 13, '(ng,move-right(l3,l2))': 21, 'YR1-n1-n1-1': 65, 'reachableI(n0)': 43, '(var0=2)(n1)': 15, '(var0=0)(n0)': 7, '(ng,move-right)': 24, '(n0,n0)': 34, '(n0,move-right,ng)': 27, 'YR1-n1-n0-1': 64, 'YR1-n0-ng-0': 57, 'reachableG(n1,0)': 52, 'YR1-n1-n1-0': 59, '(n1,n0)': 37, '(var0=0)(ng)': 20, 'YR1-n0-ng-1': 63, '(ng,move-right,n1)': 32, 'reachableI(n1)': 44, '(ng,n1)': 41, 'reachableG(n1,2)': 47, 'YR1-n0-n1-1': 62, '(var0=1)(n0)': 1, '(n0,move-right(l2,l1))': 5, '(n1,move-right(l2,l1))': 11, '(n0,ng)': 36, '(n0,move-right,n0)': 25, '(ng,n0)': 40, 'YR1-n1-ng-0': 60, 'reachableG(n0,0)': 51, '(var0=1)(ng)': 17, '(n0,move-right(l1,l2))': 6, '(n1,move-right)': 23, 'reachableG(n0,2)': 46, '(n0,move-right(l3,l2))': 8, 'reachableG(n0,1)': 53, 'YR1-n0-n1-0': 56, '(n1,move-right(l2,l3))': 9, '(ng,move-right,ng)': 33, 'reachableG(ng,2)': 48, '(var0=2)(n0)': 2, '(n0,n1)': 35}
>>> print(cnf.mapNumberVariable)
{1: '(var0=1)(n0)', 2: '(var0=2)(n0)', 3: '(var0=2)(ng)', 4: '(n0,move-right(l2,l3))', 5: '(n0,move-right(l2,l1))', 6: '(n0,move-right(l1,l2))', 7: '(var0=0)(n0)', 8: '(n0,move-right(l3,l2))', 9: '(n1,move-right(l2,l3))', 10: '(var0=1)(n1)', 11: '(n1,move-right(l2,l1))', 12: '(n1,move-right(l1,l2))', 13: '(var0=0)(n1)', 14: '(n1,move-right(l3,l2))', 15: '(var0=2)(n1)', 16: '(ng,move-right(l2,l3))', 17: '(var0=1)(ng)', 18: '(ng,move-right(l2,l1))', 19: '(ng,move-right(l1,l2))', 20: '(var0=0)(ng)', 21: '(ng,move-right(l3,l2))', 22: '(n0,move-right)', 23: '(n1,move-right)', 24: '(ng,move-right)', 25: '(n0,move-right,n0)', 26: '(n0,move-right,n1)', 27: '(n0,move-right,ng)', 28: '(n1,move-right,n0)', 29: '(n1,move-right,n1)', 30: '(n1,move-right,ng)', 31: '(ng,move-right,n0)', 32: '(ng,move-right,n1)', 33: '(ng,move-right,ng)', 34: '(n0,n0)', 35: '(n0,n1)', 36: '(n0,ng)', 37: '(n1,n0)', 38: '(n1,n1)', 39: '(n1,ng)', 40: '(ng,n0)', 41: '(ng,n1)', 42: '(ng,ng)', 43: 'reachableI(n0)', 44: 'reachableI(n1)', 45: 'reachableI(ng)', 46: 'reachableG(n0,2)', 47: 'reachableG(n1,2)', 48: 'reachableG(ng,2)', 49: 'reachableG(ng,0)', 50: 'reachableG(ng,1)', 51: 'reachableG(n0,0)', 52: 'reachableG(n1,0)', 53: 'reachableG(n0,1)', 54: 'reachableG(n1,1)', 55: 'YR1-n0-n0-0', 56: 'YR1-n0-n1-0', 57: 'YR1-n0-ng-0', 58: 'YR1-n1-n0-0', 59: 'YR1-n1-n1-0', 60: 'YR1-n1-ng-0', 61: 'YR1-n0-n0-1', 62: 'YR1-n0-n1-1', 63: 'YR1-n0-ng-1', 64: 'YR1-n1-n0-1', 65: 'YR1-n1-n1-1', 66: 'YR1-n1-ng-1'}
>>> print(cnf.mapVariableType)
{'reachableG(ng,0)': 5, '(var0=2)(ng)': 1, 'YR1-n1-ng-1': 6, '(n1,move-right(l1,l2))': 2, 'reachableG(ng,1)': 5, '(ng,move-right,n0)': 3, '(n1,move-right,ng)': 3, '(ng,move-right(l1,l2))': 2, 'YR1-n0-n0-0': 6, '(n1,move-right,n1)': 3, '(ng,ng)': 7, 'reachableG(n1,1)': 5, '(n0,move-right)': 2, '(n0,move-right(l2,l3))': 2, '(var0=1)(n1)': 1, '(ng,move-right(l2,l1))': 2, 'YR1-n0-n0-1': 6, '(ng,move-right(l2,l3))': 2, '(n1,move-right,n0)': 3, 'YR1-n1-n0-0': 6, '(n0,move-right,n1)': 3, '(n1,move-right(l3,l2))': 2, 'reachableI(ng)': 4, '(n1,n1)': 7, '(n1,ng)': 7, '(var0=0)(n1)': 1, '(ng,move-right(l3,l2))': 2, 'YR1-n1-n1-1': 6, 'reachableI(n0)': 4, '(var0=2)(n1)': 1, '(var0=0)(n0)': 1, '(ng,move-right)': 2, '(n0,n0)': 7, '(n0,move-right,ng)': 3, 'YR1-n1-n0-1': 6, 'YR1-n0-ng-0': 6, 'reachableG(n1,0)': 5, 'YR1-n1-n1-0': 6, '(n1,n0)': 7, '(var0=0)(ng)': 1, 'YR1-n0-ng-1': 6, '(ng,move-right,n1)': 3, 'reachableI(n1)': 4, '(ng,n1)': 7, 'reachableG(n1,2)': 5, 'YR1-n0-n1-1': 6, '(var0=1)(n0)': 1, '(n0,move-right(l2,l1))': 2, '(n1,move-right(l2,l1))': 2, '(n0,ng)': 7, '(n0,move-right,n0)': 3, '(ng,n0)': 7, 'YR1-n1-ng-0': 6, 'reachableG(n0,0)': 5, '(var0=1)(ng)': 1, '(n0,move-right(l1,l2))': 2, '(n1,move-right)': 2, 'reachableG(n0,2)': 5, '(n0,move-right(l3,l2))': 2, 'reachableG(n0,1)': 5, 'YR1-n0-n1-0': 6, '(n1,move-right(l2,l3))': 2, '(ng,move-right,ng)': 3, 'reachableG(ng,2)': 5, '(var0=2)(n0)': 1, '(n0,n1)': 7}
>>> print(cnf.clauseSizeCounter)
{}
>>> print(cnf.name_file_formula)
formula-temp.txt
>>> print(cnf.name_file_formula_extra)
formula-extra-temp.txt
>>> print(cnf.number_clauses)
234
>>> print(cnf.fair)
True
>>> print(cnf.strong)
True

上面这个数据整理一下格式:

>>> print(cnf.mapVariableNumber)
{'reachableG(ng,0)': 49,
 '(var0=2)(ng)': 3,
 'YR1-n1-ng-1': 66,
 '(n1,move-right(l1,l2))': 12,
 'reachableG(ng,1)': 50,
 '(ng,move-right,n0)': 31,
 '(n1,move-right,ng)': 30,
 '(ng,move-right(l1,l2))': 19,
 'YR1-n0-n0-0': 55,
 '(n1,move-right,n1)': 29,
 '(ng,ng)': 42,
 'reachableG(n1,1)': 54,
 '(n0,move-right)': 22,
 '(n0,move-right(l2,l3))': 4,
 '(var0=1)(n1)': 10,
 '(ng,move-right(l2,l1))': 18,
 'YR1-n0-n0-1': 61,
 '(ng,move-right(l2,l3))': 16,
 '(n1,move-right,n0)': 28,
 'YR1-n1-n0-0': 58,
 '(n0,move-right,n1)': 26,
 '(n1,move-right(l3,l2))': 14,
 'reachableI(ng)': 45,
 '(n1,n1)': 38,
 '(n1,ng)': 39,
 '(var0=0)(n1)': 13,
 '(ng,move-right(l3,l2))': 21,
 'YR1-n1-n1-1': 65,
 'reachableI(n0)': 43,
 '(var0=2)(n1)': 15,
 '(var0=0)(n0)': 7,
 '(ng,move-right)': 24,
 '(n0,n0)': 34,
 '(n0,move-right,ng)': 27,
 'YR1-n1-n0-1': 64,
 'YR1-n0-ng-0': 57,
 'reachableG(n1,0)': 52,
 'YR1-n1-n1-0': 59,
 '(n1,n0)': 37,
 '(var0=0)(ng)': 20,
 'YR1-n0-ng-1': 63,
 '(ng,move-right,n1)': 32,
 'reachableI(n1)': 44,
 '(ng,n1)': 41,
 'reachableG(n1,2)': 47,
 'YR1-n0-n1-1': 62,
 '(var0=1)(n0)': 1,
 '(n0,move-right(l2,l1))': 5,
 '(n1,move-right(l2,l1))': 11,
 '(n0,ng)': 36,
 '(n0,move-right,n0)': 25,
 '(ng,n0)': 40,
 'YR1-n1-ng-0': 60,
 'reachableG(n0,0)': 51,
 '(var0=1)(ng)': 17,
 '(n0,move-right(l1,l2))': 6,
 '(n1,move-right)': 23,
 'reachableG(n0,2)': 46,
 '(n0,move-right(l3,l2))': 8,
 'reachableG(n0,1)': 53,
 'YR1-n0-n1-0': 56,
 '(n1,move-right(l2,l3))': 9,
 '(ng,move-right,ng)': 33,
 'reachableG(ng,2)': 48,
 '(var0=2)(n0)': 2,
 '(n0,n1)': 35}


>>> print(cnf.mapNumberVariable)
{
1: '(var0=1)(n0)', 
2: '(var0=2)(n0)', 
3: '(var0=2)(ng)', 
4: '(n0,move-right(l2,l3))', 
5: '(n0,move-right(l2,l1))', 
6: '(n0,move-right(l1,l2))', 
7: '(var0=0)(n0)', 
8: '(n0,move-right(l3,l2))', 
9: '(n1,move-right(l2,l3))', 
10: '(var0=1)(n1)', 
11: '(n1,move-right(l2,l1))', 
12: '(n1,move-right(l1,l2))', 
13: '(var0=0)(n1)', 
14: '(n1,move-right(l3,l2))', 
15: '(var0=2)(n1)', 
16: '(ng,move-right(l2,l3))', 
17: '(var0=1)(ng)', 
18: '(ng,move-right(l2,l1))', 
19: '(ng,move-right(l1,l2))', 
20: '(var0=0)(ng)', 
21: '(ng,move-right(l3,l2))', 
22: '(n0,move-right)', 
23: '(n1,move-right)', 
24: '(ng,move-right)', 
25: '(n0,move-right,n0)', 
26: '(n0,move-right,n1)', 
27: '(n0,move-right,ng)', 
28: '(n1,move-right,n0)', 
29: '(n1,move-right,n1)', 
30: '(n1,move-right,ng)', 
31: '(ng,move-right,n0)', 
32: '(ng,move-right,n1)', 
33: '(ng,move-right,ng)', 
34: '(n0,n0)', 
35: '(n0,n1)', 
36: '(n0,ng)', 
37: '(n1,n0)', 
38: '(n1,n1)', 
39: '(n1,ng)', 
40: '(ng,n0)', 
41: '(ng,n1)', 
42: '(ng,ng)', 
43: 'reachableI(n0)', 
44: 'reachableI(n1)', 
45: 'reachableI(ng)', 
46: 'reachableG(n0,2)', 
47: 'reachableG(n1,2)', 
48: 'reachableG(ng,2)', 
49: 'reachableG(ng,0)', 
50: 'reachableG(ng,1)', 
51: 'reachableG(n0,0)', 
52: 'reachableG(n1,0)', 
53: 'reachableG(n0,1)', 
54: 'reachableG(n1,1)', 
55: 'YR1-n0-n0-0', 
56: 'YR1-n0-n1-0', 
57: 'YR1-n0-ng-0', 
58: 'YR1-n1-n0-0', 
59: 'YR1-n1-n1-0', 
60: 'YR1-n1-ng-0', 
61: 'YR1-n0-n0-1', 
62: 'YR1-n0-n1-1', 
63: 'YR1-n0-ng-1', 
64: 'YR1-n1-n0-1', 
65: 'YR1-n1-n1-1', 
66: 'YR1-n1-ng-1'}


>>> print(cnf.mapVariableType)
{'reachableG(ng,0)': 5,
 '(var0=2)(ng)': 1,
 'YR1-n1-ng-1': 6,
 '(n1,move-right(l1,l2))': 2,
 'reachableG(ng,1)': 5,
 '(ng,move-right,n0)': 3,
 '(n1,move-right,ng)': 3,
 '(ng,move-right(l1,l2))': 2,
 'YR1-n0-n0-0': 6,
 '(n1,move-right,n1)': 3,
 '(ng,ng)': 7,
 'reachableG(n1,1)': 5,
 '(n0,move-right)': 2,
 '(n0,move-right(l2,l3))': 2,
 '(var0=1)(n1)': 1,
 '(ng,move-right(l2,l1))': 2,
 'YR1-n0-n0-1': 6,
 '(ng,move-right(l2,l3))': 2,
 '(n1,move-right,n0)': 3,
 'YR1-n1-n0-0': 6,
 '(n0,move-right,n1)': 3,
 '(n1,move-right(l3,l2))': 2,
 'reachableI(ng)': 4,
 '(n1,n1)': 7,
 '(n1,ng)': 7,
 '(var0=0)(n1)': 1,
 '(ng,move-right(l3,l2))': 2,
 'YR1-n1-n1-1': 6,
 'reachableI(n0)': 4,
 '(var0=2)(n1)': 1,
 '(var0=0)(n0)': 1,
 '(ng,move-right)': 2,
 '(n0,n0)': 7,
 '(n0,move-right,ng)': 3,
 'YR1-n1-n0-1': 6,
 'YR1-n0-ng-0': 6,
 'reachableG(n1,0)': 5,
 'YR1-n1-n1-0': 6,
 '(n1,n0)': 7,
 '(var0=0)(ng)': 1,
 'YR1-n0-ng-1': 6,
 '(ng,move-right,n1)': 3,
 'reachableI(n1)': 4,
 '(ng,n1)': 7,
 'reachableG(n1,2)': 5,
 'YR1-n0-n1-1': 6,
 '(var0=1)(n0)': 1,
 '(n0,move-right(l2,l1))': 2,
 '(n1,move-right(l2,l1))': 2,
 '(n0,ng)': 7,
 '(n0,move-right,n0)': 3,
 '(ng,n0)': 7,
 'YR1-n1-ng-0': 6,
 'reachableG(n0,0)': 5,
 '(var0=1)(ng)': 1,
 '(n0,move-right(l1,l2))': 2,
 '(n1,move-right)': 2,
 'reachableG(n0,2)': 5,
 '(n0,move-right(l3,l2))': 2,
 'reachableG(n0,1)': 5,
 'YR1-n0-n1-0': 6,
 '(n1,move-right(l2,l3))': 2,
 '(ng,move-right,ng)': 3,
 'reachableG(ng,2)': 5,
 '(var0=2)(n0)': 1,
 '(n0,n1)': 7}

最终找到的SAT解答

SAT
SAT
-1 -2 3 4 5 -6 -7 -8 -9 -10 -11 12 13 -14 -15 -16 -17 -18 -19 -20 -21 22 23 -24 -25 26 -27 -28 -29 30 -31 -32 -33 -34 35 -36 -37 -38 39 -40 -41 -42 43 44 45 46 47 48 49 50 -51 -52 -53 54 55 -56 57 58 59 60 61 62 63 64 65 66 0

对应的命题:

>>> print(cnf.mapNumberVariable)
{
3: '(var0=2)(ng)', 
4: '(n0,move-right(l2,l3))', 
5: '(n0,move-right(l2,l1))', 
12: '(n1,move-right(l1,l2))', 
13: '(var0=0)(n1)', 
22: '(n0,move-right)', 
23: '(n1,move-right)', 
26: '(n0,move-right,n1)', 
30: '(n1,move-right,ng)', 
35: '(n0,n1)', 
39: '(n1,ng)', 
43: 'reachableI(n0)', 
44: 'reachableI(n1)', 
45: 'reachableI(ng)', 
46: 'reachableG(n0,2)', 
47: 'reachableG(n1,2)', 
48: 'reachableG(ng,2)', 
49: 'reachableG(ng,0)', 
50: 'reachableG(ng,1)', 
54: 'reachableG(n1,1)', 
55: 'YR1-n0-n0-0', 
57: 'YR1-n0-ng-0', 
58: 'YR1-n1-n0-0', 
59: 'YR1-n1-n1-0', 
60: 'YR1-n1-ng-0', 
61: 'YR1-n0-n0-1', 
62: 'YR1-n0-n1-1', 
63: 'YR1-n0-ng-1', 
64: 'YR1-n1-n0-1', 
65: 'YR1-n1-n1-1', 
66: 'YR1-n1-ng-1'}

cnf.py

class CNF(builtins.object)
   CNF(n_file, n_file_extra, fair, strong)
 

 
 Methods defined here:
__init__(self, n_file, n_file_extra, fair, strong)
Initialize self.  See help(type(self)) for accurate signature.
addClause(self, clause)
addClauseExtra(self, clause)
alreadyUsed(self, var)
assignKey(self, var, typeVar=-1)
generateAfterG(self, n)
generateAtLeastOneAction(self, task, controllerStates, debug)
generateAtomControllerState(self, atom, controllerState)
generateCompletionReachabilityG(self, task, controllerStates, k, debug=False)
generateConn(self, CStates)
generateFirstG(self, n)
generateGeneralizeConnection(self, task, controllerStates, debug=False)
generateGoal(self, task, goalCState, debug=False)
generateInequalityN(self, n1, n2)
generateInitial(self, task, initialCState, debug=False)
generateInputSat(self, nameFile)
generateLowerPredecessor(self, n1, n2)
generateMutexGroupsClauses(self, task, controllerStates, debug=False)
generateNegativeForwardPropagation(self, task, controllerStates, debug)
generateOneSuccessor(self, task, controllerStates, debug=False)
generatePairActionControllerState(self, action, controllerState)
generatePairCSCS(self, n1, n2)
generatePairFairCS(self, n)
generatePairUnfairCS(self, n)
generatePossibleNonDet(self, task, controllerStates, debug=False)
generatePreconditions(self, task, controllerStates, debug=False)
generatePropagationIG(self, task, controllerStates, k, debug=False)
generatePropagationReachableGCyclic(self, task, controllerStates, k, debug=False)
generatePropagationReachableGStrong(self, task, controllerStates, k, debug=False)
generatePropagationReachableGUnfair(self, task, controllerStates, k, debug=False)
generatePropagationReachableI(self, task, controllerStates, debug=False)
generateReachableG(self, controllerState, j)
generateReachableGClauses(self, task, controllerStates, goalCState, k, debug=False)
generateReachableGInitial(self, task, goalCState, controllerStates, numberControllerStates, debug=False)
generateReachableI(self, controllerState)
generateReachableI2(self, controllerState, j)
generateReachableIClauses(self, task, initialCState, controllerStates, k, debug=False)
generateReachableIinitial(self, initialCState, debug=False)
generateReplacementEquality(self, n1, n2, atom)
generateReplacementGoalPropagation(self, controllerState1, controllerState2, i)
generateReplacementGoalPropagation3(self, controllerState1, controllerState2, i)
generateReplacementIPropagation(self, controllerState1, controllerState2, i)
generateSymmetryBreaking(self, task, controllerStates, initialCState, goalCState, debug=False)
generateTripletCSACS(self, initialState, action, finalState)
generateTripletForcesBin(self, task, controllerStates, debug=False)
generate_clauses(self, task, initialCState, goalCState, controllerStates, k, parser=None, debug=False)
getNumberClauses(self)
getNumberVariables(self)
get_num_cl_vars(self)
parseOutput(self, nameFile, controllerStates, parser, print_policy=False)
printClausesSizes(self, n)
printMapVarNumber(self)
printVariables(self)
reset(self)
setFairUnfairActions(self, task, controllerStates)
writeDisjunctions(self, file)

Data descriptors defined here:
__dict__
dictionary for instance variables (if defined)
__weakref__
list of weak references to the object (if defined)

Data and other attributes defined here:
num_types = 18
print_types = [1, 2, 3, 7]
type1 = 'Atom-Controller'
type10 = 'Replacement-Goal'
type2 = 'Action-Controller'
type3 = 'Triplet'
type4 = 'Reachable-I'
type5 = 'Reachable-G'
type6 = 'Replacement-Goal'
type7 = 'Controller-Controller'
type8 = 'Replacement-Equality'
type9 = 'Inequality-CSCS'

入口函数

    #唯一重点,一行代码
    cnf.generate_clauses(my_task, 'n0', 'ng', controllerStates, len(controllerStates), p, show_gen_info)
    #生成子句Clauses和写入cnf文件合取范式的核心代码!!!

查看定义:

    def generate_clauses(self, task, initialCState, goalCState, controllerStates, k, parser = None, debug = False):
        self.generateInitial(task, initialCState, debug)
        self.generateGoal(task, goalCState, debug)
        self.generatePreconditions(task, controllerStates, debug)
        self.generatePossibleNonDet(task, controllerStates, debug)
        self.generateOneSuccessor(task, controllerStates, debug)
        self.generateTripletForcesBin(task, controllerStates, debug)
        self.generateAtLeastOneAction(task, controllerStates, debug)
        self.generateNegativeForwardPropagation(task, controllerStates, debug)
        self.generateGeneralizeConnection(task, controllerStates, debug)
        self.generateReachableIClauses(task, initialCState, controllerStates, k, debug)
        self.generateReachableGClauses(task, controllerStates, goalCState, k, debug)
        self.generateSymmetryBreaking(task, controllerStates, initialCState, goalCState, debug)
        self.generateMutexGroupsClauses(task, controllerStates, debug)

cnf源码加解析各自的类

import sys
from myTask import MyTask
from timeit import default_timer as timer
import os

class MyCNFError(Exception):
  def __init__(self, value):
    self.value = value
  def __str__(self):
    return repr(self.value)

class CNF:
    type1 = 'Atom-Controller'
    type2 = 'Action-Controller'
    type3 = 'Triplet'
    type4 = 'Reachable-I'
    type5 = 'Reachable-G'
    type6 = 'Replacement-Goal'
    type7 = 'Controller-Controller'
    type8 = 'Replacement-Equality'
    type9 = 'Inequality-CSCS'
    type10 = 'Replacement-Goal'
    num_types = 18
    print_types = [1, 2, 3, 7]

    def __init__(self, n_file, n_file_extra, fair, strong):
        self.disjunctions = [] # list of disjunctions
        self.maxKey = 1
        self.mapVariableNumber = {}
        self.mapNumberVariable = {}
        self.mapVariableType = {}
        self.clauseSizeCounter = {}
        self.name_file_formula = n_file
        self.name_file_formula_extra = n_file_extra
        self.file_formula = open(n_file, 'w')
        self.file_formula_extra = open(n_file_extra, 'w')
        self.file_formula.close()
        self.file_formula_extra.close()
        self.number_clauses = 0
        self.fair   = fair
        self.strong = strong

    def reset(self):
        self.disjunctions = [] # list of disjunctions
        self.maxKey = 1
        self.mapVariableNumber = {}
        self.mapNumberVariable = {}
        self.mapVariableType = {}
        self.clauseSizeCounter = {}
        self.file_formula = open(self.name_file_formula, 'w')
        self.file_formula.write('p cnf 1 1\n')
        self.file_formula_extra = open(self.name_file_formula_extra, 'a')
        # File formula extra is not used, can be ignored
        self.number_clauses = 0

代码接上,标记方便跳转查看

GENERAl通用功能性函数

    ###########################################
    ################# GENERAL #################
    ###########################################

    def generateAtomControllerState(self, atom, controllerState):
        var = atom + '(' + controllerState + ')'
        self.assignKey(var, 1)
        return var

    def generatePairActionControllerState(self, action, controllerState):
        var = '(' + controllerState + ',' + action + ')'
        self.assignKey(var, 2)
        return var

    def generateTripletCSACS(self, initialState, action, finalState):
        var = '(' + initialState + ',' + action + ',' + finalState + ')'
        self.assignKey(var, 3)
        return var

    def generateReachableI(self, controllerState):
        var = 'reachableI(' + controllerState + ')'
        self.assignKey(var, 4)
        return var

    def generateReachableI2(self, controllerState, j):
        var = 'reachableI(' + controllerState + ',' + str(j) + ')'
        self.assignKey(var, 4)
        return var

    def generateReachableG(self, controllerState, j):
        var = 'reachableG(' + controllerState + ',' + str(j) + ')'
        self.assignKey(var, 5)
        return var

    def generateReplacementGoalPropagation(self, controllerState1, controllerState2, i):
        var = 'YR1-' + controllerState1 + '-' + controllerState2 + '-' + str(i)
        self.assignKey(var, 6)
        return var

    def generateReplacementGoalPropagation3(self, controllerState1, controllerState2, i):
        var = 'YR1-FAIR-' + controllerState1 + '-' + controllerState2 + '-' + str(i)
        self.assignKey(var, 6)
        return var

    def generatePairCSCS(self, n1, n2):
        var = '(' + n1 + ',' + n2 + ')'
        self.assignKey(var, 7)
        return var

    def generateReplacementEquality(self, n1, n2, atom):
        var = 'YR2-' + n1 + '-' + n2 + '-' + atom
        self.assignKey(var, 8)
        return var

    def generateInequalityN(self, n1, n2): # n1 < n2
        var = n1 + '<' + n2
        self.assignKey(var, 9)
        return var  

    def generateReplacementIPropagation(self, controllerState1, controllerState2, i):
        var = 'YR3-' + controllerState1 + '-' + controllerState2 + '-' + str(i)
        self.assignKey(var, 10)
        return var

    def generateFirstG(self, n):
        var = 'FirstG(' + str(n) + ')'
        self.assignKey(var, 13)
        return var

    def generateAfterG(self, n):
        var = 'AfterG(' + str(n) + ')'
        self.assignKey(var, 14)
        return var

    def generateConn(self, CStates):
        var = 'conn('
        for n in CStates:
            var += str(n) + ','
        var += ')'
        self.assignKey(var, 15)
        return var

    def generatePairFairCS(self, n):
        var = 'F(' + n + ',fair)'
        self.assignKey(var, 16)
        return var

    def generatePairUnfairCS(self, n):
        var = 'U(' + n + ',unfair)'
        self.assignKey(var, 17)
        return var

    def generateLowerPredecessor(self, n1, n2):
        var = 'Lower(' + n1 + ', ' + n2 + ')'
        self.assignKey(var, 18)
        return var

    def generateInputSat(self, nameFile):
        self.file_formula.close()
        with open(nameFile, 'r') as formula:
            name_final = nameFile + 'header'
            with open(name_final, 'w') as final_formula:
                final_formula.write('p cnf %i %i\n' % (len(self.mapNumberVariable), self.number_clauses))
                first_line = True
                for line in formula:
                    if first_line:
                        first_line = False
                        continue
                    final_formula.write(line)
        # name_final is the name of the file that contains the formula with header and everything
        return name_final

    def writeDisjunctions(self, file):
        for i in self.disjunctions:
            for j in i:
                if j[0] == '-':
                    file.write('-' + str(self.mapVariableNumber[j[1:]]) + '\t')
                else:
                    file.write(str(self.mapVariableNumber[j]) + '\t')
            file.write('0\n')

    # def printDisjunctions(self):
    #   for i in self.disjunctions:
    #       for j in i:
    #           print j + ' ',
    #       print '\n',

    # def printDisjunctionsNumbers(self, printExpanded):
    #   for i in self.disjunctions:
    #       if printExpanded:
    #           for j in i:
    #               print j + '\t',
    #           print ''
    #       for j in i:
    #           if j[0] == '-':
    #               print '-' + str(self.mapVariableNumber[j[1:]]), '\t',
    #           else:
    #               print self.mapVariableNumber[j], '\t',
    #       print ' 0'

    def printVariables(self):
        for i in self.mapVariableNumber:
            print(i)

parseOutput输出解决policy

    def parseOutput(self, nameFile, controllerStates, parser, print_policy = False):
        sets = [set([]) for i in range(self.num_types)]
        fres = open(nameFile, 'r')
        res = fres.readlines()
        if 'UNSAT' in res[0]:
            return False
        if 'INDET' in res[0]:
            return None
        if not print_policy:
            return True
        res = res[1]
        res = res.split(' ')
        for r in res:
            if '\n' in res:
                continue
            var = int(r)
            if var > 0:
                varName = self.mapNumberVariable[var]
                t = self.mapVariableType[varName]
                sets[t - 1].add(varName)
        print('===================\n===================')
        print('Controller -- CS = Controller State')
        for i in range(len(sets)):
            if i + 1 in self.print_types:
                s = sets[i]
                if i == 0:
                    # pair atom controller
                    print('===================\n===================')
                    print('Atom (CS)')
                    print('___________________')
                    for n in controllerStates:
                        print('----------')
                        for j in s:
                            ind = '(' + n + ')'
                            if ind in j:
                                print('%s %s' % (str(parser.get_var_string(j.split(ind)[0])), str(ind)))
                elif i == 1:
                    # pair cs action
                    print('===================\n===================')
                    print('(CS, Action with arguments)')
                    print('___________________')
                    for n in controllerStates:
                        for j in s:
                            if '(' + n + ',' in j:
                                print(j)
                elif i == 2:
                    # Triplet
                    print('===================\n===================')
                    print('(CS, Action name, CS)')
                    print('___________________')
                    for n in controllerStates:
                        for j in s:
                            if '(' + n + ',' in j:
                                print(j)
                else:
                    print('===================')
                    print('(CS, CS)')
                    print('___________________')
                    for j in s:
                        print(j)
        print('===================')
        print('Solved with %i states' % len(controllerStates))
        return True

    def getNumberVariables(self):
        return len(self.mapVariableNumber)

    def getNumberClauses(self):
        return self.number_clauses

    def printMapVarNumber(self):
        for i in self.mapVariableNumber:
            print(i, '-->', self.mapVariableNumber[i])

    def alreadyUsed(self, var):
        if var in self.mapVariableNumber:
            return True
        return False

    def assignKey(self, var, typeVar = -1):
        if not self.alreadyUsed(var):
            self.mapVariableNumber[var] = self.maxKey
            self.mapNumberVariable[self.maxKey] = var
            self.mapVariableType[var] = typeVar
            self.maxKey += 1

    def get_num_cl_vars(self):
        return self.getNumberClauses(), self.getNumberVariables()

    def addClause(self, clause):
        self.number_clauses += 1
        for j in clause:
            negated = (j[0] == '-')
            if negated:
                var = j[1:]
            else:
                var = j
            if negated:
                self.file_formula.write('-' + str(self.mapVariableNumber[var]) + '\t')
            else:
                self.file_formula.write(str(self.mapVariableNumber[var]) + '\t')
        self.file_formula.write('0\n')

    def addClauseExtra(self, clause):
        for j in clause:
            self.file_formula_extra.write(j + '|')
        self.file_formula_extra.write('\n')
        # j1|j2|...|jn|\n

    def printClausesSizes(self, n):
        print(self.clauseSizeCounter)
        sum_all = 0
        sum_greater = 0
        for i in self.clauseSizeCounter:
            sum_all += self.clauseSizeCounter[i]
            if i >= n:
                sum_greater += self.clauseSizeCounter[i]
            else:
                print(i, ':', self.clauseSizeCounter[i])
        print('>=', i, ':', sum_greater)

代码接上,标记方便跳转查看

generate_clauses核心入口类

main.py 高潮部分:注意留意重点:

solver_time = []
for i in range(1000):
    cnf = CNF(name_formula_file, name_formula_file_extra, fair, strong)#文件formula-temp.txt这时候是空白的,formula-extra-temp此时空白,仅仅是传入地址方便最终结果存入数据
    ......
    cnf.reset()
      start_g = timer()
    cnf.generate_clauses(my_task, 'n0', 'ng', controllerStates, len(controllerStates), p, show_gen_info)#生成子句Clauses和写入cnf文件合取范式的核心代码!!!
    ......
    command = './minisat %s %s' % (name_formula_file, name_output_satsolver)#调用minisat
    ......
    result = cnf.parseOutput(name_output_satsolver, controllerStates, p, print_policy)#读取文件name_output_satsolver : outsat-temp.txt输出结果
    ......

cnf.py

    ###########################################
    ############## GENERATION #################
    ###########################################

    def generate_clauses(self, task, initialCState, goalCState, controllerStates, k, parser = None, debug = False):
        self.generateInitial(task, initialCState, debug)
        self.generateGoal(task, goalCState, debug)
        self.generatePreconditions(task, controllerStates, debug)
        self.generatePossibleNonDet(task, controllerStates, debug)
        self.generateOneSuccessor(task, controllerStates, debug)
        self.generateTripletForcesBin(task, controllerStates, debug)
        self.generateAtLeastOneAction(task, controllerStates, debug)
        self.generateNegativeForwardPropagation(task, controllerStates, debug)
        self.generateGeneralizeConnection(task, controllerStates, debug)
        self.generateReachableIClauses(task, initialCState, controllerStates, k, debug)
        self.generateReachableGClauses(task, controllerStates, goalCState, k, debug)
        self.generateSymmetryBreaking(task, controllerStates, initialCState, goalCState, debug)
        self.generateMutexGroupsClauses(task, controllerStates, debug)

代码接上,标记方便跳转查看

generate_clauses调用的生成子句的类

    ###########################################
    ################ INITIAL ##################
    ###########################################

    def generateInitial(self, task, initialCState, debug = False):
        # -p(n0) for all p not in initial state
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        initial = task.get_initial()
        atoms = task.get_atoms()
        for a in atoms:
            if a not in initial:
                variable = self.generateAtomControllerState(a, initialCState)
                self.addClause(['-' + variable])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: Initial\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    ###########################################
    ############## GOAL #######################
    ###########################################

    def generateGoal(self, task, goalCState, debug = False):
        # p(ng) for all p in goal state
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        goal = task.get_goal()
        atoms = task.get_atoms()
        for a in atoms:
            if a in goal:
                variable = self.generateAtomControllerState(a, goalCState)
                self.addClause([variable])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: Goal\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    ###########################################
    ############## PRECONDITIONS ##############
    ###########################################

    def generatePreconditions(self, task, controllerStates, debug = False):
        # (n, b) --> p(n) // if p \in prec(b)
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        atoms = task.get_atoms()
        actions = task.get_actions()

        for n in controllerStates:
            for a in actions:
                pre = task.get_preconditions(a)
                var = self.generatePairActionControllerState(a, n)
                for p in pre:
                    varPre = self.generateAtomControllerState(p, n)
                    self.addClause(['-' + var, varPre])
                    # print clause + [varPre] # DEBUG

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: Precs\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))


    ###########################################
    ############## NON-DET ####################
    ###########################################

    def generatePossibleNonDet(self, task, controllerStates, debug = False):
        # 1. (n, act) --> (n, act') // act, act' are non det act of equal det action (action names)
        # 2. (n, act) --> -(n, act'') //
        # 3. (n, b) --> (n, b') // b, b' are siblings
        # 4. (n, b) --> -(n, b'') // b, b'' belong to same act
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        acts = task.get_action_names()
        for n in controllerStates:
            for act in acts:
                var_pair = self.generatePairActionControllerState(act, n)
                other_acts = task.get_other_actions_name(act)
                for act2 in acts:
                    if act2 == act:
                        continue
                    var_pair2 = self.generatePairActionControllerState(act2, n)
                    if act2 in other_acts:
                        self.addClause(['-' + var_pair, var_pair2]) # 1
                    else:
                        self.addClause(['-' + var_pair, '-' + var_pair2]) # 2

                for a1 in task.get_actions_with_name(act):
                    var1 = self.generatePairActionControllerState(a1, n)
                    for a2 in task.get_actions_with_name(act):
                        if a2 == a1:
                            continue
                        if task.actions_are_compatible(a1, a2): # IMPORTANT!! ie. prec not mutex
                            var2 = self.generatePairActionControllerState(a2, n)
                            self.addClause(['-' + var1, '-' + var2]) # 4

            for a in task.get_actions():
                var1 = self.generatePairActionControllerState(a, n)
                other_actions = task.get_other_actions(a)
                for other in other_actions:
                    if other == a:
                        continue
                    var2 = self.generatePairActionControllerState(other, n)
                    self.addClause(['-' + var1, var2]) # 3

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: Non Det\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    ###########################################
    ############## ONE SUCC ###################
    ###########################################

    def generateOneSuccessor(self, task, controllerStates, debug = False):
        # 1. (n, act) --> \OR_{b} (n, b) // for b with name act
        # 2. (n, act) --> \OR_{n'} (n, act, n')
        # 3. -(n, act, n') \lor -(n, act, n'')
        # 4. (n, b) --> (n, act)
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        acts = task.get_action_names()

        for n1 in controllerStates:
            for a_name in acts:
                for n2 in controllerStates:
                    for n3 in controllerStates:
                        if n3 == n2:
                            continue
                        var1 = self.generateTripletCSACS(n1, a_name, n2)
                        var2 = self.generateTripletCSACS(n1, a_name, n3)
                        self.addClause(['-' + var1, '-' + var2]) # 3

                for a in task.get_actions_with_name(a_name):
                    pair1 = self.generatePairActionControllerState(a, n1)
                    pair2 = self.generatePairActionControllerState(a_name, n1)
                    self.addClause(['-' + pair1, pair2]) # 4

                var1 = self.generatePairActionControllerState(a_name, n1)
                var_triplets = []
                for n2 in controllerStates:
                    var_triplets.append(self.generateTripletCSACS(n1, a_name, n2))
                self.addClause(['-' + var1] + var_triplets) # 2

                var1 = self.generatePairActionControllerState(a_name, n1)
                var_bin = []
                for a in task.get_actions_with_name(a_name):
                    var_bin.append(self.generatePairActionControllerState(a, n1))
                self.addClause(['-' + var1] + var_bin) # 1

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: One succ\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    ###########################################
    ############## TRIPLET-BIN ################
    ###########################################

    def generateTripletForcesBin(self, task, controllerStates, debug = False):
        # (n, act, n') --> (n, act)
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        actions = task.get_action_names()
        for n1 in controllerStates:
            for a in actions:
                for n2 in controllerStates:
                    var1 = self.generateTripletCSACS(n1, a, n2)
                    var2 = self.generatePairActionControllerState(a, n1)
                    # print ['-' + var1, var2] # DEBUG
                    self.addClause(['-' + var1, var2])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: Trip bin\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    ###########################################
    ############## ONE ACTION #################
    ###########################################

    def generateAtLeastOneAction(self, task, controllerStates, debug):
        # \OR_{act_name} (n, act) for all n except goal, ng
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        actions = task.get_action_names()
        for n in controllerStates:
            if n == 'ng':
                continue
            disj = []
            for a in actions:
                pair = self.generatePairActionControllerState(a, n)
                disj.append(pair)
            self.addClause(disj)

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: One act\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    ###########################################
    ############## NEG-FORWARD PROP ###########
    ###########################################

    def __sibling_action_adds_atom(self, task, action, atom):
        siblings = task.get_other_actions(action)
        for a in siblings:
            add_list = task.get_add_list(a)
            if atom in add_list:
                return True
        return False

    def generateNegativeForwardPropagation(self, task, controllerStates, debug):
        # 1. (n, act, n') \land (n, b) --> -p(n') // if p in delete list
        # 2. (n, n') \land -p(n) --> -p(n') \lor \OR_{b: p \in add(b)} (n, b)
        # 3. (n, act, n') \land (n, b) \land -p(n) --> -p(n') // if p \not \in add(b) 
        # and some sibling of b adds p
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        atoms = task.get_atoms()
        actions = task.get_actions()

        #for a in actions:
        #   print(a, task.get_del_list(a))
        #   print(a, task.get_add_list(a))

        for n1 in controllerStates:
            for n2 in controllerStates:
                for p in atoms:
                    var_atom_n1 = self.generateAtomControllerState(p, n1)
                    var_pair_n1n2 = self.generatePairCSCS(n1, n2)
                    var_atom_n2 = self.generateAtomControllerState(p, n2)
                    disj_add_clause = ['-' + var_pair_n1n2, var_atom_n1, '-' + var_atom_n2]
                    for a in task.get_relevant_actions(p):
                        a_name = task.get_action_name(a)
                        del_list = task.get_del_list(a)
                        add_list = task.get_add_list(a)
                        var_triplet = self.generateTripletCSACS(n1, a_name, n2)
                        var_bin = self.generatePairActionControllerState(a, n1)
                        if p in del_list:
                            self.addClause(['-' + var_triplet, '-' + var_bin,'-' + var_atom_n2]) # 1
                        if p in add_list:
                            disj_add_clause.append(var_bin)
                        if p not in add_list and self.__sibling_action_adds_atom(task, a, p):
                            self.addClause(['-' + var_triplet, '-' + var_bin, var_atom_n1, '-' + var_atom_n2]) # 3
                    self.addClause(disj_add_clause) # 2

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: Neg Prop\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    ###########################################
    ############## GEN-CONNS ##################
    ###########################################

    def generateGeneralizeConnection(self, task, controllerStates, debug = False):
        # (n, n') <--> \OR_{act} (n, act, n')
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        actions = task.get_action_names()
        for n1 in controllerStates:
            for n2 in controllerStates:
                varBin = self.generatePairCSCS(n1, n2)
                triplets = ['-' + varBin]
                for a in actions:
                    triplet = self.generateTripletCSACS(n1, a, n2)
                    self.addClause(['-' + triplet, varBin])
                    # print ['-' + triplet, varBin] # DEBUG
                    triplets.append(triplet)
                # print triplets # DEBUG
                self.addClause(triplets)

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: Gen conn\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    ###########################################
    ############## REACH-I ####################
    ###########################################

    def generateReachableIClauses(self, task, initialCState, controllerStates, k, debug = False):
        self.generateReachableIinitial(initialCState, debug)
        self.generatePropagationReachableI(task, controllerStates, debug)
        self.generatePropagationIG(task, controllerStates, k - 1, debug)

    def generateReachableIinitial(self, initialCState, debug = False):
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        self.addClause([self.generateReachableI(initialCState)])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: RI init\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    def generatePropagationReachableI(self, task, controllerStates, debug = False):
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        for n1 in controllerStates:
            for n2 in controllerStates:
                var1 = self.generateReachableI(n1)
                var2 = self.generateReachableI(n2)
                var3 = self.generatePairCSCS(n1, n2)
                self.addClause(['-' + var3, '-' + var1, var2])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: RI prop\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    def generatePropagationIG(self, task, controllerStates, k, debug = False):
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        for n in controllerStates:
            var1 = self.generateReachableI(n)
            var2 = self.generateReachableG(n, k)
            self.addClause(['-' + var1, var2])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: IG prop\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    ###########################################
    ############## REACH-G ####################
    ###########################################

    def generateReachableGClauses(self, task, controllerStates, goalCState, k, debug = False):
        self.generateReachableGInitial(task, goalCState, controllerStates, k - 1, debug)
        self.generateCompletionReachabilityG(task, controllerStates, k - 1, debug)
        if self.strong:
            self.generatePropagationReachableGStrong(task, controllerStates, k - 1, debug)
        else:
            if not self.fair:
                self.generatePropagationReachableGUnfair(task, controllerStates, k - 1, debug)
            else:
                self.generatePropagationReachableGCyclic(task, controllerStates, k - 1, debug)  

    def generateReachableGInitial(self, task, goalCState, controllerStates, numberControllerStates, debug = False):
        # ReachG(ng,0), ReachG(ng,1), ...
        # -ReachG(n, 0) for n != ng
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        # set the initial values for goal state
        for i in range(numberControllerStates + 1):
            self.addClause([self.generateReachableG(goalCState, i)])
        # set the negation for non goal states
        for n in controllerStates:
            if n == goalCState:
                continue
            self.addClause(['-' + self.generateReachableG(n, 0)])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: RG init\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    def generateCompletionReachabilityG(self, task, controllerStates, k, debug = False):
        # ReachG(n,j) --> ReachG(n, j+1)
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        for n in controllerStates:
            for i in range(k):
                var1 = self.generateReachableG(n, i)
                var2 = self.generateReachableG(n, i + 1)
                self.addClause(['-' + var1, var2])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: RG compl\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    def setFairUnfairActions(self, task, controllerStates):
        # 1: (n, unfair) <-> \OR_{b: unf} (n,b)
        # 2: (n, fair) <-> \OR_{b: unf} (n,b)
        # 3: -(n, fair) \lor -(n, unfair)
        actions = task.get_action_names()
        for n in controllerStates:
            varPairUnf = self.generatePairUnfairCS(n)
            disj = ['-' + varPairUnf]
            for a in actions:
                if '_unfair_' in a:
                    varPair = self.generatePairActionControllerState(a, n)
                    self.addClause(['-' + varPair, varPairUnf]) # 1
                    # print(['-' + varPair, varPairUnf])
                    disj.append(varPair)
            self.addClause(disj) # 1
            # print(disj)
        for n in controllerStates:
            varPairF = self.generatePairFairCS(n)
            disj = ['-' + varPairF]
            for a in actions:
                if '_unfair_' not in a:
                    varPair = self.generatePairActionControllerState(a, n)
                    self.addClause(['-' + varPair, varPairF]) # 2
                    # print(['-' + varPair, varPairF])
                    disj.append(varPair) 
            self.addClause(disj) # 2
            # print(disj)
        for n in controllerStates:
            varF = self.generatePairFairCS(n)
            varU = self.generatePairUnfairCS(n)
            self.addClause(['-' + varF, '-' + varU]) # 3
            # print(['-' + varF, '-' + varU])

    def generatePropagationReachableGUnfair(self, task, controllerStates, k, debug = False):
        # ReachG(n, j+1) <--> [1] 
        # [1] = [2] \lor [3]
        # [2] = (n, unfair) \land \AND_{n'} [(n,n') --> RG(n',j)]
        # [3] = \OR_{n'} [(n, fair) \land (n,n') \land RG(n',j)]
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        # Set variables (n, fair) and (n, unfair)
        self.setFairUnfairActions(task, controllerStates)
        # Force the equivalences for [2]
        # [(n,n') --> RG(n',j)] <-> Repl(n,n',j)
        for i in range(k):
            for n1 in controllerStates:
                if n1 == 'ng':
                    continue
                for n2 in controllerStates:
                    varRepl = self.generateReplacementGoalPropagation(n1, n2, i)
                    varPair = self.generatePairCSCS(n1, n2)
                    varRG   = self.generateReachableG(n2, i)
                    self.addClause(['-' + varRepl, '-' + varPair, varRG])
                    self.addClause(['-' + varRG, varRepl])
                    self.addClause([varPair, varRepl])
        # Force the equivalences for [3]
        # [(n, fair) \land (n,n') \land RG(n',j)] <-> Repl3(n,n',j)
        for i in range(k):
            for n1 in controllerStates:
                if n1 == 'ng':
                    continue
                for n2 in controllerStates:
                    varRepl = self.generateReplacementGoalPropagation3(n1, n2, i)
                    varPair = self.generatePairCSCS(n1, n2)
                    varFair = self.generatePairFairCS(n1)
                    varRG   = self.generateReachableG(n2, i)
                    self.addClause(['-' + varRepl, varPair])
                    self.addClause(['-' + varRepl, varFair])
                    self.addClause(['-' + varRepl, varRG])
                    self.addClause([varRepl, '-' + varPair, '-' + varFair, '-' + varRG])
        # Right arrow
        for n1 in controllerStates:
            if n1 == 'ng':
                continue
            for i in range(k):
                varRG = self.generateReachableG(n1, i + 1)
                listStrong = [self.generatePairUnfairCS(n1)]
                listCyclic = []
                for n in controllerStates:
                    listStrong.append(self.generateReplacementGoalPropagation(n1, n, i))
                    listCyclic.append(self.generateReplacementGoalPropagation3(n1, n, i))
                clause = ['-' + varRG] + listCyclic
                for e in listStrong:
                    self.addClause(clause + [e])
                    # print(clause + [e])
        # Left arrow
        for n1 in controllerStates:
            if n1 == 'ng':
                continue
            for i in range(k):
                varRG = self.generateReachableG(n1, i + 1)
                listStrong = [self.generatePairUnfairCS(n1)]
                listCyclic = []
                for n in controllerStates:
                    listStrong.append(self.generateReplacementGoalPropagation(n1, n, i))
                    listCyclic.append(self.generateReplacementGoalPropagation3(n1, n, i))
                self.addClause([varRG] + ['-' + e for e in listStrong])
                # print([varRG] + ['-' + e for e in listStrong])
                for e in listCyclic:
                    self.addClause([varRG, '-' + e])
                    # print([varRG, '-' + e])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: RG prop\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    def generatePropagationReachableGCyclic(self, task, controllerStates, k, debug = False):
        # ReachG(n, j+1) <--> \OR_{n'} [(n,n') \land ReachG(n', j)]
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        # Force the equivalences
        for i in range(k):
            for n1 in controllerStates:
                if n1 == 'ng':
                    continue
                for n2 in controllerStates:
                    var1 = self.generateReplacementGoalPropagation(n1, n2, i)
                    var2 = self.generatePairCSCS(n1, n2)
                    var3 = self.generateReachableG(n2, i)
                    self.addClause(['-' + var1, var2])
                    self.addClause(['-' + var1, var3])
                    self.addClause([var1, '-' + var2, '-' + var3])
        # Right arrow
        for n1 in controllerStates:
            if n1 == 'ng':
                continue
            for i in range(k):
                var1 = self.generateReachableG(n1, i + 1)
                var2 = ['-' + var1]
                for n2 in controllerStates:
                    var3 = self.generateReplacementGoalPropagation(n1, n2, i)
                    var2.append(var3)
                self.addClause(var2)
        # Left arrow
        for n1 in controllerStates:
            if n1 == 'ng':
                continue
            for i in range(k):
                var1 = self.generateReachableG(n1, i + 1)
                for n2 in controllerStates:
                    var2 = self.generateReplacementGoalPropagation(n1, n2, i)
                    self.addClause([var1, '-' + var2])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: RG prop\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    def generatePropagationReachableGStrong(self, task, controllerStates, k, debug = False):
        # ReachG(n, j+1) <--> \AND_{n'} [(n,n') --> ReachG(n', j)]
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        # Force the equivalences
        for i in range(k):
            for n1 in controllerStates:
                if n1 == 'ng':
                    continue
                for n2 in controllerStates:
                    varRepl = self.generateReplacementGoalPropagation(n1, n2, i)
                    varPair = self.generatePairCSCS(n1, n2)
                    varRG   = self.generateReachableG(n2, i)
                    self.addClause(['-' + varRepl, '-' + varPair, varRG])
                    self.addClause(['-' + varRG, varRepl])
                    self.addClause([varPair, varRepl])
        # Right arrow
        for n1 in controllerStates:
            if n1 == 'ng':
                continue
            for i in range(k):
                varRG = self.generateReachableG(n1, i + 1)
                for n2 in controllerStates:
                    varRepl = self.generateReplacementGoalPropagation(n1, n2, i)
                    self.addClause(['-' + varRG, varRepl])
        # Left arrow
        for n1 in controllerStates:
            if n1 == 'ng':
                continue
            for i in range(k):
                disj = [self.generateReachableG(n1, i + 1)]
                for n2 in controllerStates:
                    varRepl = self.generateReplacementGoalPropagation(n1, n2, i)
                    disj.append('-' + varRepl)
                self.addClause(disj)

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: RG prop\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    ###########################################
    ############## SYMM-BREAKING ##############
    ###########################################

    def generateSymmetryBreaking(self, task, controllerStates, initialCState, goalCState, debug = False):
        c1, v1 = self.get_num_cl_vars()
        start = timer()

        if len(controllerStates) >= 4:
            # (na, nb) --> \OR_{i<=a} (n_i, n_{b-1})
            for ia, na in enumerate(controllerStates[:-1]):
                for ib, nb in enumerate(controllerStates[:-1]):
                    if ib in [0, 1]:
                        continue
                    nb_1 = controllerStates[ib - 1]
                    var_pair_ab = self.generatePairCSCS(na, nb)
                    disj = ['-' + var_pair_ab]
                    for i in range(ia + 1):
                        ni = controllerStates[i]
                        disj.append(self.generatePairCSCS(ni, nb_1))
                    self.addClause(disj)

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: Sym brk\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))


    ###########################################
    ############## MUTEX GROUPS ###############
    ###########################################

    def generateMutexGroupsClauses(self, task, controllerStates, debug = False):
        c1, v1 = self.get_num_cl_vars()
        start = timer()
        mutex_groups = task.get_mutex_groups()
        for mg in mutex_groups:
            pairs = self.__get_all_pairs(mg)
            for (a1, a2) in pairs:
                for n in controllerStates:
                    var1 = self.generateAtomControllerState(a1, n)
                    var2 = self.generateAtomControllerState(a2, n)
                    self.addClause(['-' + var1, '-' + var2])

        c2, v2 = self.get_num_cl_vars()
        if debug:
            print('Generation: Mutex\t\t v %i \t\t c : %i \t\t %f' % (v2 - v1, c2 - c1, timer() - start))

    def __get_all_pairs(self, els):
        return [(e1, e2) for (i1, e1) in enumerate(els) for (i2, e2) in enumerate(els) if i2 > i1]