├── examples ├── req.part ├── req1.part ├── cc.part ├── counter_1.part ├── ltlf3377.part ├── req1.ltlf ├── counter_2.part ├── counters_1.part ├── counters_2.part ├── req.ltlf ├── counter_1.ltlf ├── cc.ltlf ├── counter_2.ltlf ├── counters_1.ltlf ├── ltlf3377.ltlf ├── counters_2.ltlf └── testcase.ltlf ├── src ├── Makefile ├── debug.hh ├── common.hh ├── mona.hh ├── strategy.hh ├── aututil.hh ├── specparser.hh ├── ltlf2fol.hh ├── synt.hh ├── dfwa.hh ├── spotutil.hh ├── argparser.cc ├── strategy.cc ├── dfwavar.hh ├── argparser.hh ├── dfwamin2.hh ├── testencode.cc ├── specparser.cc ├── dfwamin.hh ├── dfwamin3.hh ├── synt.cc ├── testltlf2fa.cc ├── aututil.cc ├── spotutil.cc ├── dfwavar.cc ├── mona.cc ├── dfwa.cc ├── lisa.cc └── dfwamin2.cc └── README.md /examples/req.part: -------------------------------------------------------------------------------- 1 | .inputs go cancel req 2 | .outputs grant 3 | -------------------------------------------------------------------------------- /examples/req1.part: -------------------------------------------------------------------------------- 1 | .inputs cancel req 2 | .outputs ack grant 3 | -------------------------------------------------------------------------------- /examples/cc.part: -------------------------------------------------------------------------------- 1 | .inputs initcounter0 inc 2 | .outputs counter0 carry0 3 | -------------------------------------------------------------------------------- /examples/counter_1.part: -------------------------------------------------------------------------------- 1 | .inputs INITCOUNTER0 INC 2 | .outputs COUNTER0 CARRY0 -------------------------------------------------------------------------------- /examples/ltlf3377.part: -------------------------------------------------------------------------------- 1 | .inputs: P60 P62 P71 P91 P75 P16 P18 P35 2 | .outputs: P135 P106 P151 -------------------------------------------------------------------------------- /examples/req1.ltlf: -------------------------------------------------------------------------------- 1 | (((G (F (req))) || (F (cancel))) -> ((G (F (grant))) || (G (ack)))) 2 | -------------------------------------------------------------------------------- /examples/counter_2.part: -------------------------------------------------------------------------------- 1 | .inputs INITCOUNTER0 INITCOUNTER1 INC 2 | .outputs COUNTER0 COUNTER1 CARRY0 CARRY1 -------------------------------------------------------------------------------- /examples/counters_1.part: -------------------------------------------------------------------------------- 1 | .inputs INITCOUNTER0 INCENV 2 | .outputs COUNTERENV0 COUNTERSYS0 CARRYENV0 CARRYSYS0 INCSYS -------------------------------------------------------------------------------- /examples/counters_2.part: -------------------------------------------------------------------------------- 1 | .inputs INITCOUNTER0 INITCOUNTER1 INCENV 2 | .outputs COUNTERENV0 COUNTERSYS0 COUNTERENV1 COUNTERSYS1 CARRYENV0 CARRYSYS0 CARRYENV1 CARRYSYS1 INCSYS -------------------------------------------------------------------------------- /examples/req.ltlf: -------------------------------------------------------------------------------- 1 | ((G ((cancel) -> (X (go)))) -> (G ((((req) -> (X ((grant) || (X ((grant) || (X (grant))))))) && ((grant) -> (X (! (grant))))) && ((cancel) -> (X ((! (grant)) U (go))))))) 2 | -------------------------------------------------------------------------------- /examples/counter_1.ltlf: -------------------------------------------------------------------------------- 1 | ((COUNTER0 <-> INITCOUNTER0)) && (G (CARRY0 <-> INC)) && (G ((X COUNTER0 -> !(COUNTER0 <-> CARRY0)) && (X !COUNTER0 -> (COUNTER0 <-> CARRY0)))) && ((G ((!INC -> X INC)) -> F (!COUNTER0))) -------------------------------------------------------------------------------- /examples/cc.ltlf: -------------------------------------------------------------------------------- 1 | (((G ((((carry0) <-> (inc)) && ((X (counter0)) -> (! ((counter0) <-> (carry0))))) && ((X (! (counter0))) -> ((counter0) <-> (carry0))))) && ((counter0) <-> (initcounter0))) && ((G ((! (inc)) -> (X (inc)))) -> (F (! (counter0))))) 2 | -------------------------------------------------------------------------------- /examples/counter_2.ltlf: -------------------------------------------------------------------------------- 1 | ((COUNTER0 <-> INITCOUNTER0)) && ((COUNTER1 <-> INITCOUNTER1)) && (G (CARRY0 <-> INC)) && (G (CARRY1 <-> (COUNTER0 && CARRY0))) && (G ((X COUNTER0 -> !(COUNTER0 <-> CARRY0)) && (X !COUNTER0 -> (COUNTER0 <-> CARRY0)))) && (G ((X COUNTER1 -> !(COUNTER1 <-> CARRY1)) && (X !COUNTER1 -> (COUNTER1 <-> CARRY1)))) && ((G ((!INC -> X INC)) -> F (!COUNTER0 && !COUNTER1))) -------------------------------------------------------------------------------- /examples/counters_1.ltlf: -------------------------------------------------------------------------------- 1 | ((COUNTERENV0 <-> INITCOUNTER0)) && (!COUNTERSYS0) && (G (CARRYENV0 <-> INCENV)) && (G (CARRYSYS0 <-> INCSYS)) && (G ((X COUNTERENV0 -> !(COUNTERENV0 <-> CARRYENV0)) && (X !COUNTERENV0 -> (COUNTERENV0 <-> CARRYENV0)))) && (G ((X COUNTERSYS0 -> !(COUNTERSYS0 <-> CARRYSYS0)) && (X !COUNTERSYS0 -> (COUNTERSYS0 <-> CARRYSYS0)))) && ((G ((INCENV -> !X INCENV)) -> F ((COUNTERENV0 <-> COUNTERSYS0)))) -------------------------------------------------------------------------------- /examples/ltlf3377.ltlf: -------------------------------------------------------------------------------- 1 | ((G((P71) -> (X(P35)))) -> ((G((P16) -> ((X(P135)) | (X(X(P135))) | (X(X(X(P135))))))) & (G((P135) -> (X(!(P135))))) & (G((P71) -> (X((!(P135)) U (P35))))))) & ((G((P91) -> (X(P35)))) -> ((G((P18) -> ((X(P151)) | (X(X(P151))) | (X(X(X(P151))))))) & (G((P151) -> (X(!(P151))))) & (G((P91) -> (X((!(P151)) U (P35))))))) & ((G((P62) -> (X(P75)))) -> ((G((P60) -> ((X(P106)) | (X(X(P106))) | (X(X(X(P106))))))) & (G((P106) -> (X(!(P106))))) & (G((P62) -> (X((!(P106)) U (P75))))))) 2 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | all: T1 T2 2 | 3 | T1: 4 | g++ lisa.cc dfwavar.cc dfwa.cc spotutil.cc ltlf2fol.cc mona.cc dfwamin.cc synt.cc strategy.cc dfwamin2.cc -o lisa -lspot -lbddx -lcudd -O3 5 | 6 | T2: 7 | g++ testltlf2fa.cc aututil.cc ltlf2fol.cc dfwavar.cc dfwa.cc spotutil.cc mona.cc -o testltlf2fol -lspot -lbddx -lcudd 8 | 9 | #------------------------------------------------------ 10 | clean: #clean 11 | rm -f *.o main *.cc~ *.h~ Makefile~ 12 | #------------------------------------------------------ 13 | 14 | -------------------------------------------------------------------------------- /src/debug.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #ifndef DEBUG 8 | //#define DEBUG 0 // set debug mode 9 | #endif 10 | 11 | // debug functions 12 | #ifdef DEBUG 13 | #define DEBUG_STDERR(x) (std::cerr << (x) << std::endl) 14 | #define DEBUG_STDOUT(x) (std::cout << (x) << std::endl) 15 | 16 | #else 17 | #define DEBUG_STDERR(x) 18 | #define DEBUG_STDOUT(x) 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/common.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | // CUDD and BuDDy both use BDD, we need new names for CUDD::BDD 12 | typedef CUDD::BDD cudd_bdd; 13 | 14 | typedef CUDD::BDD& cudd_bdd_ptr; 15 | 16 | typedef CUDD::Cudd* cudd_ptr; 17 | 18 | typedef CUDD::Cudd cudd; 19 | 20 | typedef DdNode* cudd_node_ptr; 21 | 22 | typedef bdd buddy_bdd; 23 | 24 | typedef bdd& buddy_bdd_ptr; 25 | -------------------------------------------------------------------------------- /examples/counters_2.ltlf: -------------------------------------------------------------------------------- 1 | ((COUNTERENV0 <-> INITCOUNTER0)) && ((COUNTERENV1 <-> INITCOUNTER1)) && (!COUNTERSYS0) && (!COUNTERSYS1) && (G (CARRYENV0 <-> INCENV)) && (G (CARRYSYS0 <-> INCSYS)) && (G (CARRYENV1 <-> (COUNTERENV0 && CARRYENV0))) && (G (CARRYSYS1 <-> (COUNTERSYS0 && CARRYSYS0))) && (G ((X COUNTERENV0 -> !(COUNTERENV0 <-> CARRYENV0)) && (X !COUNTERENV0 -> (COUNTERENV0 <-> CARRYENV0)))) && (G ((X COUNTERSYS0 -> !(COUNTERSYS0 <-> CARRYSYS0)) && (X !COUNTERSYS0 -> (COUNTERSYS0 <-> CARRYSYS0)))) && (G ((X COUNTERENV1 -> !(COUNTERENV1 <-> CARRYENV1)) && (X !COUNTERENV1 -> (COUNTERENV1 <-> CARRYENV1)))) && (G ((X COUNTERSYS1 -> !(COUNTERSYS1 <-> CARRYSYS1)) && (X !COUNTERSYS1 -> (COUNTERSYS1 <-> CARRYSYS1)))) && ((G ((INCENV -> !X INCENV)) -> F ((COUNTERENV0 <-> COUNTERSYS0) && (COUNTERENV1 <-> COUNTERSYS1)))) -------------------------------------------------------------------------------- /src/mona.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "ltlf2fol.hh" 23 | 24 | using namespace spot; 25 | using namespace std; 26 | 27 | bool 28 | str_contain(string str, const char* match); 29 | 30 | void 31 | str_split(string str, vector& result, char delim = ' '); 32 | // translate ltlf formula to DFA via mona 33 | twa_graph_ptr 34 | translate_ltlf_mona(formula ltl, bdd_dict_ptr dict); 35 | 36 | twa_graph_ptr 37 | read_from_mona_file(const char * file_name, bdd_dict_ptr dict); 38 | -------------------------------------------------------------------------------- /src/strategy.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #include "spotutil.hh" 11 | 12 | /** 13 | * here we construct a strategy represented by a bdd such that 14 | * state s needs to give output o iff s /\ o = 1 in the bdd 15 | * */ 16 | 17 | class strategy 18 | { 19 | private: 20 | 21 | bdd& _states_and_outputs; 22 | //buddy_bdd _output_cube; 23 | int _max_state_var = -1; 24 | bdd _anony_cube; 25 | bddPair* _label_to_anony_pair; 26 | bddPair* _anony_to_label_pair; 27 | 28 | bool is_state_variable(int index) 29 | { 30 | return index < _max_state_var; 31 | } 32 | 33 | //buddy_bdd synthesize_strategy_rec(buddy_bdd_ptr s_and_o, int index); 34 | bdd synthesize_strategy_rec(bdd& s_and_o, unordered_map& computed_table); 35 | 36 | public: 37 | 38 | strategy(bdd& s_and_o, bdd output_cube, bdd state_cube); 39 | ~strategy(); 40 | 41 | bdd synthesize_strategy(); 42 | 43 | }; 44 | 45 | -------------------------------------------------------------------------------- /examples/testcase.ltlf: -------------------------------------------------------------------------------- 1 | (a U b) & (F c) 2 | XX!(1 U !((X[!] p1 U (!p2 U (!p0 & !p2))) | X!(1 U !p0))) 3 | X[!] X(1 U (p1 U ((p0 & p1) | !(1 U !p1)))) 4 | G(a | Fb) | (FGb R !b) 5 | G(a | Fb) | (FGb R (X[!] b)) 6 | G(a & Fb) & (FGb R (X[!] b)) 7 | X[!] (p2 & X (p2 U (!p0 | !(1 U !p2)))) 8 | F!(!p1 <-> FGp1) 9 | F(p0 R !p1) 10 | G(p0 | Fp2) W (FGp2 R !p2) 11 | (p2 R G!p1) | G(p2 U !p0) 12 | (p2 W p0) U p2 13 | F!G(!Gp1 W p2) 14 | ((G ((cancel) -> (X (go)))) -> (G ((((req) -> (X ((grant) || (X ((grant) || (X (grant))))))) && ((grant) -> (X (! (grant))))) && ((cancel) -> (X ((! (grant)) U (go))))))) 15 | ((G ((cancel) -> (X[!] (go)))) -> (G ((((req) -> (X[!] ((grant) || (X[!] ((grant) || (X[!] (grant))))))) && ((grant) -> (X[!] (! (grant))))) && ((cancel) -> (X[!] ((! (grant)) U (go))))))) 16 | (G (false | (!(X[!](p12))) | (p5))) & (G (false | (!(X[!](p13))) | (p6))) & (G (false | (!(X[!](p14))) | (p7))) & (G (false | (!(X[!](p15))) | (p8))) 17 | G a 18 | F !a 19 | X a 20 | X[!] a 21 | F a 22 | a U b 23 | (F i2) & (F i1) & (F i1) & (F o2) 24 | (F i3) & (F i2) & (F i1) & (F i1) & (F o2) & (F o3) 25 | (F i4) & (F i3) & (F i2) & (F i1) & (F i1) & (F o2) & (F o3) & (F o4) 26 | (F i5) & (F i4) & (F i3) & (F i2) & (F i1) & (F i1) & (F o2) & (F o3) & (F o4) & (F o5) 27 | (G (r1 -> X[!] g1)) & (G( r2 -> X[!] g2)) & G(!g1 & !g2) 28 | (G (r1 -> X[!] g1)) & (G( r2 -> X[!] g2)) & (G( r3 -> X[!] g3)) & G(!g1 & !g2 & !g3) 29 | (G (r1 -> X[!] g1)) & (G( r2 -> X[!] g2)) & (G( r3 -> X[!] g3)) & (G( r4 -> X[!] g4)) & G(!g1 & !g2 & !g3 & !g4) 30 | -------------------------------------------------------------------------------- /src/aututil.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "spotutil.hh" 14 | 15 | /*-------------------------------------------------------------------*/ 16 | // Project out all the variables specified in @cube the automaton @aut 17 | // if @min is true, determinize and minimize the resulting automaton 18 | /*-------------------------------------------------------------------*/ 19 | 20 | twa_graph_ptr 21 | project(spot::bdd_dict_ptr dict, twa_graph_ptr aut, bdd cube, bool min); 22 | 23 | 24 | /*-------------------------------------------------------------------*/ 25 | // Reverse a finite automaton @aut, i.e., 26 | // 1. (s, a, t) -> (t, a, s) 27 | // 2. s is accepting then make it nonaccepting 28 | /*-------------------------------------------------------------------*/ 29 | twa_graph_ptr 30 | reverse(spot::bdd_dict_ptr dict, twa_graph_ptr aut); 31 | 32 | 33 | /*-------------------------------------------------------------------*/ 34 | // Reduce a finite automaton @aut, i.e., 35 | // @level is the amount of effort for reduction 36 | // 0. low level 37 | // 1. medium level 38 | // 2. high level 39 | /*-------------------------------------------------------------------*/ 40 | twa_graph_ptr 41 | reduce(twa_graph_ptr aut, int level); 42 | -------------------------------------------------------------------------------- /src/specparser.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include // std::setw 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | // for convenience 19 | using json = nlohmann::json; 20 | using namespace std; 21 | using namespace spot; 22 | 23 | // description for the specification 24 | const char* DESCR = "description"; 25 | // assumption for the specification 26 | const char* ASSUMPTIONS = "assumptions"; 27 | // guarantees for the specification 28 | const char* GUARANTEES = "guarantees"; 29 | // inputs for the specification 30 | const char* INPUTS = "inputs"; 31 | // outputs for the specification 32 | const char* OUTPUTS = "outputs"; 33 | // types for the synthesized strategies 34 | const char* TYPE = "type"; 35 | // semantics for the synthesized strategies 36 | const char* SEMANTICS = "semantics"; 37 | // unobservable inputs 38 | const char* UNOBSERS = "unobservable"; 39 | // 40 | //const char* WINNING = "winning"; 41 | // 42 | const char* DOMINANT = "dominant"; 43 | 44 | const char* MEALY = "mealy"; 45 | 46 | 47 | enum class strategy_type { WINNING, DOMINANT }; 48 | enum class strategy_semantics { MOORE, MEALY }; 49 | 50 | struct spec 51 | { 52 | string descr; 53 | 54 | strategy_type start_type; 55 | strategy_semantics start_semantics; 56 | 57 | vector input_aps; 58 | vector output_aps; 59 | vector unobservable_aps; 60 | 61 | vector assumptions; 62 | vector guarantees; 63 | 64 | 65 | friend std::ostream& operator<<(std::ostream& os, const spec& obj); 66 | 67 | }; 68 | 69 | typedef spec* spec_ptr; 70 | 71 | spec_ptr 72 | parse_spec(const char* file_name); 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/ltlf2fol.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "spotutil.hh" 13 | 14 | 15 | 16 | /*-------------------------------------------------------------------*/ 17 | //Translate an LTLf formula to a First-Order Logic (FOL) formula, as described in 18 | // the paper https://www.cs.rice.edu/~vardi/papers/ijcai13.pdf 19 | /*-------------------------------------------------------------------*/ 20 | void 21 | ltlf_to_fol(ostream& os, formula& f); 22 | // helper for translation from LTLf formulas to FOL formulas 23 | string 24 | translate2fol(formula& f, int t, int& c); 25 | 26 | /*-------------------------------------------------------------------*/ 27 | //Translate an LTLf formula to a past First-Order Logic (FOL) formula, as described in 28 | // the paper https://arxiv.org/abs/1901.06108 by Shufang Zhu et al. 29 | /*-------------------------------------------------------------------*/ 30 | void 31 | ltlf_to_pfol(ostream& os, formula& f); 32 | // helper for translation from LTLf formulas to FOL formulas 33 | string 34 | translate2pfol(formula& f, string t, int& c); 35 | 36 | 37 | // TODO: no idea about what this function will do 38 | void 39 | trans_prefixltlf2fol(ostream &os, formula &f); 40 | 41 | string 42 | get_prefix2fol(formula& f, int t, int& c); 43 | 44 | 45 | 46 | /*-------------------------------------------------------------------*/ 47 | // Normal form 48 | /*-------------------------------------------------------------------*/ 49 | 50 | // obtain a formula in negation normal form (NNF) 51 | formula 52 | get_nnf(formula& f); 53 | 54 | // helper for obataining NNF for negation 55 | formula 56 | push_not_in(formula& f); 57 | 58 | // obtain a formula in Boolean normal form (BNF) 59 | // BNF is choosed by default 60 | formula 61 | get_bnf(formula& f); 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/synt.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include "dfwa.hh" 18 | #include "dfwavar.hh" 19 | #include "strategy.hh" 20 | 21 | using namespace std; 22 | using namespace spot; 23 | 24 | enum class synt_result { YES, NO, UNKNOWN }; 25 | 26 | /* 27 | * (X, Y, Z) 28 | * X is the set of input variables (_in_cube) 29 | * Y is the set of output variables (_out_cube) 30 | * Z is the set of state variables 31 | * */ 32 | const char* const REALIZABLE = "REALIZABLE"; 33 | const char* const UNREALIZABLE = "UNREALIZABLE"; 34 | 35 | class synt 36 | { 37 | private: 38 | void prepare(); 39 | bdd pre_image(bdd& w); 40 | 41 | // output transducer 42 | bdd _mealy_init; 43 | bdd _mealy_trans; 44 | bdd _mealy_out; 45 | bool _env_first; 46 | 47 | bool eval(bdd& dd, bdd& assign); 48 | public: 49 | unsigned _copies; 50 | // (Z, Y) is the sequence of winning states and outputs 51 | vector _tseq; 52 | // (Z) is the sequence of winning states 53 | vector _wseq; 54 | // input 55 | bdd _in_cube; 56 | // output 57 | bdd _out_cube; 58 | // rest of propositions 59 | //bdd _rest_cube; 60 | bdd_dict_ptr _dict; 61 | 62 | synt_result _result; 63 | dfwa_ptr _dfa; 64 | 65 | synt(dfwa_ptr dfa, bdd& input_cube, bdd& output_cube) 66 | : _dfa(dfa), _in_cube(input_cube), _out_cube(output_cube) 67 | { 68 | prepare(); 69 | } 70 | 71 | ~synt(); 72 | 73 | void is_realizable(); 74 | 75 | void synthesize(); 76 | 77 | void env_play_first(); 78 | }; 79 | -------------------------------------------------------------------------------- /src/dfwa.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "dfwavar.hh" 19 | #include "debug.hh" 20 | #include "spotutil.hh" 21 | 22 | 23 | // needs to input as pointers 24 | class dfwa 25 | { 26 | public: 27 | twa_graph_ptr _aut; 28 | dfwa_var _state_vars; 29 | bdd _curr_cube; 30 | bdd _next_cube; 31 | bdd _label_cube; 32 | bddPair* _curr_to_next_pairs; 33 | bddPair* _next_to_curr_pairs; 34 | 35 | bdd _init; 36 | bdd _trans; 37 | bdd _finals; 38 | bdd _reach; 39 | // label_cube should not be a pointer 40 | dfwa(bdd_dict_ptr dict, bdd label_cube); 41 | dfwa(twa_graph_ptr aut, bdd label_cube, set& finals, const char* name = "s"); 42 | ~dfwa(); 43 | 44 | bdd next_image(bdd curr); 45 | 46 | bdd pre_image(bdd curr); 47 | 48 | bdd get_init(); 49 | 50 | bdd get_trans(); 51 | 52 | bdd get_finals(); 53 | 54 | bdd explore(); 55 | bdd back_explore(); 56 | 57 | bool is_empty(); 58 | 59 | bdd_dict_ptr get_dict() 60 | { 61 | return _state_vars.get_dict(); 62 | } 63 | 64 | //dfwa& operator &(dfwa& other); 65 | void output(ostream& os); 66 | 67 | void output_dfwa(ostream& os); 68 | 69 | void make_complete(); 70 | 71 | }; 72 | 73 | //ostream& operator<<(ostream& os, const dfwa& dfa); 74 | typedef dfwa& dfwa_ptr; 75 | 76 | //typedef dfwa* dfwa_pointer; 77 | 78 | 79 | void 80 | intersect_dfwa(dfwa_ptr result, dfwa_ptr op1, dfwa_ptr op2); 81 | dfwa_ptr 82 | product_dfwa_and(dfwa_ptr op1, dfwa_ptr op2); 83 | dfwa_ptr 84 | product_dfwa_or(dfwa_ptr op1, dfwa_ptr op2); 85 | dfwa_ptr 86 | product_dfwa_minus(dfwa_ptr op1, dfwa_ptr op2); 87 | -------------------------------------------------------------------------------- /src/spotutil.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | // Enable the strong Next operator for LTLf formula 8 | #define SPOT_WANT_STRONG_X 1 9 | #define SPOT_HAS_STRONG_X 1 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | 39 | using namespace std; 40 | using namespace spot; 41 | 42 | const char* const ALIVE_AP = "alive"; 43 | 44 | string 45 | is_twa_included(twa_graph_ptr aut_a, twa_graph_ptr aut_b); 46 | 47 | string 48 | is_twa_equivalent(twa_graph_ptr aut_a, twa_graph_ptr aut_b); 49 | 50 | twa_graph_ptr 51 | trans_formula(formula f, bdd_dict_ptr dict, unsigned num_ap_for_mona); 52 | 53 | twa_graph_ptr 54 | dfa_to_wdba(twa_graph_ptr aut, bdd_dict_ptr dict, set finals); 55 | 56 | void 57 | get_final_states(twa_graph_ptr aut, set& finals); 58 | 59 | void 60 | get_nonfinal_states(twa_graph_ptr A, set& nonfinals); 61 | 62 | void 63 | compute_final_states(twa_graph_ptr A, set& finals); 64 | 65 | void 66 | compute_accepting_states(twa_graph_ptr A, set& acc); 67 | 68 | unsigned 69 | get_size_formula_ap(formula& f); 70 | 71 | void 72 | get_formula_aps(formula& f, set& aps); 73 | 74 | unsigned 75 | get_size_formula(formula& f); 76 | 77 | bool 78 | is_even(unsigned value); 79 | 80 | void 81 | get_list_var_indices(vector& vars, bdd cube); 82 | 83 | void 84 | output_bdd(ostream& os, bdd dd); 85 | 86 | bdd 87 | local_bdd_and(bdd& op1, bdd& op2); 88 | 89 | bdd 90 | local_bdd_or(bdd& op1, bdd& op2); 91 | 92 | bdd 93 | local_bdd_not_and(bdd& op1, bdd& op2); 94 | -------------------------------------------------------------------------------- /src/argparser.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #include "argparser.hh" 6 | 7 | /* Parse a single option. */ 8 | static error_t 9 | parse_opt (int key, char *arg, struct argp_state *state) 10 | { 11 | /* Get the input argument from argp_parse, which we 12 | know is a pointer to our arguments structure. */ 13 | struct arguments *arguments = (struct arguments *)state->input; 14 | 15 | switch (key) 16 | { 17 | case 'q': case 's': 18 | arguments->silent = 1; 19 | break; 20 | case 'v': 21 | arguments->verbose = 1; 22 | break; 23 | case 'o': 24 | arguments->output_file = arg; 25 | break; 26 | case 'r': 27 | arguments->repeat_count = arg ? atoi (arg) : 10; 28 | break; 29 | case OPT_ABORT: 30 | arguments->abort = 1; 31 | break; 32 | 33 | case ARGP_KEY_NO_ARGS: 34 | argp_usage (state); 35 | 36 | case ARGP_KEY_ARG: 37 | /* Here we know that state->arg_num == 0, since we 38 | force argument parsing to end before any more arguments can 39 | get here. */ 40 | arguments->arg1 = arg; 41 | 42 | /* Now we consume all the rest of the arguments. 43 | state->next is the index in state->argv of the 44 | next argument to be parsed, which is the first string 45 | we're interested in, so we can just use 46 | &state->argv[state->next] as the value for 47 | arguments->strings. 48 | 49 | In addition, by setting state->next to the end 50 | of the arguments, we can force argp to stop parsing here and 51 | return. */ 52 | arguments->strings = &state->argv[state->next]; 53 | state->next = state->argc; 54 | 55 | break; 56 | 57 | default: 58 | return ARGP_ERR_UNKNOWN; 59 | } 60 | return 0; 61 | } 62 | 63 | /* Our argp parser. */ 64 | static struct argp argp = { options, parse_opt, args_doc, doc }; 65 | 66 | int main (int argc, char **argv) 67 | { 68 | int i, j; 69 | struct arguments arguments; 70 | 71 | /* Default values. */ 72 | arguments.silent = 0; 73 | arguments.verbose = 0; 74 | arguments.output_file = nullptr; 75 | arguments.repeat_count = 1; 76 | arguments.abort = 0; 77 | 78 | /* Parse our arguments; every option seen by parse_opt will be 79 | reflected in arguments. */ 80 | argp_parse (&argp, argc, argv, 0, 0, &arguments); 81 | 82 | if (arguments.abort) 83 | error (10, 0, "ABORTED"); 84 | 85 | for (i = 0; i < arguments.repeat_count; i++) 86 | { 87 | printf ("ARG1 = %s\n", arguments.arg1); 88 | printf ("STRINGS = "); 89 | for (j = 0; arguments.strings[j]; j++) 90 | printf (j == 0 ? "%s" : ", %s", arguments.strings[j]); 91 | printf ("\n"); 92 | printf ("OUTPUT_FILE = %s\nVERBOSE = %s\nSILENT = %s\n", 93 | arguments.output_file, 94 | arguments.verbose ? "yes" : "no", 95 | arguments.silent ? "yes" : "no"); 96 | } 97 | 98 | exit (0); 99 | } 100 | //Go to the first, previous, next, last section, table of 101 | 102 | -------------------------------------------------------------------------------- /src/strategy.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #include "strategy.hh" 6 | 7 | // NOTE THAT the ordering of the variables is A, X, X' 8 | // first traverse the possible values of 9 | // if the ordering is X, A 10 | // then get bdd_satone when first get to the label variables 11 | 12 | strategy::strategy(bdd& s_and_o, bdd output_cube, bdd state_cube) 13 | : _states_and_outputs(s_and_o) 14 | { 15 | vector list_label_vars; 16 | get_list_var_indices(list_label_vars, output_cube); 17 | vector list_state_vars; 18 | get_list_var_indices(list_state_vars, state_cube); 19 | // largest state variable occuring in _states_and_outputs 20 | _max_state_var = list_state_vars.back() + 1; 21 | _label_to_anony_pair = bdd_newpair(); 22 | _anony_to_label_pair = bdd_newpair(); 23 | // compute pairs 24 | _anony_cube = bddtrue; 25 | for(unsigned i = 0; i < list_label_vars.size(); i ++) 26 | { 27 | int anony_index = _max_state_var + i; 28 | bdd_setpair(_label_to_anony_pair, list_label_vars[i], anony_index); 29 | bdd_setpair(_anony_to_label_pair, anony_index, list_label_vars[i]); 30 | _anony_cube = _anony_cube & bdd_ithvar(anony_index); 31 | } 32 | } 33 | 34 | strategy::~strategy() 35 | { 36 | if(_label_to_anony_pair != nullptr) 37 | { 38 | bdd_freepair(_label_to_anony_pair); 39 | _label_to_anony_pair = nullptr; 40 | } 41 | if(_anony_to_label_pair != nullptr) 42 | { 43 | bdd_freepair(_anony_to_label_pair); 44 | _anony_to_label_pair = nullptr; 45 | } 46 | } 47 | 48 | bdd 49 | strategy::synthesize_strategy() 50 | { 51 | bdd new_state_output = bdd_replace(_states_and_outputs, _label_to_anony_pair); 52 | unordered_map computed_table; 53 | bdd func_output = synthesize_strategy_rec(new_state_output, computed_table); 54 | func_output = bdd_replace(func_output, _anony_to_label_pair); 55 | return func_output; 56 | } 57 | 58 | /* 59 | buddy_bdd 60 | strategy::synthesize_strategy_rec(buddy_bdd_ptr s_and_o, int index) 61 | { 62 | return bddtrue; 63 | } 64 | */ 65 | // if the ordering is X, A 66 | // then get bdd_satone when first get to the label variables 67 | bdd 68 | strategy::synthesize_strategy_rec(bdd& s_and_o 69 | , unordered_map& computed_table) 70 | { 71 | if(s_and_o == bddfalse) 72 | { 73 | return bddfalse; 74 | } 75 | // check whether it has been computed 76 | int dd_id = s_and_o.id(); 77 | unordered_map::const_iterator it = computed_table.find(dd_id); 78 | if(it != computed_table.end()) 79 | { 80 | return it->second; 81 | } 82 | // now check if it is true 83 | 84 | if(s_and_o == bddtrue ) 85 | { 86 | // choose one sat 87 | bdd set = bdd_satoneset(s_and_o, _anony_cube, bddtrue); 88 | computed_table[dd_id] = set; 89 | return set; 90 | } 91 | bdd result; 92 | int top_var = bdd_var(s_and_o); 93 | if(is_state_variable(top_var)) 94 | { 95 | // now do it recursively 96 | bdd low_branch = bdd_low(s_and_o); 97 | bdd low = synthesize_strategy_rec(low_branch, computed_table); 98 | bdd high_branch = bdd_high(s_and_o); 99 | bdd high = synthesize_strategy_rec(high_branch, computed_table); 100 | bdd var_dd = bdd_ithvar(top_var); 101 | result = bdd_ite(var_dd, high, low); 102 | }else 103 | { 104 | // reach non state variables 105 | result = bdd_satoneset(s_and_o, _anony_cube, bddtrue); 106 | } 107 | computed_table[dd_id] = result; 108 | return result; 109 | } 110 | -------------------------------------------------------------------------------- /src/dfwavar.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | 20 | using namespace std; 21 | using namespace spot; 22 | 23 | static unsigned index_for_vars = 0; 24 | 25 | unsigned 26 | get_num_bits(int value); 27 | 28 | /** 29 | * Use dict to register anonymous variables as state variables. 30 | * remember to register the variables whenever use the state variables 31 | * and release the variables in destructor. 32 | * */ 33 | class dfwa_var 34 | { 35 | private: 36 | void prepare_vars(); 37 | const char* UNDERSCORE = "_"; 38 | void order_vars(); 39 | 40 | public: 41 | dfwa_var(bdd_dict_ptr dict, twa_graph_ptr aut, unsigned copies, string name, int lower, int upper) 42 | : _dict(dict), _aut(aut), _copies(copies), _name(name), _lower(lower), _upper(upper) 43 | { 44 | assert(lower <= upper); 45 | prepare_vars(); 46 | } 47 | 48 | unsigned _copies = 0; 49 | vector> _dd_vars; 50 | bdd_dict_ptr _dict; 51 | vector> _dd_names; 52 | //vector _dd_nums; 53 | string _name; 54 | int _lower; 55 | int _upper; 56 | twa_graph_ptr _aut; 57 | 58 | 59 | // for product 60 | dfwa_var(bdd_dict_ptr dict); 61 | 62 | ~dfwa_var(); 63 | int get_lower() 64 | { 65 | return _lower; 66 | } 67 | int get_upper() 68 | { 69 | return _upper; 70 | } 71 | 72 | string get_name() 73 | { 74 | return _name; 75 | } 76 | 77 | unsigned get_copies() 78 | { 79 | return _copies; 80 | } 81 | 82 | unsigned get_var_num(int copy) 83 | { 84 | return _dd_vars[copy].size(); 85 | } 86 | 87 | bdd_dict_ptr get_dict() 88 | { 89 | return _dict; 90 | } 91 | 92 | bdd& get_var(int copy, int index) 93 | { 94 | assert(index >= 0 95 | && copy < _copies 96 | && _dd_vars[copy].size() > index); 97 | return _dd_vars[copy][index]; 98 | } 99 | 100 | int get_var_id(int copy, int index) 101 | { 102 | return bdd_var(get_var(copy, index)); 103 | } 104 | 105 | void pop_back_vars(); 106 | 107 | void add_bdd_vars(dfwa_var& vars); 108 | 109 | // when the ordering of the variables does not matter 110 | void add_ordered_bdd_vars(dfwa_var& vars); 111 | 112 | //void add_bdd_vars(vector& vars_vec); 113 | 114 | vector& get_bdd_vars(unsigned copy) 115 | { 116 | return _dd_vars[copy]; 117 | } 118 | // only contains variables 119 | int to_integer(bdd dd); 120 | 121 | bdd new_value(int copy, int value); 122 | 123 | void new_value(vector& bits, int copy, int value); 124 | 125 | bdd get_cube(int copy); 126 | 127 | bddPair* make_pair(unsigned fst_copy, unsigned snd_copy); 128 | }; 129 | 130 | typedef dfwa_var& dfwa_var_ptr; 131 | -------------------------------------------------------------------------------- /src/argparser.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | // This file is adapted from Argp example #4 at https://www.gnu.org/software/libc/manual/html_node/Argp-Example-4.html 12 | 13 | const char *argp_program_version = 14 | "lisa v0.1"; 15 | 16 | const char *argp_program_bug_address = 17 | ""; 18 | 19 | /* Program documentation. */ 20 | static char doc[] = 21 | "Translate an LTLf formula to a DFA and perform synthesis if necessary"; 22 | /* 23 | \ 24 | options\ 25 | \vThis part of the documentation comes *after* the options;\ 26 | note that the text is automatically filled, but it's possible\ 27 | to force a line-break, e.g.\n<-- here."; 28 | */ 29 | 30 | /* A description of the arguments we accept. */ 31 | static char args_doc[] = "[SPECIFICATION...]"; 32 | 33 | /* Keys for options without short-options. */ 34 | #define OPT_ABORT 1 /* --abort */ 35 | 36 | /* The options we understand. */ 37 | static struct argp_option options[] = { 38 | 39 | // second argument is the key for parsing arguments 40 | /*-------------------------------------------*/ 41 | { 0,0,0,0, "Input:", 1 }, 42 | {"formula", 'f', "STRING" , 0, "Process the specification STRING"}, 43 | // use json format 44 | {"file", 'F', "FILE" , 0, "Process the specification in FILE"}, 45 | {"verbose", 'v', 0, 0, "Produce verbose output" }, 46 | {"quiet", 'q', 0, 0, "Don't produce any output" }, 47 | //{"silent", 's', 0, OPTION_ALIAS }, 48 | {"output", 'o', "FILE", OPTION_ARG_OPTIONAL, "Output to FILE instead of standard output" }, 49 | 50 | /*-------------------------------------------*/ 51 | {0,0,0,0, "DFA construction:", 2}, 52 | {"explicit", 'e', 0, OPTION_ARG_OPTIONAL, "Only explicit approach for DFA construction\n(Default: false)"}, 53 | {"individual", 'i', "INT", 0, "Switch to symbolic approach when the number of states of an individual DFA exceeds INT\n(Default: 800)"}, 54 | {"product", 'p', "INT", 0, "Switch to symbolic approach when the number of states of a product DFA exceeds INT\n(Default: 2500)"}, 55 | 56 | /*-------------------------------------------*/ 57 | {0,0,0,0, "Synthesis:", 3 }, 58 | {"synthesize", 's', 0, OPTION_ARG_OPTIONAL, 59 | "Synthesize a strategy from the specification"}, 60 | 61 | /*-------------------------------------------*/ 62 | {0,0,0,0, "DFA minimization:", 4 }, 63 | {"minimize", 'm', 0, 0, 64 | "Minimize the DFA for the specification"}, 65 | 66 | /*-------------------------------------------*/ 67 | {0,0,0,0, "BDD choice:", 5}, 68 | {"cudd", 'c', 0, 0, 69 | "Apply CUDD for DFA minimization"}, 70 | {"buddy", 'b', 0, 0, 71 | "Apply BuDDy for DFA minimization"}, 72 | {"sylvan", 'y', 0, 0, 73 | "Apply Sylvan for DFA minimization"}, 74 | 75 | /*-------------------------------------------*/ 76 | {0,0,0,0, "Miscellaneous options:", -1}, 77 | { nullptr, 0, nullptr, 0, nullptr, 0 } 78 | //{"help", 'h', 0, 0, "print this help page" }, 79 | //{0} 80 | }; 81 | 82 | // command line parser 83 | static struct opt_t 84 | { 85 | const char* _ltlfile_name = nullptr; 86 | const char* _parfile_name = nullptr; 87 | 88 | bool _symbolic = true; 89 | bool _minimization = false; 90 | 91 | unsigned _num_ap_for_mona = 7; 92 | unsigned _num_product = 6; 93 | unsigned _num_st_for_single = 800; 94 | unsigned _num_st_for_product = 2500; 95 | int _num_last_automata = -1; 96 | 97 | bool _synthesis = false; 98 | bool _out_start = false; 99 | bool _env_first = false; 100 | 101 | uint8_t _bdd = 0; 102 | 103 | }* opt; 104 | 105 | /* Used by main to communicate with parse_opt. */ 106 | struct arguments 107 | { 108 | char *arg1; /* arg1 */ 109 | char **strings; /* [string...] */ 110 | int silent, verbose, abort; /* `-s', `-v', `--abort' */ 111 | char *output_file; /* file arg to `--output' */ 112 | int repeat_count; /* count arg to `--repeat' */ 113 | }; 114 | 115 | 116 | -------------------------------------------------------------------------------- /src/dfwamin2.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #ifndef __ORIGINAL__ 8 | #define __ORIGINAL__ 1 // set original mode 9 | #endif 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | //#include 18 | 19 | 20 | #include "common.hh" 21 | 22 | #include "dfwa.hh" 23 | #include "dfwavar.hh" 24 | #include "spotutil.hh" 25 | 26 | //using namespace CUDD; 27 | using namespace std; 28 | 29 | //static unsigned nodes_num = 0; 30 | 31 | /** 32 | * The input DFA has the ordering of A, (X, X') 33 | * The ordering of BDD variables in the DFA minimization is A, (X, X'), A' and then K (block variables) 34 | * the strategy for changing the order of a BDD data structure in BuDDy is as follows: 35 | * renaming A to A' in T(A, (X, X')) before doing DFA minimization 36 | * 37 | * CUDD is good at renaming and building BDDs, and BuDDy is good at state space exploration 38 | * */ 39 | 40 | class dfwa_min_bdd 41 | { 42 | public: 43 | dfwa_min_bdd(dfwa_ptr aut); 44 | // cube bdd 45 | buddy_bdd _curr_cube; 46 | buddy_bdd _next_cube; 47 | buddy_bdd _label_cube; 48 | 49 | // dfa (I(X) T(X, X', A), F(X)) 50 | buddy_bdd _init; 51 | buddy_bdd _trans; 52 | buddy_bdd _finals; 53 | 54 | // first position after state variables 55 | int _max_states_var = -1; //_last_pos_states; 56 | // first position after label variables 57 | unsigned _last_pos_labels; 58 | 59 | unsigned _num_min_states; 60 | 61 | #ifdef __ORIGINAL__ 62 | // state to anonymous 63 | bddPair* _state_to_anony_pair = nullptr; 64 | bddPair* _curr_to_next_state_pair = nullptr; 65 | bddPair* _next_to_curr_state_pair = nullptr; 66 | unordered_map _map; 67 | //unordered_map _anony_to_label; 68 | 69 | #endif 70 | // state variables 71 | vector> _state_vars; 72 | // block variables 73 | vector> _block_vars; 74 | bddPair* _curr_to_next_block_pair = nullptr; 75 | bddPair* _next_to_curr_block_pair = nullptr; 76 | 77 | // new to label 78 | bddPair* _label_to_anony_pair = nullptr; 79 | bddPair* _anony_to_label_pair = nullptr; 80 | // label variables 81 | vector _label_vars; 82 | 83 | dfwa_ptr _aut; 84 | 85 | ~dfwa_min_bdd(); 86 | 87 | void minimize(); 88 | 89 | dfwa_ptr move_dfwa(); 90 | 91 | //dfwa& operator &(dfwa& other); 92 | void output(ostream& os); 93 | 94 | unsigned get_num_min_states() 95 | { 96 | return _num_min_states; 97 | } 98 | private: 99 | 100 | bool is_state_variable(const unsigned var_index) 101 | { 102 | return var_index < _max_states_var; 103 | } 104 | 105 | // prepare for the minimization 106 | void prepare(); 107 | void prepare_variables(); 108 | 109 | // bdd_replace function for cudd 110 | buddy_bdd move_to(buddy_bdd dd); 111 | buddy_bdd move_to(buddy_bdd dd, unordered_map& computed_table); 112 | 113 | // helper functions for minimization 114 | void new_block_variables(unsigned num = 1); 115 | buddy_bdd new_block_number(int block_number, int copy); 116 | buddy_bdd initialize_partition(); 117 | pair refine_partition(buddy_bdd_ptr sig); 118 | buddy_bdd refine_partition_rec(buddy_bdd_ptr dd, unsigned & block_number, unordered_map &computed_table); 119 | void compute_block_number_rec(buddy_bdd_ptr sig, unordered_map& table, int & block_number); 120 | void reduce_block_variables(buddy_bdd_ptr partition); 121 | 122 | // print functions 123 | void print(buddy_bdd bdd); 124 | void generate_all_bits(vector& vars, unsigned index, buddy_bdd_ptr dd, buddy_bdd temp); 125 | 126 | // state space exploration 127 | buddy_bdd next_image(buddy_bdd_ptr curr); 128 | buddy_bdd pre_image(buddy_bdd_ptr curr); 129 | buddy_bdd forward_explore(); 130 | buddy_bdd backward_explore(); 131 | }; 132 | -------------------------------------------------------------------------------- /src/testencode.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | // standard 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // spot 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #include "spotutil.hh" 36 | #include "mona.hh" 37 | #include "ltlf2fol.hh" 38 | #include "aututil.hh" 39 | #include "dfwa.hh" 40 | 41 | using namespace spot; 42 | using namespace std; 43 | 44 | int main(int argc, char **argv) 45 | { 46 | if (argc < 1 || argc > 3) 47 | std::cout << "please input formula file" << std::endl; 48 | 49 | ifstream ltlfile(argv[1]); 50 | string line; 51 | bdd_dict_ptr dict = make_bdd_dict(); 52 | // ltlfile.open(argv[1]); 53 | 54 | //cout << "Opened file" << endl; 55 | 56 | if (ltlfile.is_open()) 57 | { 58 | //cout << "We are inside the file" << endl; 59 | while (getline(ltlfile, line)) 60 | { 61 | //cout << "formula: " << line << endl; 62 | auto pf1 = spot::parse_infix_psl(line.c_str()); 63 | if (pf1.format_errors(std::cerr)) 64 | { 65 | std::cerr << "error: " << line << std::endl; 66 | return -1; 67 | } 68 | //cout << "parsed formula: " << endl; 69 | formula f = pf1.f; 70 | cout << "formula: " << f << endl; 71 | string mona_file_name2 = "./ltlf2.mona"; 72 | ofstream ofs2(mona_file_name2, ofstream::out); 73 | ofs2 << "#LTLf formula" << endl; 74 | ofs2 << "#" << str_psl(f, true) << endl; 75 | ofs2 << "# Backus normal form" << endl; 76 | formula r = get_bnf(f); 77 | // output in a parsable formula 78 | // the BNF form, and then convert it to fol formula 79 | ltlf_to_pfol(ofs2, r); 80 | ofs2.close(); 81 | //cout << "formula: " << str_psl(f, true) << endl; 82 | // now call ltlf2fol 83 | //string mona_file_name = "./ltlf.mona"; 84 | //string command = "./ltlf2fol NNF " + fol_file_name + " > " + mona_file_name; 85 | //system(command.c_str()); 86 | string dfa_file_name = "./mona.dfa"; 87 | string command = "mona -u -xw " + mona_file_name2 + " >" + dfa_file_name; 88 | system(command.c_str()); 89 | // if this turns to be a bottleneck, we need pthread to read from pipe 90 | twa_graph_ptr dfa = read_from_mona_file(dfa_file_name.c_str(), dict); 91 | cout << "#Past DFA: " << dfa->num_states() << endl; 92 | //aut4->merge_edges(); 93 | //ofstream outfile1("output4.hoa"); 94 | //print_hoa(outfile1, aut4); 95 | //outfile1.close(); 96 | // reverse 97 | //cout << "Output aut5" << endl; 98 | twa_graph_ptr nfa = reverse(dict, dfa); 99 | cout << "#Reverse NFA: " << nfa->num_states() << endl; 100 | //aut5->merge_edges(); 101 | //ofstream outfile2("output5.hoa"); 102 | //print_hoa(outfile2, aut5); 103 | //outfile2.close(); 104 | // symbolic encoding 105 | nfa = reduce(nfa, 1); 106 | cout << "#Reduced FA: " << nfa->num_states() << endl; 107 | set nonfinals; 108 | get_nonfinal_states(nfa, nonfinals); 109 | map &var_map = nfa->get_dict()->var_map; 110 | map::const_iterator iter = var_map.begin(); 111 | bdd labelcube = bddtrue; 112 | while (iter != var_map.end()) 113 | { 114 | formula key = iter->first; 115 | int value = iter->second; 116 | //cout << key << " -> " << value << endl; 117 | labelcube = labelcube & bdd_ithvar(value); 118 | iter++; 119 | } 120 | clock_t start = clock(); 121 | if(is_deterministic(nfa)) 122 | { 123 | cout << "Deterministic" << endl; 124 | dfwa *ret = new dfwa(nfa, labelcube, nonfinals); 125 | delete ret; 126 | }else 127 | { 128 | cout << "Nondeterministic" << endl; 129 | dfwa *ret = new dfwa(nfa, labelcube, nonfinals, true); 130 | delete ret; 131 | } 132 | 133 | clock_t end = clock(); 134 | cout << "Total CPU time used for encoding NFA: " << 1000.0 * (end - start) / CLOCKS_PER_SEC << " ms\n"; 135 | 136 | } 137 | } 138 | ltlfile.close(); 139 | return 0; 140 | } 141 | -------------------------------------------------------------------------------- /src/specparser.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #include "specparser.hh" 6 | 7 | spec_ptr 8 | parse_spec(const char *file_name) 9 | { 10 | spec_ptr p = new spec; 11 | 12 | json j; 13 | ifstream ispecfile(file_name); 14 | ispecfile >> j; 15 | cout << j << endl; 16 | 17 | p->descr = j[DESCR]; 18 | 19 | vector assumps = j[ASSUMPTIONS]; 20 | cout << "Assumptions: " << endl; 21 | for (string assump : assumps) 22 | { 23 | auto pf1 = spot::parse_infix_psl(assump.c_str()); 24 | formula conjunct = pf1.f; 25 | p->assumptions.push_back(conjunct); 26 | cout << pf1.f << endl; 27 | } 28 | cout << "Guarantees: " << endl; 29 | vector guarantees = j[GUARANTEES]; 30 | for (string guarantee : guarantees) 31 | { 32 | auto pf1 = spot::parse_infix_psl(guarantee.c_str()); 33 | formula conjunct = pf1.f; 34 | p->guarantees.push_back(conjunct); 35 | cout << pf1.f << endl; 36 | } 37 | 38 | for (string input_ap : j[INPUTS]) 39 | { 40 | p->input_aps.push_back(input_ap); 41 | cout << "in: " << input_ap << endl; 42 | } 43 | 44 | for (string output_ap : j[OUTPUTS]) 45 | { 46 | p->output_aps.push_back(output_ap); 47 | cout << "out: " << output_ap << endl; 48 | } 49 | 50 | for (string ubobs_ap : j[UNOBSERS]) 51 | { 52 | p->unobservable_aps.push_back(ubobs_ap); 53 | cout << "unobservable: " << ubobs_ap << endl; 54 | } 55 | 56 | if (j[TYPE] == DOMINANT) 57 | { 58 | p->start_type = strategy_type::DOMINANT; 59 | } 60 | else 61 | { 62 | p->start_type = strategy_type::WINNING; 63 | cout << "Winning" << endl; 64 | } 65 | 66 | if (j[SEMANTICS] == MEALY) 67 | { 68 | p->start_semantics = strategy_semantics::MEALY; 69 | } 70 | else 71 | { 72 | p->start_semantics = strategy_semantics::MOORE; 73 | cout << "Moore" << endl; 74 | } 75 | 76 | return p; 77 | } 78 | 79 | std::ostream & 80 | operator<<(std::ostream &os, const spec &obj) 81 | { 82 | // write obj to stream 83 | os << "[" << endl; 84 | os << setw(4) << "\"" << DESCR << "\": \"" << obj.descr << "\"," << endl; 85 | os << setw(4) << "\"" << SEMANTICS << "\": \"" << (obj.start_semantics == strategy_semantics::MEALY ? "mealy" : "moore") << "\"," << endl; 86 | os << setw(4) << "\"" << TYPE << "\": \"" << (obj.start_type ==strategy_type::WINNING ? "winning" : "dominant") << "\"," << endl; 87 | os << setw(4) << "\"" << INPUTS << "\": ["; 88 | bool first = true; 89 | for (string in : obj.input_aps) 90 | { 91 | if (first) 92 | { 93 | os << "\"" << in << "\""; 94 | first = false; 95 | } 96 | else 97 | { 98 | os << ", \"" << in << "\""; 99 | } 100 | } 101 | os << "]," << endl; 102 | os << setw(4) << "\"" << OUTPUTS << "\": ["; 103 | first = true; 104 | for (string out : obj.output_aps) 105 | { 106 | if (first) 107 | { 108 | os << "\"" << out << "\""; 109 | first = false; 110 | } 111 | else 112 | { 113 | os << ", \"" << out << "\""; 114 | } 115 | } 116 | os << "]," << endl; 117 | os << setw(4) << "\"" << UNOBSERS << "\": ["; 118 | first = true; 119 | for (string in : obj.unobservable_aps) 120 | { 121 | if (first) 122 | { 123 | os << "\"" << in << "\""; 124 | first = false; 125 | } 126 | else 127 | { 128 | os << ", \"" << in << "\""; 129 | } 130 | } 131 | os << "]," << endl; 132 | 133 | os << setw(4) << "\"" << ASSUMPTIONS << "\": ["; 134 | if (obj.assumptions.size() == 0) 135 | { 136 | os << "]," << endl; 137 | } 138 | else 139 | { 140 | first = true; 141 | os << endl; 142 | for (formula f : obj.assumptions) 143 | { 144 | if (first) 145 | { 146 | os << setw(6) << "\"" << str_psl(f, true) << "\"" << endl; 147 | first = false; 148 | } 149 | else 150 | { 151 | os << setw(6) << ", \"" << str_psl(f, true) << "\"" << endl; 152 | } 153 | } 154 | os << setw(4) << "]," << endl; 155 | } 156 | 157 | os << setw(4) << "\"" << GUARANTEES << "\": ["; 158 | if (obj.guarantees.size() == 0) 159 | { 160 | os << "]," << endl; 161 | } 162 | else 163 | { 164 | first = true; 165 | os << endl; 166 | for (formula f : obj.guarantees) 167 | { 168 | if (first) 169 | { 170 | os << setw(6) << "\"" << str_psl(f, true) << "\"" << endl; 171 | first = false; 172 | } 173 | else 174 | { 175 | os << setw(6) << ", \"" << str_psl(f, true) << "\"" << endl; 176 | } 177 | } 178 | os << setw(4) << "]" << endl; 179 | } 180 | os << "]" << endl; 181 | return os; 182 | } 183 | 184 | int main(int argc, char **args) 185 | { 186 | char *name = args[1]; 187 | spec_ptr sp = parse_spec(name); 188 | cout << *sp << endl; 189 | delete sp; 190 | return 0; 191 | } -------------------------------------------------------------------------------- /src/dfwamin.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | //#include 14 | 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "dfwa.hh" 21 | #include "dfwavar.hh" 22 | #include "spotutil.hh" 23 | 24 | //using namespace CUDD; 25 | using namespace std; 26 | 27 | // CUDD and BuDDy both use BDD, we need new names for CUDD::BDD 28 | typedef CUDD::BDD cudd_bdd; 29 | 30 | typedef CUDD::BDD& cudd_bdd_ptr; 31 | 32 | typedef CUDD::Cudd* cudd_ptr; 33 | 34 | typedef CUDD::Cudd cudd; 35 | 36 | typedef DdNode* cudd_node_ptr; 37 | 38 | typedef bdd buddy_bdd; 39 | 40 | typedef bdd& buddy_bdd_ptr; 41 | 42 | static unsigned nodes_num = 0; 43 | 44 | typedef std::tuple key_triple; 45 | struct key_hash: public std::unary_function 46 | { 47 | std::size_t operator()(const key_triple& k) const 48 | { 49 | return (long)get<0>(k) ^ (long)get<1>(k) ^ (long)get<2>(k); 50 | } 51 | }; 52 | 53 | struct key_equal: public std::function 54 | { 55 | bool operator()(const key_triple& k1, const key_triple& k2) const 56 | { 57 | return get<0>(k1) == get<0>(k2) 58 | && get<1>(k1) == get<1>(k2) 59 | && get<2>(k1) == get<2>(k2); 60 | } 61 | }; 62 | 63 | typedef unordered_map map_t; 64 | 65 | /** 66 | * The ordering of BDD variables in the DFA: (X, X'), A and then K (block variables) 67 | * the strategy for moving a BDD data structure from BuDDy to CUDD is as follows: 68 | * 1. create variables A', X, X', A, K in CUDD, where A', X, X' are used in migration 69 | * 2. renaming A' to A before doing DFA minimization 70 | * */ 71 | 72 | class dfwa_min 73 | { 74 | public: 75 | dfwa_min(cudd_ptr manager, dfwa_ptr aut) 76 | :_manager(manager), _aut (aut) 77 | { 78 | prepare(); 79 | } 80 | // cube bdd 81 | cudd_bdd _curr_cube; 82 | cudd_bdd _next_cube; 83 | cudd_bdd _label_cube; // seems to be redundant 84 | 85 | // dfa (I(X) T(X, X', A), F(X)) 86 | cudd_bdd _init; 87 | cudd_bdd _trans; 88 | cudd_bdd _finals; 89 | 90 | // first position after state variables 91 | unsigned _num_states_vars; //_last_pos_states; 92 | // first position after label variables 93 | unsigned _last_pos_labels; 94 | 95 | unsigned _num_min_states; 96 | 97 | // state variables 98 | vector> _state_vars; 99 | // block variables 100 | vector> _block_vars; 101 | // label variables 102 | vector _label_vars; 103 | 104 | // utility for mapping to and from BuDDy bdds 105 | vector _cudd_to_buddy_vars; 106 | unordered_map _buddy_to_cudd_vars; 107 | 108 | dfwa_ptr _aut; 109 | 110 | // CUDD manager 111 | cudd_ptr _manager = nullptr; 112 | 113 | ~dfwa_min(); 114 | 115 | void minimize(); 116 | 117 | dfwa_ptr move_dfwa(); 118 | 119 | //dfwa& operator &(dfwa& other); 120 | void output(ostream& os); 121 | 122 | unsigned get_num_min_states() 123 | { 124 | return _num_min_states; 125 | } 126 | private: 127 | 128 | bool is_state_variable(const unsigned var_index) 129 | { 130 | return var_index < _num_states_vars; 131 | } 132 | 133 | // prepare for the minimization 134 | void prepare(); 135 | void prepare_variables(); 136 | 137 | // move BDD to a different BDD manager 138 | cudd_bdd move_to_cudd(buddy_bdd dd); 139 | cudd_bdd move_to_cudd(buddy_bdd dd, unordered_map& computed_table); 140 | 141 | // move BDD from CUDD to BuDDy 142 | buddy_bdd move_to_buddy(cudd_bdd dd, unordered_map& cudd_to_buddy_map); 143 | buddy_bdd move_to_buddy(cudd_bdd_ptr dd, unordered_map& cudd_to_buddy_map 144 | , unordered_map& computed_table); 145 | 146 | // bdd_replace function for cudd 147 | cudd_bdd cudd_permute(cudd_bdd_ptr dd, vector& from, vector& to); 148 | 149 | // helper functions for minimization 150 | void new_block_variables(unsigned num = 1); 151 | cudd_bdd new_block_number(int block_number, int copy); 152 | cudd_bdd initialize_partition(); 153 | pair refine_partition(cudd_bdd_ptr sig); 154 | cudd_bdd refine_partition_rec(cudd_bdd_ptr dd, unsigned & block_number, unordered_map &computed_table); 155 | void compute_block_number_rec(cudd_bdd_ptr sig, unordered_map& table, int & block_number); 156 | void reduce_block_variables(cudd_bdd_ptr partition); 157 | 158 | cudd_bdd make_quotient_trans(cudd_bdd_ptr trans, cudd_bdd_ptr curr_partition, cudd_bdd_ptr next_partition); 159 | cudd_bdd make_quotient_trans(cudd_bdd trans, cudd_bdd curr_partition, cudd_bdd next_partition, vector>& var_sets, map_t& computed_table); 160 | 161 | // print functions 162 | void print(cudd_bdd bdd); 163 | void generate_all_bits(vector& vars, unsigned index, cudd_bdd_ptr dd, cudd_bdd temp); 164 | 165 | // state space exploration 166 | cudd_bdd next_image(cudd_bdd_ptr curr); 167 | cudd_bdd pre_image(cudd_bdd_ptr curr); 168 | cudd_bdd forward_explore(); 169 | cudd_bdd backward_explore(); 170 | }; 171 | -------------------------------------------------------------------------------- /src/dfwamin3.hh: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | //#include 14 | 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "dfwa.hh" 21 | #include "dfwavar.hh" 22 | #include "spotutil.hh" 23 | 24 | //using namespace CUDD; 25 | using namespace std; 26 | using namespace sylvan; 27 | 28 | // this file will use sylvan 29 | 30 | // CUDD and BuDDy both use BDD, we need new names for CUDD::BDD 31 | 32 | typedef bdd buddy_bdd; 33 | 34 | typedef bdd& buddy_bdd_ptr; 35 | 36 | typedef Bdd sylvan_bdd; 37 | typedef BddSet sylvan_bdd_set; 38 | typedef Bdd& sylvan_bdd_ptr; 39 | 40 | typedef sylvan::BDD sylvan_BDD; 41 | 42 | 43 | //static unsigned nodes_num = 0; 44 | 45 | 46 | /** 47 | * The ordering of BDD variables in the DFA: (X, X'), A and then K (block variables) 48 | * the strategy for moving a BDD data structure from BuDDy to CUDD is as follows: 49 | * 1. create variables A', X, X', A, K in CUDD, where A', X, X' are used in migration 50 | * 2. renaming A' to A before doing DFA minimization 51 | * */ 52 | 53 | typedef std::tuple key_triple_sylvan; 54 | struct key_hash_sylvan: public std::unary_function 55 | { 56 | std::size_t operator()(const key_triple_sylvan& k) const 57 | { 58 | return (long)get<0>(k) ^ (long)get<1>(k) ^ (long)get<2>(k); 59 | } 60 | }; 61 | 62 | struct key_equal_sylvan: public std::function 63 | { 64 | bool operator()(const key_triple_sylvan& k1, const key_triple_sylvan& k2) const 65 | { 66 | return get<0>(k1) == get<0>(k2) 67 | && get<1>(k1) == get<1>(k2) 68 | && get<2>(k1) == get<2>(k2); 69 | } 70 | }; 71 | 72 | typedef unordered_map map_t_sylvan; 73 | 74 | class dfwa_min_sylvan 75 | { 76 | public: 77 | dfwa_min_sylvan(dfwa_ptr aut) 78 | : _aut (aut) 79 | { 80 | prepare(); 81 | } 82 | 83 | uint32_t _num_vars; 84 | // cube bdd 85 | sylvan_bdd_set _curr_cube; 86 | sylvan_bdd_set _next_cube; 87 | sylvan_bdd_set _label_cube; 88 | sylvan_bdd_set _curr_label_cube; 89 | sylvan_bdd_set _next_label_cube; 90 | 91 | // dfa (I(X) T(X, X', A), F(X)) 92 | sylvan_bdd _init; 93 | sylvan_bdd _trans; 94 | sylvan_bdd _finals; 95 | 96 | // first position after state variables 97 | uint32_t _num_states_vars; //_last_pos_states; 98 | // first position after label variables 99 | unsigned _last_pos_labels; 100 | 101 | unsigned _num_min_states; 102 | 103 | // state variables 104 | vector> _state_vars; 105 | // block variables 106 | vector> _block_vars; 107 | // label variables 108 | vector _label_vars; 109 | 110 | // utility for mapping to and from BuDDy bdds 111 | vector _sylvan_to_buddy_vars; 112 | unordered_map _buddy_to_sylvan_vars; 113 | 114 | dfwa_ptr _aut; 115 | 116 | // CUDD manager 117 | 118 | ~dfwa_min_sylvan(); 119 | 120 | void minimize(); 121 | 122 | dfwa_ptr move_dfwa(); 123 | 124 | //dfwa& operator &(dfwa& other); 125 | void output(ostream& os); 126 | 127 | unsigned get_num_min_states() 128 | { 129 | return _num_min_states; 130 | } 131 | private: 132 | 133 | bool is_state_variable(const uint32_t var_index) 134 | { 135 | return var_index < _num_states_vars; 136 | } 137 | 138 | // prepare for the minimization 139 | void prepare(); 140 | void prepare_variables(); 141 | 142 | // move BDD to a different BDD manager 143 | sylvan_bdd move_to_sylvan(buddy_bdd dd); 144 | sylvan_bdd move_to_cudd(buddy_bdd dd, unordered_map& computed_table); 145 | 146 | // move BDD from CUDD to BuDDy 147 | buddy_bdd move_to_buddy(sylvan_bdd dd, unordered_map& cudd_to_buddy_map); 148 | buddy_bdd move_to_buddy(sylvan_bdd_ptr dd, unordered_map& cudd_to_buddy_map 149 | , unordered_map& computed_table); 150 | 151 | // bdd_replace function for cudd 152 | //sylvan_bdd cudd_permute(sylvan_bdd_ptr dd, vector& from, vector& to); 153 | 154 | // helper functions for minimization 155 | void new_block_variables(unsigned num = 1); 156 | sylvan_bdd new_block_number(int block_number, int copy); 157 | sylvan_bdd initialize_partition(); 158 | pair refine_partition(sylvan_bdd_ptr sig); 159 | sylvan_bdd refine_partition_rec(sylvan_bdd_ptr dd, unsigned & block_number, unordered_map &computed_table); 160 | void compute_block_number_rec(sylvan_bdd_ptr sig, unordered_map& table, int & block_number); 161 | void reduce_block_variables(sylvan_bdd_ptr partition); 162 | 163 | sylvan_bdd make_quotient_trans(sylvan_bdd_ptr trans, sylvan_bdd_ptr curr_partition, sylvan_bdd_ptr next_partition); 164 | sylvan_bdd make_quotient_trans(sylvan_bdd trans, sylvan_bdd curr_partition, sylvan_bdd next_partition, vector>& var_sets, map_t_sylvan& computed_table); 165 | 166 | // print functions 167 | void print(sylvan_bdd bdd); 168 | void generate_all_bits(vector& vars, unsigned index, sylvan_bdd_ptr dd, sylvan_bdd temp); 169 | 170 | // state space exploration 171 | sylvan_bdd next_image(sylvan_bdd_ptr curr); 172 | sylvan_bdd pre_image(sylvan_bdd_ptr curr); 173 | sylvan_bdd forward_explore(); 174 | sylvan_bdd backward_explore(); 175 | }; 176 | -------------------------------------------------------------------------------- /src/synt.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #include "synt.hh" 6 | 7 | /*-------------------------------------------------------------------*/ 8 | // prepare for realizability checking 9 | /*-------------------------------------------------------------------*/ 10 | void 11 | synt::prepare() 12 | { 13 | // first add finals 14 | _tseq.push_back(_dfa.get_finals()); 15 | _wseq.push_back(_dfa.get_finals()); 16 | //remove input and output variables 17 | //_rest_cube = bdd_exist(_dfa._label_cube, _in_cube & _out_cube); 18 | _result = synt_result::UNKNOWN; 19 | _env_first = false; 20 | } 21 | 22 | synt::~synt() 23 | { 24 | } 25 | 26 | /*-------------------------------------------------------------------*/ 27 | // compute pre image 28 | /*-------------------------------------------------------------------*/ 29 | bdd 30 | synt::pre_image(bdd& curr) 31 | { 32 | bdd next = bdd_replace(curr, _dfa._curr_to_next_pairs); 33 | // has label_cube 34 | bdd pre = bdd_relprod(_dfa._trans, next, _dfa._next_cube); 35 | // only allow reachable states 36 | //pre = pre & _dfa._reach; 37 | return pre; 38 | } 39 | 40 | /*-------------------------------------------------------------------*/ 41 | // fixed point computation for checking realizability 42 | /*-------------------------------------------------------------------*/ 43 | void 44 | synt::env_play_first() 45 | { 46 | _env_first = true; 47 | } 48 | 49 | // evaluate assign in dd 50 | bool 51 | synt::eval(bdd& dd, bdd& assign) 52 | { 53 | bdd overlap = dd & assign; 54 | return overlap != bddfalse; 55 | } 56 | 57 | void 58 | synt::is_realizable() 59 | { 60 | unsigned curr = 0; 61 | while(true) 62 | { 63 | cout << "The number of nodes in T("<< curr << ") is " << bdd_nodecount(_tseq[curr]) << endl; 64 | cout << "The number of nodes in W("<< curr << ") is " << bdd_nodecount(_wseq[curr]) << endl; 65 | 66 | // pre_image (X, Y, Z) 67 | bdd pre_w = pre_image(_wseq[curr]); 68 | cout << "The number of nodes in pre_image("<< curr << ") is " << bdd_nodecount(pre_w) << endl; 69 | /* 70 | cout << "pre image of curr" << endl; 71 | bdd_print_set(cout, _dfa._state_vars.get_dict(), pre_w); 72 | cout << endl; 73 | 74 | cout << "in_cube " << endl; 75 | bdd_print_set(cout, _dfa._state_vars.get_dict(), _in_cube); 76 | cout << endl; 77 | */ 78 | 79 | if(_env_first) 80 | { 81 | // first quantify out all the outputs 82 | // w_{i + 1}(Z) = w_{i}(Z) | (!w_{i}(Z) & ∀ X.∃Y. (tr(X, Y, (w_{i})(Z)))) 83 | bdd tmp = bdd_exist(pre_w, _out_cube); 84 | /* 85 | cout << "bdd_exist pre_w " << endl; 86 | bdd_print_set(cout, _dfa._state_vars.get_dict(), tmp); 87 | cout << endl; 88 | */ 89 | tmp = bdd_forall(tmp, _in_cube); 90 | bdd wp = _wseq[curr] | tmp; 91 | _wseq.push_back(wp); 92 | 93 | // retain only valid states 94 | bdd state_io = pre_w & tmp; 95 | bdd tp = _tseq[curr] | ((!_wseq[curr]) & state_io); 96 | _tseq.push_back(tp); 97 | 98 | }else 99 | { 100 | // t_{i + 1}(Z, Y) = t_{i}(Z, Y) | (!w_{i}(Z) & ∀ X. (tr(X, Y, (w_{i})(Z)))) 101 | pre_w = bdd_forall(pre_w, _in_cube); 102 | /* 103 | cout << "bdd_foall pre_w " << endl; 104 | bdd_print_set(cout, _dfa._state_vars.get_dict(), pre_w); 105 | cout << endl; 106 | */ 107 | // now pre_w has only Z and Y 108 | bdd tp = _tseq[curr] | ((!_wseq[curr]) & pre_w); 109 | /* 110 | cout << "bdd_foall tp " << endl; 111 | bdd_print_set(cout, _dfa._state_vars.get_dict(), tp); 112 | cout << endl; 113 | 114 | cout << "out_cube " << endl; 115 | bdd_print_set(cout, _dfa._state_vars.get_dict(), _out_cube); 116 | cout << endl; 117 | */ 118 | _tseq.push_back(tp); 119 | // w_{i+1}(Z) = ∃Y.ti+1(Z, Y) 120 | bdd wp = bdd_exist(tp, _out_cube); 121 | /* 122 | cout << "bdd_foall wp " << endl; 123 | bdd_print_set(cout, _dfa._state_vars.get_dict(), wp); 124 | cout << endl; 125 | */ 126 | _wseq.push_back(wp); 127 | } 128 | 129 | ++ curr; 130 | // fixed point or see the initial state 131 | if(_wseq[curr].id() == _wseq[curr - 1].id() 132 | || eval(_wseq[curr], _dfa._init)) 133 | { 134 | break; 135 | } 136 | } 137 | cout << "Finished synthesis after " << curr << " iterations" << endl; 138 | cout << "The number of nodes in T(i+1) is " << bdd_nodecount(_tseq.back()) << endl; 139 | 140 | if(eval(_wseq[curr], _dfa._init)) 141 | { 142 | _result = synt_result::YES; 143 | cout << REALIZABLE << endl; 144 | }else 145 | { 146 | _result = synt_result::NO; 147 | cout << UNREALIZABLE << endl; 148 | } 149 | } 150 | /*-------------------------------------------------------------------*/ 151 | // synthesize winning strategy 152 | /*-------------------------------------------------------------------*/ 153 | void 154 | synt::synthesize() 155 | { 156 | // with the set t(Z, Y), we can construct a mealy machine 157 | // by construct T(X, Y, Z, Z') & t(Z, Y) 158 | if(_result == synt_result::YES) 159 | { 160 | _mealy_init = _dfa._init; 161 | // construct the transition relation of a mealy machine 162 | 163 | _mealy_trans = _dfa._trans; 164 | // relate one state with only one output 165 | clock_t c_start = clock(); 166 | if(_env_first) 167 | { 168 | strategy strat(_tseq.back(), _out_cube, _dfa._curr_cube & _in_cube); 169 | _mealy_out = strat.synthesize_strategy(); 170 | }else 171 | { 172 | strategy strat(_tseq.back(), _out_cube, _dfa._curr_cube); 173 | _mealy_out = strat.synthesize_strategy(); 174 | } 175 | //cout << "mealy output: " << endl; 176 | //bdd_print_set(cout, _dfa.get_dict(), _mealy_out); 177 | //cout << endl; 178 | clock_t c_end = clock(); 179 | cout << "Strategy exaction done in "<< 1000.0 * (c_end - c_start) / CLOCKS_PER_SEC << " ms\n"; 180 | cout << "The number of nodes in strategy is " << bdd_nodecount(_mealy_out) << endl; 181 | 182 | } 183 | 184 | } 185 | -------------------------------------------------------------------------------- /src/testltlf2fa.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | // standard 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // spot 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | 35 | #include "spotutil.hh" 36 | #include "mona.hh" 37 | #include "ltlf2fol.hh" 38 | #include "aututil.hh" 39 | 40 | 41 | using namespace spot; 42 | using namespace std; 43 | 44 | int 45 | main(int argc, char** argv) 46 | { 47 | if(argc < 1 || argc > 3) 48 | std::cout << "please input formula file" << std::endl; 49 | 50 | ifstream ltlfile(argv[1]); 51 | string line; 52 | bdd_dict_ptr dict = make_bdd_dict(); 53 | // ltlfile.open(argv[1]); 54 | 55 | //cout << "Opened file" << endl; 56 | 57 | if (ltlfile.is_open()) 58 | { 59 | //cout << "We are inside the file" << endl; 60 | while (getline(ltlfile, line)) 61 | { 62 | //cout << "formula: " << line << endl; 63 | auto pf1 = spot::parse_infix_psl(line.c_str()); 64 | if (pf1.format_errors(std::cerr)) 65 | { 66 | std::cerr << "error: " << line << std::endl; 67 | return -1; 68 | } 69 | //cout << "parsed formula: " << endl; 70 | formula f = pf1.f; 71 | cout << str_psl(pf1.f, true) << endl; 72 | formula f1 = from_ltlf(f, "alive"); 73 | // formula 1 74 | formula r = get_bnf(f); 75 | formula r1 = from_ltlf(r, "alive"); 76 | //spot::formula f = spot::parse_formula("(a U b) U a"); 77 | //spot::formula g = spot::parse_formula("b U a"); 78 | std::cout << " BNF and Original LTLf formulas:"<< (spot::are_equivalent(f1, r1) ? 79 | "Equivalent\n" : "Not equivalent\n"); 80 | 81 | formula rr = get_nnf(f); 82 | formula rr1 = from_ltlf(r, "alive"); 83 | std::cout << " NNF and Original LTLf formulas: " << (spot::are_equivalent(f1, rr1) ? 84 | "Equivalent\n" : "Not equivalent\n"); 85 | // automata construction 86 | option_map m; 87 | translator trans(dict, &m); 88 | formula ltl = from_ltlf(f, "alive"); 89 | //spot::tl_simplifier simpl; 90 | //ltl = simpl.simplify(ltl); 91 | twa_graph_ptr aut1 = trans.run(ltl); 92 | // construct from MONA 93 | string mona_file_name = "./ltlf.mona"; 94 | ofstream ofs (mona_file_name, ofstream::out); 95 | ofs << "#LTLf formula" << endl; 96 | ofs << "#" << str_psl(f, true) << endl; 97 | ofs << "# Backus normal form" << endl; 98 | // output in a parsable formula 99 | // the BNF form, and then convert it to fol formula 100 | ltlf_to_fol(ofs, r); 101 | ofs.close(); 102 | //cout << "formula: " << str_psl(f, true) << endl; 103 | // now call ltlf2fol 104 | //string mona_file_name = "./ltlf.mona"; 105 | //string command = "./ltlf2fol NNF " + fol_file_name + " > " + mona_file_name; 106 | //system(command.c_str()); 107 | string dfa_file_name = "./mona.dfa"; 108 | string command = "mona -u -xw " + mona_file_name+ " >" + dfa_file_name; 109 | system(command.c_str()); 110 | // if this turns to be a bottleneck, we need pthread to read from pipe 111 | twa_graph_ptr aut2 = read_from_mona_file(dfa_file_name.c_str(), dict); 112 | cout << "#Spot DFA: " << aut1->num_states() << endl; 113 | cout << "#Mona DFA: " << aut2->num_states() << endl; 114 | // check equivalence 115 | string word = is_twa_equivalent(aut1, aut2); 116 | cout << "Spot and MONA DFA:"; 117 | if(word.size() == 0) 118 | { 119 | cout << "Equivalent" << endl; 120 | }else 121 | { 122 | cout << "CE: " << word << endl; 123 | cout << "Inequivalent" << endl; 124 | exit(-1); 125 | } 126 | // another automaton 127 | //rans_prefixltlf2fol(ostream &os, formula &f) 128 | //string mona_file_name1 = "./ltlf1.mona"; 129 | //ofstream ofs1(mona_file_name1, ofstream::out); 130 | //ofs1 << "#LTLf formula" << endl; 131 | //ofs1 << "#" << str_psl(f, true) << endl; 132 | //ofs1 << "# Backus normal form" << endl; 133 | // output in a parsable formula 134 | // the BNF form, and then convert it to fol formula 135 | //trans_prefixltlf2fol(ofs1, r); 136 | //ofs1.close(); 137 | //cout << "formula: " << str_psl(f, true) << endl; 138 | // now call ltlf2fol 139 | //string mona_file_name = "./ltlf.mona"; 140 | //string command = "./ltlf2fol NNF " + fol_file_name + " > " + mona_file_name; 141 | //system(command.c_str()); 142 | //string dfa_file_name = "./mona.dfa"; 143 | //command = "mona -u -xw " + mona_file_name1 + " >" + dfa_file_name; 144 | //system(command.c_str()); 145 | // if this turns to be a bottleneck, we need pthread to read from pipe 146 | //twa_graph_ptr aut3 = read_from_mona_file(dfa_file_name.c_str(), dict); 147 | //cout << "Aut3: " << aut3->num_states() << endl; 148 | //ofstream outfile("outputaut.hoa"); 149 | //print_hoa(outfile, aut3); 150 | //bool isIn = contains(aut3, aut2); 151 | /* 152 | if(isIn) 153 | { 154 | cout << "Contains" << endl; 155 | }else 156 | { 157 | cout << "Not contained" << endl; 158 | } 159 | isIn = contains(aut2, aut3); 160 | if(isIn) 161 | { 162 | cout << "Contains" << endl; 163 | }else 164 | { 165 | cout << "Not contained" << endl; 166 | } 167 | */ 168 | string mona_file_name2 = "./ltlf2.mona"; 169 | ofstream ofs2(mona_file_name2, ofstream::out); 170 | ofs2 << "#LTLf formula" << endl; 171 | ofs2 << "#" << str_psl(f, true) << endl; 172 | ofs2 << "# Backus normal form" << endl; 173 | // output in a parsable formula 174 | // the BNF form, and then convert it to fol formula 175 | ltlf_to_pfol(ofs2, r); 176 | ofs2.close(); 177 | //cout << "formula: " << str_psl(f, true) << endl; 178 | // now call ltlf2fol 179 | //string mona_file_name = "./ltlf.mona"; 180 | //string command = "./ltlf2fol NNF " + fol_file_name + " > " + mona_file_name; 181 | //system(command.c_str()); 182 | //string dfa_file_name = "./mona.dfa"; 183 | command = "mona -u -xw " + mona_file_name2 + " >" + dfa_file_name; 184 | system(command.c_str()); 185 | // if this turns to be a bottleneck, we need pthread to read from pipe 186 | twa_graph_ptr aut4 = read_from_mona_file(dfa_file_name.c_str(), dict); 187 | cout << "#Past DFA: " << aut4->num_states() << endl; 188 | //aut4->merge_edges(); 189 | //ofstream outfile1("output4.hoa"); 190 | //print_hoa(outfile1, aut4); 191 | //outfile1.close(); 192 | // reverse 193 | //cout << "Output aut5" << endl; 194 | twa_graph_ptr aut5 = reverse(dict, aut4); 195 | cout << "#Reverse NFA: " << aut5->num_states() << endl; 196 | //aut5->merge_edges(); 197 | //ofstream outfile2("output5.hoa"); 198 | //print_hoa(outfile2, aut5); 199 | //outfile2.close(); 200 | word = is_twa_equivalent(aut1, aut5); 201 | cout << "Spot DFA and Reverse NFA: "; 202 | if(word.size() == 0) 203 | { 204 | cout << "Equivalent" << endl; 205 | }else 206 | { 207 | cout << "CE: " << word << endl; 208 | cout << "Inequivalent" << endl; 209 | exit(-1); 210 | } 211 | } 212 | } 213 | ltlfile.close(); 214 | return 0; 215 | } 216 | 217 | 218 | -------------------------------------------------------------------------------- /src/aututil.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #include "aututil.hh" 6 | 7 | // quantify out all variables in @cube on transitions 8 | // bdd_vars should include alive_ap 9 | twa_graph_ptr 10 | project(spot::bdd_dict_ptr dict, twa_graph_ptr aut, bdd cube, bool min) 11 | { 12 | // now construct the dfa 13 | spot::twa_graph_ptr ret = make_twa_graph(aut->get_dict()); 14 | 15 | ret->set_buchi(); 16 | ret->prop_state_acc(); 17 | // add one extra state for accepting state 18 | 19 | unsigned num_states = aut->num_states(); 20 | ret->new_states(num_states); 21 | ret->set_init_state(aut->get_init_state_number()); 22 | // for identifying accepting states 23 | string alive_ap(ALIVE_AP); 24 | int var_index = dict->varnum(formula::ap(alive_ap)); 25 | bdd p = bdd_ithvar(var_index); 26 | // register propositions 27 | //cout << "var map: " << endl; 28 | map &var_map = ret->get_dict()->var_map; 29 | map::const_iterator iter = var_map.begin(); 30 | while (iter != var_map.end()) 31 | { 32 | formula key = iter->first; 33 | int value = iter->second; 34 | //cout << key << " -> " << value << endl; 35 | ret->register_ap(key); 36 | iter++; 37 | } 38 | // project on transitions 39 | for (unsigned s = 0; s < num_states; ++s) 40 | { 41 | // check if it is predecessor of accepting 42 | //out << "State " << s << ":\n"; 43 | bool acc = false; 44 | // check whether current state s is accepting in DFA 45 | for (auto &t : aut->out(s)) 46 | { 47 | if (t.acc.has(0) || (t.cond & !p) != bddfalse) 48 | { 49 | acc = true; 50 | break; 51 | } 52 | } 53 | if (acc) 54 | { 55 | // make accepting state s a sink accepting state 56 | ret->new_edge(s, s, bddtrue, {0}); 57 | //cout << "state: " << s << endl; 58 | } 59 | else 60 | { 61 | for (auto &t : aut->out(s)) 62 | { 63 | // quantify out output variables; transition t: t.cond is the bdd 64 | bdd new_label = bdd_exist(t.cond, cube); 65 | //cout << "projected label : " << new_label << " old label: " << t.cond << " cube: " << cube << endl; 66 | ret->new_edge(t.src, t.dst, new_label); 67 | } 68 | } 69 | // there may be a transition to the sink accepting state 70 | } 71 | // for sure original sink accepting state is no longer reachable 72 | // hopefully reduce some states 73 | clock_t post_start = clock(); 74 | spot::postprocessor post; 75 | post.set_type(spot::postprocessor::BA); 76 | //post.set_pref(spot::postprocessor::Deterministic); 77 | post.set_level(spot::postprocessor::Low); 78 | ret = post.run(ret); 79 | clock_t post_end = clock(); 80 | cout << "Total CPU time used for reducing projected DBA: " 81 | << 1000.0 * (post_end - post_start) / CLOCKS_PER_SEC << " ms\n"; 82 | if (min) 83 | { 84 | clock_t c_start = clock(); 85 | twa_graph_ptr tmp = spot::minimize_wdba(ret); 86 | clock_t c_end = clock(); 87 | cout << "Total CPU time used for minimizing projected DBA: " 88 | << 1000.0 * (c_end - c_start) / CLOCKS_PER_SEC << " ms\n"; 89 | //ofstream outfile1("output3.hoa"); 90 | //print_hoa(outfile1, C); 91 | return tmp; 92 | } 93 | else 94 | { 95 | return ret; 96 | } 97 | } 98 | 99 | // reverse a DFA: make accepting states initial states and reverse transitions 100 | // bdd_vars should include alive_ap 101 | twa_graph_ptr 102 | reverse(spot::bdd_dict_ptr dict, twa_graph_ptr aut) 103 | { 104 | clock_t rev_start = clock(); 105 | // now construct the NFA 106 | spot::twa_graph_ptr ret = make_twa_graph(aut->get_dict()); 107 | 108 | ret->set_buchi(); 109 | ret->prop_state_acc(); 110 | // add one extra state for accepting state 111 | 112 | // set the maximal state the unique initial state 113 | unsigned num_states = aut->num_states() + 1; 114 | 115 | ret->new_states(num_states); 116 | int init_state = aut->num_states(); 117 | ret->set_init_state(init_state); 118 | // for identifying accepting states 119 | string alive_ap(ALIVE_AP); 120 | int var_index = dict->varnum(formula::ap(alive_ap)); 121 | bdd p = bdd_ithvar(var_index); 122 | // register propositions 123 | //cout << "var map: " << endl; 124 | map &var_map = ret->get_dict()->var_map; 125 | map::const_iterator iter = var_map.begin(); 126 | while (iter != var_map.end()) 127 | { 128 | formula key = iter->first; 129 | int value = iter->second; 130 | //cout << key << " -> " << value << endl; 131 | ret->register_ap(key); 132 | iter++; 133 | } 134 | // reverse the transitions of the DFA 135 | set acc_states; 136 | unsigned sink = -1; 137 | for (unsigned s = 0; s < num_states - 1; ++s) 138 | { 139 | // check if it is predecessor of accepting 140 | //out << "State " << s << ":\n"; 141 | bool acc = false; 142 | // check whether current state s is the sink accepting state in wDBA 143 | bool found_sink = false; 144 | if (!found_sink) 145 | { 146 | for (auto &t: aut->out(s)) 147 | { 148 | // loop transition and accepting transition 149 | if (t.acc.has(0) && s == t.dst) 150 | { 151 | sink = s; 152 | found_sink = true; 153 | break; 154 | } 155 | } 156 | } 157 | // if not sink state in wDBA, check whether s is accepting in DFA 158 | if(s != sink) 159 | { 160 | for (auto &t : aut->out(s)) 161 | { 162 | if (t.acc.has(0) || (t.cond & !p) != bddfalse) 163 | { 164 | acc = true; 165 | break; 166 | } 167 | } 168 | } 169 | 170 | if (acc) 171 | { 172 | // this state may be the sink or accepting states in the DFA 173 | acc_states.insert(s); 174 | //cout << "state: " << s << endl; 175 | } 176 | else 177 | { 178 | // not accepting states, then just reverse transitions 179 | // no transitions to the sink state 180 | for (auto &t : aut->out(s)) 181 | { 182 | // transition t: t.cond is the bdd 183 | ret->new_edge(t.dst, t.src, t.cond); 184 | } 185 | } 186 | } 187 | assert( sink != -1); 188 | // initial state to sink, as accepting state in NFA 189 | ret->new_edge(aut->get_init_state_number(), sink, !p); 190 | ret->new_acc_edge(sink, sink, !p, true); 191 | // reverse transitions for accepting states in reverse DFA 192 | for(unsigned s : acc_states) 193 | { 194 | for (auto &t : aut->out(s)) 195 | { 196 | if(t.dst != sink) 197 | { 198 | // (s, a, t) -> (t, a, s) 199 | ret->new_edge(t.dst, t.src, t.cond); 200 | } 201 | } 202 | } 203 | // now we need to add transitions from the accepting states for the initial state 204 | // copy existing transitions 205 | for(unsigned s : acc_states) 206 | { 207 | // note that here automaton is ret 208 | for (auto &t : ret->out(s)) 209 | { 210 | if(t.dst != sink) 211 | { 212 | // (s, a, t) -> (t, a, s) 213 | ret->new_edge(init_state, t.dst, t.cond); 214 | } 215 | } 216 | } 217 | // merge transitions with same source and desition states 218 | ret->merge_edges(); 219 | cout << "Resulting automaton is " << (is_deterministic(ret)? "deterministic" : "nondeterministic") << endl; 220 | clock_t rev_end = clock(); 221 | cout << "Total CPU time used for reversing DFA: " 222 | << 1000.0 * (rev_end - rev_start) / CLOCKS_PER_SEC << " ms\n"; 223 | 224 | return ret; 225 | } 226 | 227 | // reduce a nondeterministic automaton 228 | twa_graph_ptr 229 | reduce(twa_graph_ptr aut, int level) 230 | { 231 | clock_t post_start = clock(); 232 | spot::postprocessor post; 233 | post.set_type(spot::postprocessor::BA); 234 | //post.set_pref(spot::postprocessor::Deterministic); 235 | if(level == 0) 236 | { 237 | post.set_level(spot::postprocessor::Low); 238 | }else if(level == 1) 239 | { 240 | post.set_level(spot::postprocessor::Medium); 241 | }else 242 | { 243 | post.set_level(spot::postprocessor::High); 244 | } 245 | twa_graph_ptr ret = post.run(aut); 246 | clock_t post_end = clock(); 247 | cout << "Total CPU time used for reducing FA: " 248 | << 1000.0 * (post_end - post_start) / CLOCKS_PER_SEC << " ms\n"; 249 | return ret; 250 | } 251 | 252 | -------------------------------------------------------------------------------- /src/spotutil.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #include "spotutil.hh" 6 | 7 | #include "debug.hh" 8 | #include "mona.hh" 9 | 10 | 11 | bool 12 | is_even(unsigned value) 13 | { 14 | return (value & 1) == 0; 15 | } 16 | 17 | /*-------------------------------------------------------------------*/ 18 | // get the list of var indices from a cube 19 | /*-------------------------------------------------------------------*/ 20 | void 21 | get_list_var_indices(vector& vars, bdd cube) 22 | { 23 | while(cube != bddtrue) 24 | { 25 | int index = bdd_var(cube); 26 | vars.push_back(index); 27 | cube = bdd_high(cube); 28 | } 29 | } 30 | 31 | /*-------------------------------------------------------------------*/ 32 | // check the language inclusion of two input NBAs 33 | /*-------------------------------------------------------------------*/ 34 | string 35 | is_twa_included(twa_graph_ptr aut_a, twa_graph_ptr aut_b) 36 | { 37 | auto complement_aut_b = dualize(aut_b); 38 | spot::twa_word_ptr word = aut_a->intersecting_word(complement_aut_b); 39 | std::stringstream ss; 40 | if(word != nullptr) { 41 | //spot::twa_graph_ptr result = word->as_automaton(); 42 | word->simplify(); 43 | ss << (*word); 44 | // Print the resulting automaton. 45 | //print_hoa(std::cout, result); 46 | }else { 47 | ss << ""; 48 | } 49 | return ss.str(); 50 | } 51 | 52 | /*-------------------------------------------------------------------*/ 53 | // check the equivalence of two input NBAs 54 | /*-------------------------------------------------------------------*/ 55 | string 56 | is_twa_equivalent(twa_graph_ptr aut_a, twa_graph_ptr aut_b) 57 | { 58 | string word = is_twa_included(aut_a, aut_b); 59 | if(word.size() != 0) 60 | { 61 | return word; 62 | } 63 | word = is_twa_included(aut_b, aut_a); 64 | return word; 65 | } 66 | 67 | /*-------------------------------------------------------------------*/ 68 | // compute the connectives and operators of a formula 69 | /*-------------------------------------------------------------------*/ 70 | unsigned 71 | get_size_formula(formula& f) 72 | { 73 | // use id as the key to record the length and the number of props in a formula 74 | //std::cout << "operator" << f.id() << std::endl; 75 | unsigned count = 0; 76 | if(f.kind() == op::Not || f.kind() == op::X || f.kind() == op::strong_X || f.kind() == op::F || f.kind() == op::G ) 77 | { 78 | formula f1 = f[0]; 79 | count += 1 + get_size_formula(f1); 80 | }else 81 | if(f.kind() == op::U || f.kind() == op::R || f.kind() == op::M || f.kind() == op::W || f.kind() == op::Implies || f.kind() == op::Equiv ) 82 | { 83 | formula f1 = f[0], f2 = f[1]; 84 | count += 1 + get_size_formula(f1) + get_size_formula(f2); 85 | }else 86 | if(f.kind() == op::And || f.kind() == op::Or) 87 | { 88 | count = 1; 89 | for(formula child: f) 90 | { 91 | count += get_size_formula(child); 92 | } 93 | } 94 | return count; 95 | } 96 | 97 | /*-------------------------------------------------------------------*/ 98 | // compute the number of propositions of a formula 99 | /*-------------------------------------------------------------------*/ 100 | void 101 | get_formula_aps(formula& f, set& aps) 102 | { 103 | if(f.kind() == op::Not || f.kind() == op::X || f.kind() == op::strong_X || f.kind() == op::F || f.kind() == op::G ) 104 | { 105 | formula f1 = f[0]; 106 | return get_formula_aps(f1, aps); 107 | }else 108 | if(f.kind() == op::U || f.kind() == op::R || f.kind() == op::M || f.kind() == op::W || f.kind() == op::Implies || f.kind() == op::Equiv ) 109 | { 110 | formula f1 = f[0], f2 = f[1]; 111 | get_formula_aps(f1, aps); 112 | get_formula_aps(f2, aps); 113 | }else 114 | if(f.kind() == op::And || f.kind() == op::Or) 115 | { 116 | for(formula child: f) 117 | { 118 | get_formula_aps(child, aps); 119 | } 120 | }else 121 | if(f.kind() == op::ap) 122 | { 123 | aps.insert(f); 124 | }else if(f.kind() != op::tt && f.kind() != op::ff) 125 | { 126 | cerr << "Error formula in get_formula_aps(): " << f << endl; 127 | exit(-1); 128 | } 129 | } 130 | 131 | 132 | unsigned 133 | get_size_formula_ap(formula& f) 134 | { 135 | set aps; 136 | get_formula_aps(f, aps); 137 | #ifdef DEBUG 138 | for(auto& ap : aps) 139 | { 140 | cout << "AP = " << ap << endl; 141 | } 142 | #endif 143 | return aps.size(); 144 | } 145 | 146 | /*-------------------------------------------------------------------*/ 147 | // check the equivalence of two input NBAs 148 | /*-------------------------------------------------------------------*/ 149 | twa_graph_ptr 150 | trans_formula(formula f, bdd_dict_ptr dict, unsigned num_ap_for_mona) 151 | { 152 | twa_graph_ptr aut; 153 | unsigned num_aps = get_size_formula_ap(f); 154 | 155 | if(num_aps > num_ap_for_mona) 156 | { 157 | DEBUG_STDOUT( "mona translating "); 158 | aut = translate_ltlf_mona(f, dict); 159 | DEBUG_STDOUT( "done mona translating "); 160 | }else 161 | { 162 | DEBUG_STDOUT( "spot translating "); 163 | 164 | //cout << "spot translating" << endl; 165 | option_map m; 166 | translator trans(dict, &m); 167 | formula ltl = from_ltlf(f, ALIVE_AP); 168 | 169 | //spot::tl_simplifier simpl; 170 | //ltl = simpl.simplify(ltl); 171 | aut = trans.run(ltl); 172 | //spot::postprocessor post; 173 | //post.set_type(spot::postprocessor::BA); 174 | //post.set_pref(spot::postprocessor::Deterministic); 175 | //post.set_pref(spot::postprocessor::Deterministic); // or ::Deterministi 176 | //print_hoa(std::cout, aut) << '\n'; 177 | DEBUG_STDOUT( "done spot translating "); 178 | } 179 | 180 | return aut; 181 | } 182 | /*-------------------------------------------------------------------*/ 183 | // compute the final states of a DFA 184 | /*-------------------------------------------------------------------*/ 185 | void 186 | get_final_states(twa_graph_ptr aut, set& finals) 187 | { 188 | stack todo; 189 | unsigned init = aut->get_init_state_number(); 190 | todo.push(init); 191 | set seen; 192 | seen.insert(init); 193 | while (!todo.empty()) 194 | { 195 | unsigned s = todo.top(); 196 | todo.pop(); 197 | // transitions of s 198 | for (auto& e: aut->out(s)) 199 | { 200 | if (seen.insert(e.dst).second) 201 | todo.push(e.dst); 202 | if(e.acc.has(0)) 203 | { 204 | //cout << "final state: " << e.dst << endl; 205 | finals.insert(e.dst); 206 | } 207 | } 208 | } 209 | } 210 | 211 | void 212 | get_nonfinal_states(twa_graph_ptr A, set& nonfinals) 213 | { 214 | for(unsigned s = 0; s < A->num_states(); s ++) 215 | { 216 | for (auto& e: A->out(s)) 217 | { 218 | if(! e.acc.has(0)) 219 | { 220 | nonfinals.insert(s); 221 | } 222 | } 223 | } 224 | } 225 | 226 | /*-------------------------------------------------------------------*/ 227 | // obtain the set of final states of a DFA 228 | // (has transition to accepting state of weak DBA on !alive ) 229 | /*-------------------------------------------------------------------*/ 230 | void 231 | compute_final_states(twa_graph_ptr A, set& finals) 232 | { 233 | bdd p2 = bdd_ithvar(A->register_ap(ALIVE_AP)); 234 | for(unsigned s = 0; s < A->num_states(); s ++) 235 | { 236 | for (auto& e: A->out(s)) 237 | { 238 | if((e.cond & !p2) != bddfalse && s != e.dst) 239 | { 240 | finals.insert(s); 241 | } 242 | } 243 | } 244 | } 245 | 246 | /*-------------------------------------------------------------------*/ 247 | // obtain the set of accepting states of a weak DBA 248 | /*-------------------------------------------------------------------*/ 249 | void 250 | compute_accepting_states(twa_graph_ptr A, set& acc) 251 | { 252 | for(unsigned s = 0; s < A->num_states(); s ++) 253 | { 254 | for (auto& e: A->out(s)) 255 | { 256 | if(e.acc.has(0)) 257 | { 258 | acc.insert(s); 259 | } 260 | } 261 | } 262 | } 263 | /*-------------------------------------------------------------------*/ 264 | // convert a DFA to a weak DBA by adding alive propositions 265 | /*-------------------------------------------------------------------*/ 266 | twa_graph_ptr 267 | dfa_to_wdba(twa_graph_ptr aut, bdd_dict_ptr dict, set finals) 268 | { 269 | return nullptr; 270 | } 271 | 272 | void 273 | output_bdd(ostream& os, bdd dd, set& computed_table) 274 | { 275 | int dd_id = dd.id(); 276 | if(computed_table.find(dd_id) != computed_table.end()) 277 | { 278 | return ; 279 | } 280 | if(dd == bddtrue) 281 | { 282 | os << dd_id << " -1 t 0" << endl; 283 | }else 284 | if(dd == bddfalse) 285 | { 286 | os << dd_id << " -1 f 0" << endl; 287 | }else 288 | { 289 | bdd high = bdd_high(dd); 290 | output_bdd(os, high, computed_table); 291 | bdd low = bdd_low(dd); 292 | output_bdd(os, low, computed_table); 293 | os << dd_id << " " << bdd_var(dd) << " " << high.id() << " " << low.id() << endl; 294 | } 295 | computed_table.insert(dd_id); 296 | } 297 | 298 | void 299 | output_bdd(ostream& os, bdd dd) 300 | { 301 | set computed_table; 302 | output_bdd(os, dd, computed_table); 303 | } 304 | 305 | bdd 306 | local_bdd_and(bdd& op1, bdd& op2) 307 | { 308 | //cout << "Inside local_bdd_and..." << endl; 309 | return op1 & op2; 310 | } 311 | 312 | bdd 313 | local_bdd_or(bdd& op1, bdd& op2) 314 | { 315 | //cout << "Inside local_bdd_or..." << endl; 316 | return op1 | op2; 317 | } 318 | 319 | bdd 320 | local_bdd_not_and(bdd& op1, bdd& op2) 321 | { 322 | //cout << "Inside local_bdd_not_and..." << endl; 323 | return op1 & !op2; 324 | } 325 | -------------------------------------------------------------------------------- /src/dfwavar.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #include "dfwavar.hh" 6 | 7 | /*-------------------------------------------------------------------*/ 8 | // get the number of bits needed to represent an integer value 9 | /*-------------------------------------------------------------------*/ 10 | unsigned 11 | get_num_bits(int value) 12 | { 13 | if(value == 1) 14 | { 15 | return 1; 16 | } 17 | -- value; 18 | unsigned count = 0; 19 | while (value) 20 | { 21 | //cout << " val = " << value << endl; 22 | value = value >> 1; 23 | ++ count; 24 | } 25 | return count; 26 | } 27 | /*-------------------------------------------------------------------*/ 28 | // new empty bdd variables: ONLY for product automaton 29 | /*-------------------------------------------------------------------*/ 30 | dfwa_var::dfwa_var(bdd_dict_ptr dict) 31 | : _dict(dict) 32 | { 33 | _aut = nullptr; 34 | _copies = 0; 35 | _lower = 0; 36 | _upper = 0; 37 | } 38 | 39 | /*-------------------------------------------------------------------*/ 40 | // release the use of variables 41 | /*-------------------------------------------------------------------*/ 42 | dfwa_var::~dfwa_var() 43 | { 44 | if(_dict != nullptr) 45 | { 46 | _dict->unregister_all_my_variables(this); 47 | } 48 | } 49 | 50 | /*-------------------------------------------------------------------*/ 51 | // new bdd variables 52 | /*-------------------------------------------------------------------*/ 53 | 54 | void 55 | dfwa_var::prepare_vars() 56 | { 57 | // numbers 58 | int num_values = get_upper() - get_lower() + 1; 59 | unsigned num_bits = get_num_bits(num_values); 60 | //cout << "needs " << num_bits << " bits" << endl; 61 | for (unsigned copy = 0; copy < _copies; copy++) 62 | { 63 | vector vec; 64 | _dd_vars.push_back(vec); 65 | vector vec_str; 66 | _dd_names.push_back(vec_str); 67 | } 68 | 69 | //int varNum = bdd.getNumVars(); 70 | // n consecutive BDD variables which will be used only by for_me. 71 | //unsigned var_num = _dict->register_anonymous_variables(_copies * num_bits, _aut); 72 | /* 73 | unsigned var_num =_dict->register_anonymous_variables(_copies * num_bits, this); 74 | cout << "allocate " << _copies * num_bits << " variables starting from " << var_num << endl; 75 | for (unsigned bit = 0; bit < num_bits; bit++) 76 | { 77 | //_dd_nums.push_back(var_num); 78 | for (unsigned copy = 0; copy < _copies; copy++) 79 | { 80 | bdd dd = bdd_ithvar(var_num); 81 | string dd_name = _name + UNDERSCORE + to_string(bit) + UNDERSCORE + to_string(copy); 82 | _dd_vars[copy].push_back(dd); 83 | _dd_names[copy].push_back(dd_name); 84 | //cout << "dd_name = " << dd_name << " var_num = " << var_num << endl; 85 | ++ var_num; 86 | } 87 | }*/ 88 | // need to improve the naming of variables 89 | for (unsigned bit = 0; bit < num_bits; bit++) 90 | { 91 | //_dd_nums.push_back(var_num); 92 | for (unsigned copy = 0; copy < _copies; copy++) 93 | { 94 | string dd_name = _name + to_string(index_for_vars) + UNDERSCORE + to_string(bit) + UNDERSCORE + to_string(copy); 95 | int var_index = _dict->register_proposition(formula::ap(dd_name), this); 96 | bdd dd = bdd_ithvar(var_index); 97 | _dd_vars[copy].push_back(dd); 98 | _dd_names[copy].push_back(dd_name); 99 | //cout << "dd_name = " << dd_name << " var_num = " << var_index << endl; 100 | } 101 | } 102 | ++ index_for_vars; 103 | order_vars(); 104 | } 105 | /*-------------------------------------------------------------------*/ 106 | // a bdd to an integer 107 | /*-------------------------------------------------------------------*/ 108 | int 109 | dfwa_var::to_integer(bdd dd) 110 | { 111 | int value = 0; 112 | int bit = 1; 113 | for (bdd bit_var : get_bdd_vars(0)) 114 | { 115 | bdd result = bit_var & dd; 116 | if (result != bddfalse) 117 | { 118 | value |= bit; 119 | } 120 | bit <<= 1; 121 | } 122 | value += _lower; 123 | return value; 124 | } 125 | 126 | /*-------------------------------------------------------------------*/ 127 | // an integer to a bdd 128 | /*-------------------------------------------------------------------*/ 129 | bdd 130 | dfwa_var::new_value(int copy, int value) 131 | { 132 | value -= get_lower(); 133 | bdd dd = bddtrue; 134 | int bit = 1; 135 | for (bdd bit_var : get_bdd_vars(copy)) 136 | { 137 | bdd bit_var_not = !bit_var; 138 | dd = dd & ((value & bit) != 0 ? bit_var : bit_var_not); 139 | bit <<= 1; 140 | } 141 | return dd; 142 | } 143 | 144 | void 145 | dfwa_var::new_value(vector& bits, int copy, int value) 146 | { 147 | value -= get_lower(); 148 | int bit = 1; 149 | for (bdd bit_var : get_bdd_vars(copy)) 150 | { 151 | if((value & bit) != 0) 152 | { 153 | bits.push_back(bddtrue); 154 | }else 155 | { 156 | bits.push_back(bddfalse); 157 | } 158 | bit <<= 1; 159 | } 160 | } 161 | 162 | /*-------------------------------------------------------------------*/ 163 | // get the list of variables of copy 164 | /*-------------------------------------------------------------------*/ 165 | bdd 166 | dfwa_var::get_cube(int copy) 167 | { 168 | bdd cube = bddtrue; 169 | for (bdd dd : get_bdd_vars(copy)) 170 | { 171 | bdd temp = cube & dd; 172 | cube = temp; 173 | } 174 | return cube; 175 | } 176 | 177 | /*-------------------------------------------------------------------*/ 178 | // add more variables 179 | /*-------------------------------------------------------------------*/ 180 | void 181 | dfwa_var::add_bdd_vars(dfwa_var& vars) 182 | { 183 | dfwa_var* other = &vars; 184 | // needs to register state variables before use 185 | _dict->register_all_variables_of(other, this); 186 | unsigned copies = max(_copies, vars.get_copies()); 187 | //cout << "add state vars: copies = " << copies << endl; 188 | for(unsigned i = 0; i < copies; i ++) 189 | { 190 | if(i < _dd_vars.size()) 191 | { 192 | // add variables to the copy i vector 193 | vector& temp = _dd_vars[i]; 194 | vector& add = vars.get_bdd_vars(i); 195 | for(unsigned j = 0; j < add.size(); j ++) 196 | { 197 | temp.push_back(add[j]); 198 | } 199 | }else 200 | { 201 | //create a vector and add variables 202 | vector temp; 203 | vector& add = vars.get_bdd_vars(i); 204 | for(unsigned j = 0; j < add.size(); j ++) 205 | { 206 | temp.push_back(add[j]); 207 | } 208 | _dd_vars.push_back(temp); 209 | } 210 | } 211 | // no ordering for variables 212 | } 213 | 214 | void 215 | dfwa_var::add_ordered_bdd_vars(dfwa_var& vars) 216 | { 217 | dfwa_var* other = &vars; 218 | _dd_vars.clear(); 219 | // needs to register state variables before use 220 | _dict->register_all_variables_of(other, this); 221 | assert(vars.get_copies() == 2); 222 | assert(get_copies() == 2); 223 | vector all_vars; 224 | //cout << "add state vars: copies = " << _copies << endl; 225 | for(unsigned i = 0; i < vars.get_copies(); i ++) 226 | { 227 | vector& add = vars.get_bdd_vars(i); 228 | for(bdd var : add) 229 | { 230 | all_vars.push_back(var); 231 | } 232 | } 233 | struct bdd_order 234 | { 235 | bool operator()(bdd fst, bdd snd) 236 | { 237 | return bdd_var(fst) < bdd_var(snd); 238 | } 239 | } order; 240 | // make sure the order is increasing 241 | sort(all_vars.begin(), all_vars.end(), order); 242 | assert(all_vars.size() % 2 == 0); 243 | // add them to variables 244 | vector curr_vars; 245 | vector next_vars; 246 | for(unsigned i = 0; i < all_vars.size(); i += 2) 247 | { 248 | curr_vars.push_back(all_vars[i]); 249 | next_vars.push_back(all_vars[i + 1]); 250 | } 251 | _dd_vars.push_back(curr_vars); 252 | _dd_vars.push_back(next_vars); 253 | } 254 | 255 | void 256 | dfwa_var::order_vars() 257 | { 258 | struct bdd_order 259 | { 260 | // make sure there are only variables 261 | bool operator() (bdd fst, bdd snd) 262 | { 263 | return bdd_var(fst) < bdd_var(snd); 264 | } 265 | } order; 266 | // make sure the order is increasing 267 | for(unsigned i = 0; i < _dd_vars.size(); i ++) 268 | { 269 | vector& copy = _dd_vars[i]; 270 | sort(copy.begin(), copy.end(), order); 271 | } 272 | //vector& curr = _dd_vars[0]; 273 | //sort(curr.begin(), curr.end(), order); 274 | //vector& next = _dd_vars[1]; 275 | //sort(next.begin(), next.end(), order); 276 | } 277 | 278 | /* 279 | void 280 | dfwa_var::add_bdd_vars(vector& vars_vec) 281 | { 282 | _dd_vars.push_back(vars_vec); 283 | // needs to register state variables before use 284 | for(bdd& var : vars_vec) 285 | { 286 | _dict->register_anonymous_variables(bdd_var(var), this); 287 | } 288 | } 289 | */ 290 | 291 | void 292 | dfwa_var::pop_back_vars() 293 | { 294 | for(unsigned i = 0; i < _copies; i ++) 295 | { 296 | bdd var = _dd_vars[i].back(); 297 | _dict->unregister_variable(bdd_var(var), this); 298 | _dd_vars[i].pop_back(); 299 | } 300 | } 301 | 302 | /*-------------------------------------------------------------------*/ 303 | // make bdd pair by variable indices 304 | /*-------------------------------------------------------------------*/ 305 | bddPair* 306 | dfwa_var::make_pair(unsigned fst_copy, unsigned snd_copy) 307 | { 308 | bddPair* pair = bdd_newpair(); 309 | /* 310 | for(unsigned i = 0; i < _dd_nums.size(); i ++) 311 | { 312 | bdd_setpair(pair, (int)(_dd_nums[i] + fst_copy), (int)(_dd_nums[i] + snd_copy)); 313 | cout << "fst = " << (_dd_nums[i] + fst_copy) << " snd = " << (_dd_nums[i] + snd_copy) << endl; 314 | } 315 | */ 316 | vector curr = get_bdd_vars(fst_copy); 317 | vector next = get_bdd_vars(snd_copy); 318 | for(unsigned i = 0; i < curr.size(); i ++) 319 | { 320 | bdd_setpair(pair, bdd_var(curr[i]), bdd_var(next[i])); 321 | //cout << "fst = " << bdd_var(curr[i]) << " snd = " << bdd_var(next[i]) << endl; 322 | } 323 | return pair; 324 | } 325 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Overview 2 | ======= 3 | 4 | Lisa is an (a) LTLf to DFA conversion tool, and (b) an LTLf synthesis tool. 5 | 6 | It is publicly available under the license GNU GPL v3. 7 | 8 | To read more about Lisa, read our [AAAI 2020](https://suguman.github.io/Papers/AAAI20.pdf) paper. 9 | 10 | Requirements 11 | ----------------------------------- 12 | 13 | Lisa requires a C++14-compliant compiler. G++ 5.x or later should work. 14 | 15 | Third-party dependencies 16 | ----------------------------------- 17 | 18 | * [Spot model checker version>=2.9](https://spot.lrde.epita.fr/) 19 | 20 | * [MONA](https://github.com/liyong31/MONA) 21 | 22 | * [CUDD library](https://github.com/KavrakiLab/cudd.git) 23 | 24 | Lisa relies on Spot and MONA to construct a DFA from a small LTLf formula. 25 | When constructing a DFA from an LTLf formula with MONA, Lisa translates an LTLf formula to a formula in first order logic, which is then fed into MONA. 26 | 27 | Complilation steps 28 | ======= 29 | 30 | In the following we assume that we will compile Lisa on a Ubuntu system. 31 | 32 | 1. Install Spot 33 | 34 | Lisa needs Spot to convert an LTLf to a DFA and to perform intersection of DFAs with explicit state representation. 35 | 36 | * Get the latest version of Spot from https://spot.lrde.epita.fr/install.html. 37 | 38 | * Uncompress Spot and follow install intructions in README to install Spot. Note that the compilation of Spot may take a while. 39 | 40 | ./configure && make && sudo make install 41 | 42 | * Type ltl2tgba -f "F a" in command line, you expect to see some output starting with "HOA: v1". 43 | 44 | 2. Install CUDD 45 | 46 | Lisa employs CUDD for symbolic DFA minimization. 47 | 48 | * Uncompress cudd.zip or get CUDD from https://github.com/KavrakiLab/cudd.git. 49 | 50 | * Install CUDD: 51 | 52 | ./configure --enable-silent-rules --enable-obj --enable-dddmp --prefix=[install location] 53 | 54 | sudo make install 55 | 56 | If you encounter an error about aclocal, this might be fixed as follows. 57 | * Not having automake: 58 | 59 | sudo apt-get install automake 60 | * Needing to reconfigure, do this before configuring: 61 | 62 | autoreconf -i 63 | * Using a version of aclocal other than 1.14: 64 | 65 | modify the version 1.14 in configure file accordingly. 66 | 67 | 3. Install MONA 68 | 69 | Lisa needs MONA to convert a formula in first order logic to a DFA. 70 | 71 | * Go to mona-1.4-17 directory and follow the install instructions in INSTALL. 72 | 73 | ./configure && make && sudo make install-strip 74 | 75 | **NOTE** 76 | In BDD/bdd.h, the original table size is defined as #define BDD_MAX_TOTAL_TABLE_SIZE 0x1000000 (=2^24), which is too small for large DFA generation. 77 | We modify it to #define BDD_MAX_TOTAL_TABLE_SIZE 0x1000000000 (=2^36), so to allow MONA have larger table size during DFA construction. 78 | Note that MONA has explicit state representation but encodes the labels on transition symbolically. 79 | For more details on the representation of DFA in MONA, we refer to https://www.brics.dk/mona/mona14.pdf. 80 | 81 | 6. Compile Lisa 82 | 83 | * Compile Lisa with Make: 84 | 85 | make T1 86 | 87 | or compile Lisa in command line: 88 | 89 | g++ lisa.cc dfwavar.cc dfwa.cc spotutil.cc ltlf2fol.cc mona.cc dfwamin.cc synt.cc strategy.cc dfwamin2.cc -o lisa -lspot -lbddx -lcudd -O3 90 | 91 | Input format 92 | ======= 93 | 94 | Lisa accepts LTLf formulas given as a .ltlf file written in SPOT format. 95 | 96 | For synthesis, it also requires a .part file. The .part file indicates the input and output propostitions for the synthesis task. 97 | 98 | Example .ltltf file 99 | 100 | ``` 101 | ((COUNTER0 <-> INITCOUNTER0)) && (G (CARRY0 <-> INC)) && (G ((X COUNTER0 -> !(COUNTER0 <-> CARRY0)) && (X !COUNTER0 -> (COUNTER0 <-> CARRY0)))) && ((G ((!INC -> X INC)) -> F (!COUNTER0))) 102 | ``` 103 | 104 | Example .part file 105 | 106 | ``` 107 | .inputs INITCOUNTER0 INC 108 | .outputs COUNTER0 CARRY0 109 | ``` 110 | 111 | Command line usage 112 | ======= 113 | 114 | If you type ./lisa -h in command line, you should see the following command line usage: 115 | 116 | ``` 117 | Usage: lisa [OPTION...] [FILENAME[/COL]...] 118 | Read a formula file and output the number of states of the constructed DFA 119 | 120 | Input options: 121 | -h show this help page 122 | -exp use only explicit method (default false) 123 | -min minimize the last symbolic DFA (default false) 124 | -syn synthesize after DFA construction (default false) 125 | -bdd use buddy for DFA minimization 126 | -cdd use cudd for DFA minimization 127 | -nap number of atomic propositions for calling mona (default 7) 128 | -npr number of products for calling minimization (default 6) 129 | -nia number of states of individual DFA for calling symbolic approach (default 800) 130 | -npa number of states of product DFA for calling symbolic approach (default 2500) 131 | -lst number of last automata for calling symbolic approach (default -1) 132 | -out print out the wining strategy if realizable 133 | -part the file specifying the input and output propositions 134 | -ltlf the file specifying the input LTLf formula 135 | -env environment plays first 136 | ``` 137 | 138 | For LTLf to DFA construction 139 | == 140 | 1. To use the default setting to construct a DFA from an LTLf formula, type 141 | 142 | ./lisa -ltlf ./examples/ltlf3377.ltlf 143 | 144 | You are expected to see the output ending with "Number of states (or nodes) is: 78626". 145 | In the DFA generation, the symbolic representation of DFA has been triggered. 146 | As we usually do not count the number of states in a symbolic DFA, we only output the number of nodes in the BDD representation of the transition relation of the output DFA. 147 | 148 | Note that the two parameters t1 and t2 mentioned in the submission correspond to respectively the options -nia and -npa . 149 | Recall that the switch from explicit-state form to symbolic-state form is triggered if either the smallest minimal DFA has more than t1 states, or if the product of the number of states in the two smallest minimal DFAs is more than t2. 150 | For example, the following command 151 | 152 | ./lisa -ltlf ./examples/ltlf3377.ltlf -nia 0 -npa 0 153 | 154 | corresponds to pure compositional symbolic DFA generation. You are expected to see the output ending with "Number of states (or nodes) is: 40745". 155 | 156 | 165 | 166 | 2. In order to use only explicit state representation in DFA generation, type 167 | 168 | ./lisa -ltlf ./examples/ltlf3377.ltlf -exp 169 | 170 | The DFA generation with explicit states always terminates and returns a minimal DFA corresponding to the input formula. 171 | You are expected to see the output ending with "Number of states (or nodes) is: 3377". 172 | That is, the number of states in the output explicit DFA is 3377. 173 | Note that the DFA with explicit state representation has one more sink state than the DFA with symbolic representation. 174 | This is because that we use Spot data structure to store DFAs in explicit-state form but Spot only supports automata accepting infinite words. 175 | Therefore, we need to use an extra sink state for the Spot automata as an indicator that it is the end of a finite trace for DFAs. 176 | 177 | For LTLf synthesis 178 | == 179 | 180 | 1. To perform the synthesis step after DFA generation, type 181 | 182 | ./lisa -ltlf ./examples/ltlf3377.ltlf -part ./examples/ltlf3377.part -syn 183 | 184 | where the input and output variables in the LTLf formula are specified in the file ltlf3377.part. 185 | You are expected to see that Lisa outputs "UNREALIZABLE", as this specification is unrealizable. 186 | 187 | 2. To let the environment move first in the DFA game for LTLf synthesis, type 188 | 189 | ./lisa -ltlf ./examples/ltlf3377.ltlf -part ./examples/ltlf3377.part -syn -env 190 | 191 | Syntax 192 | == 193 | 194 | The Linear Temporal Logic over finite traces (LTLf) has the same syntax as LTL. 195 | Given a set P of propositions, the syntax of LTLf formulas supported by Spot is as follows: 196 | ``` 197 | φ ::= 1 | 0 | p | !φ | φ1 && φ2 | φ1 || φ2 | φ1 -> φ2 198 | | φ1 <-> φ2 | X φ | X[!] φ | F φ | G φ | φ1 U φ2 | φ1 R φ2 | φ1 W φ2 199 | 200 | ``` 201 | where p ∈ P. Here 1 and 0 represent *true* and *false* respectively. 202 | X (weak Next), X[!] (strong Next), F (Finally), G (Globally), U (Until), R (Release) and W (weak Until) are temporal operators. 203 | We have that X[!] φ ≡ ! (X !φ), F φ = !(G !φ), φ1 U φ2 ≡ !(!φ1 R !φ2) and φ1 W φ2 ≡ G φ1 || (φ1 U φ2). 204 | As usuall, we also have that F φ ≡ 1 U φ and G φ ≡ 0 R φ. 205 | 206 | For the semantics of LTLf formula, we refer to [IJCAI13 paper](https://www.cs.rice.edu/~vardi/papers/ijcai13.pdf). 207 | Specially, Spot supports a weak next and a strong next. 208 | 209 | Weak next: *X a* is true if *a* holds at next step or if there is no next step. 210 | In particular, *X(0)* is true iff there is no successor. 211 | 212 | Strong next: *X[!] a* is true if *a* holds at next step and there must be a next step. 213 | In particular *X[!]1* is true iff there is a successor. 214 | 215 | **Note** 216 | Other tools like [Syft](https://github.com/saffiepig/Syft) may interpret *X* as a strong next operator and use *N* to denote weak next operator. 217 | Moreover, the minimal DFAs constructed by lisa may have one less state than those by MONA due to the fact that lisa removes nonaccepting sink state while MONA keeps it. 218 | 219 | Please be noted the differences above. 220 | 221 | ## Acknowledgment 222 | - Alexandre Duret-Lutz : [Spot](https://spot.lrde.epita.fr/) 223 | - Jørn Lind-Nielsen: [BuDDy](http://vlsicad.eecs.umich.edu/BK/Slots/cache/www.itu.dk/research/buddy/) 224 | - Fabio Somenzi: [CUDD](https://github.com/ivmai/cudd) 225 | - Shufang Zhu: [Syft](https://github.com/saffiepig/Syft) 226 | - Aarhus University: [MONA](http://www.brics.dk/mona) 227 | - Niels Lohmann [json](https://github.com/nlohmann/json) 228 | 229 | 230 | -------------------------------------------------------------------------------- /src/mona.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #include "mona.hh" 6 | 7 | #include "debug.hh" 8 | #include "spotutil.hh" 9 | 10 | /*-------------------------------------------------------------------*/ 11 | // check whether str contains match 12 | /*-------------------------------------------------------------------*/ 13 | bool 14 | str_contain(string str, const char* match) 15 | { 16 | return str.find(match) != string::npos; 17 | } 18 | /*-------------------------------------------------------------------*/ 19 | // split str by whitespace and return the list of nonspace strings 20 | /*-------------------------------------------------------------------*/ 21 | void 22 | str_split(string str, vector& result, char delim) 23 | { 24 | std::stringstream ss(str); 25 | std::string token; 26 | while (getline(ss, token, delim)) 27 | { 28 | if(! token.empty()) 29 | { 30 | result.push_back(token); 31 | } 32 | } 33 | } 34 | /*-------------------------------------------------------------------*/ 35 | // construct the BDD from mona node file 36 | // used a map to store the nodes which have been visited before 37 | //TODO: construct MTBDD for the successors of the state, this should be more efficient 38 | /*-------------------------------------------------------------------*/ 39 | void 40 | construct_twa_trans( 41 | vector>& succs 42 | , int node_id 43 | , vector& props 44 | , vector>& node_data 45 | , unordered_map>>& node2bdd) 46 | { 47 | if(node2bdd.find(node_id) != node2bdd.end()) 48 | { 49 | // first check whether already computed 50 | succs = node2bdd[node_id]; 51 | return ; 52 | } 53 | // tuple data (x, l, r) where x is the proposition index 54 | // l is the left node 55 | // r is the right node 56 | tuple node = node_data[node_id]; 57 | // reached the leaf node 58 | int prop = get<0>(node); 59 | if(prop == -1) 60 | { 61 | // next state is get<1>(node), label is true 62 | succs.push_back(make_tuple(bddtrue, get<1>(node))); 63 | }else 64 | { 65 | // get the variable dd representation 66 | bdd prop_dd = props[prop]; 67 | // low branch 68 | vector> lsuccs; 69 | construct_twa_trans(lsuccs, get<1>(node), props, node_data, node2bdd); 70 | for (vector>::iterator it = lsuccs.begin() ; it != lsuccs.end(); ++it) 71 | { 72 | tuple tp = *it; 73 | succs.push_back(make_tuple(!prop_dd & get<0>(tp), get<1>(tp))); 74 | } 75 | // high branch 76 | vector> rsuccs; 77 | construct_twa_trans(rsuccs, get<2>(node), props, node_data, node2bdd); 78 | for (vector>::iterator it = rsuccs.begin() ; it != rsuccs.end(); ++it) 79 | { 80 | tuple tp = *it; 81 | succs.push_back(make_tuple(prop_dd & get<0>(tp), get<1>(tp))); 82 | } 83 | } 84 | node2bdd[node_id] = succs; 85 | } 86 | 87 | 88 | /*-------------------------------------------------------------------*/ 89 | // construct the DFA from mona output file 90 | /*-------------------------------------------------------------------*/ 91 | twa_graph_ptr 92 | read_from_mona_file(const char * file_name, bdd_dict_ptr dict) 93 | { 94 | // dfa file 95 | ifstream dfa_file(file_name); 96 | // ordered sequence of propositions 97 | vector atom_props; 98 | // final states in the DFA 99 | vector final_states; 100 | // stores the node number of the state 101 | vector behaviour; 102 | // node tuples for the transitions 103 | vector> node_data; 104 | // number of vars 105 | int num_vars; 106 | // number of states 107 | int num_states; 108 | // init_state 109 | int init_state; 110 | // number of bdd nodes 111 | int num_bdd_node; 112 | 113 | if (dfa_file.is_open()) 114 | { 115 | bool flag = false; 116 | string line; 117 | while(getline(dfa_file, line)) 118 | { 119 | vector temp; 120 | if(flag) 121 | { 122 | if(str_contain(line, "end") ) 123 | { 124 | break; 125 | } 126 | // not end then parsing structure of bdd 127 | str_split(line, temp, ' '); 128 | #ifdef DEBUG 129 | for(int i = 0; i < temp.size(); i ++) 130 | { 131 | cout << temp[i] << " "; 132 | } 133 | cout << endl; 134 | cout << "#bdd = " << temp.size() << endl; 135 | #endif 136 | tuple tp = make_tuple(stoi(temp[0]), stoi(temp[1]), stoi(temp[2])); 137 | 138 | node_data.push_back(tp); 139 | } 140 | if(str_contain(line, "MONA DFA")) 141 | { 142 | DEBUG_STDOUT( "parsing starts" ); 143 | }else 144 | // now we parse the output 145 | //number of variables: 5 146 | if(str_contain(line, "number of variables")) 147 | { 148 | string delimiter = ":"; 149 | string number = line.substr(line.find(delimiter) + 1); 150 | num_vars = stoi(number); 151 | DEBUG_STDOUT("#AP=" + to_string( num_vars)); 152 | }else 153 | // variables: P149 P170 P172 P53 P93 154 | if(str_contain(line, "variables") && !str_contain(line, "number")) 155 | { 156 | // split by white space and delete white space 157 | string delimiter = ":"; 158 | line = line.substr(line.find(delimiter) + 1); 159 | str_split(line, atom_props, ' '); 160 | #ifdef DEBUG 161 | for(int i = 0; i < atom_props.size(); i ++) 162 | { 163 | cout << "AP: " << atom_props[i] << endl; 164 | } 165 | #endif 166 | }else 167 | //states: 19 168 | if(str_contain(line, "states")) 169 | { 170 | string delimiter = ":"; 171 | string number = line.substr(line.find(delimiter) + 1); 172 | num_states = stoi(number); 173 | DEBUG_STDOUT("#S=" + to_string( num_states)); 174 | }else 175 | //initial: 0 176 | if(str_contain(line, "initial")) 177 | { 178 | string delimiter = ":"; 179 | string number = line.substr(line.find(delimiter) + 1); 180 | init_state = stoi(number); 181 | DEBUG_STDOUT("I = " + to_string( init_state)); 182 | }else 183 | // bdd nodes: 76 184 | if(str_contain(line, "bdd nodes")) 185 | { 186 | string delimiter = ":"; 187 | string number = line.substr(line.find(delimiter) + 1); 188 | num_bdd_node = stoi(number); 189 | DEBUG_STDOUT("#bdd = " + to_string( num_bdd_node)); 190 | }else 191 | // final: -1 -1 1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 192 | if(str_contain(line, "final")) 193 | { 194 | string delimiter = ":"; 195 | line = line.substr(line.find(delimiter) + 1); 196 | str_split(line, temp, ' '); 197 | if(temp.size() != num_states) 198 | { 199 | DEBUG_STDERR("error final states"); 200 | }else 201 | { 202 | for(int i = 0;i < temp.size(); i ++) 203 | { 204 | final_states.push_back(temp[i] == "1"); 205 | #ifdef DEBUG 206 | if(temp[i] == "1") 207 | { 208 | cout << "final : " << i << endl; 209 | } 210 | #endif 211 | } 212 | } 213 | }else 214 | // behaviour: 0 1 1 10 17 23 2 29 36 42 48 54 60 62 65 68 70 72 74 215 | // map state to the bdd node 216 | if(str_contain(line, "behaviour")) 217 | { 218 | string delimiter = ":"; 219 | line = line.substr(line.find(delimiter) + 1); 220 | str_split(line, temp, ' '); 221 | DEBUG_STDOUT("behaviour: "); 222 | for(int i = 0; i < temp.size(); i ++) 223 | { 224 | DEBUG_STDOUT(" " + temp[i]); 225 | behaviour.push_back(stoi(temp[i])); 226 | } 227 | cout << endl; 228 | 229 | }else 230 | // bdd: start of bdd 231 | if(str_contain(line, "bdd:")) 232 | { 233 | flag = true; 234 | } 235 | //end 236 | } 237 | dfa_file.close(); 238 | } 239 | // now construct the dfa 240 | spot::twa_graph_ptr aut = make_twa_graph(dict); 241 | vector bdd_props; 242 | // get bdd repr for propositions 243 | for(int i = 0; i < atom_props.size(); i ++) 244 | { 245 | bdd p = bdd_ithvar(aut->register_ap(atom_props[i])); 246 | bdd_props.push_back(p); 247 | } 248 | // add another state 249 | bdd alive = bdd_ithvar(aut->register_ap(ALIVE_AP)); 250 | //bdd_props.push_back(alive); 251 | 252 | aut->set_buchi(); 253 | aut->prop_state_acc(); 254 | // add one extra state for accepting state 255 | aut->new_states(num_states + 1); 256 | //aut->set_init_state(init_state); 257 | 258 | // now construct transition system of aut 259 | DEBUG_STDOUT("behaviour size = " + to_string( behaviour.size())); 260 | // need a map to store computed results 261 | unordered_map>> node2bdd; 262 | 263 | for(int i = 0; i < behaviour.size(); i ++) 264 | { 265 | // construct the transition of a state 266 | //, int state , bdd label , int node_id , vector props 267 | //, vector> node_data 268 | DEBUG_STDOUT("state " + to_string(i) + " behaviour " + to_string(behaviour[i])); 269 | vector> succs; 270 | if(node2bdd.find(behaviour[i]) != node2bdd.end()) 271 | { 272 | succs = node2bdd[behaviour[i]]; 273 | }else 274 | { 275 | construct_twa_trans(succs, behaviour[i], bdd_props, node_data, node2bdd); 276 | } 277 | for(tuple &t : succs) 278 | { 279 | aut->new_edge(i, get<1>(t), get<0>(t) & alive); 280 | } 281 | 282 | // accepting to extra state 283 | if(final_states[i]) 284 | { 285 | aut->new_edge(i, num_states, !alive); 286 | } 287 | } 288 | 289 | // now set accepting states 290 | aut->new_edge(num_states, num_states, !alive, {0}); 291 | aut->merge_edges(); 292 | // traverse intial state 293 | tuple node = node_data[behaviour[0]]; 294 | aut->set_init_state(get<1>(node)); 295 | 296 | #ifdef DEBUG 297 | print_hoa(std::cout, aut); 298 | cout << endl; 299 | #endif 300 | 301 | 302 | return aut; 303 | } 304 | 305 | /*-------------------------------------------------------------------*/ 306 | // execute mona to construct DFA for the input ltlf formula 307 | // NOT depend on ltlf2fol of Syft anymore 308 | /*-------------------------------------------------------------------*/ 309 | twa_graph_ptr 310 | translate_ltlf_mona(formula f, bdd_dict_ptr dict) 311 | { 312 | // code depending on ltlf2fol of Syft 313 | /* 314 | string fol_file_name = "./fol.ltlf"; 315 | ofstream ofs (fol_file_name, ofstream::out); 316 | // output in a parsable formula 317 | ofs << str_psl(f, true); 318 | ofs.close(); 319 | //cout << "formula: " << str_psl(f, true) << endl; 320 | // now call ltlf2fol 321 | string mona_file_name = "./ltlf.mona"; 322 | string command = "./ltlf2fol NNF " + fol_file_name + " > " + mona_file_name; 323 | system(command.c_str()); 324 | */ 325 | string mona_file_name = "./ltlf.mona"; 326 | ofstream ofs(mona_file_name, ofstream::out); 327 | ofs << "#LTLf formula" << endl; 328 | ofs << "#" << str_psl(f, true) << endl; 329 | formula bnf = get_bnf(f); 330 | ofs << "# Backus normal form" << endl; 331 | ofs << "#" << str_psl(bnf, true) << endl; 332 | // the BNF form, and then convert it to fol formula 333 | ltlf_to_fol(ofs, bnf); 334 | ofs.close(); 335 | string dfa_file_name = "./mona.dfa"; 336 | string command = "mona -u -xw " + mona_file_name+ " >" + dfa_file_name; 337 | int r = system(command.c_str()); 338 | // if this turns to be a bottleneck, we need pthread to read from pipe 339 | return read_from_mona_file(dfa_file_name.c_str(), dict); 340 | } 341 | -------------------------------------------------------------------------------- /src/dfwa.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #include "dfwa.hh" 6 | 7 | /*-------------------------------------------------------------------*/ 8 | // initialize dd representation of a product DFA 9 | /*-------------------------------------------------------------------*/ 10 | dfwa::dfwa(bdd_dict_ptr dict, bdd label_cube) 11 | :_state_vars(dict), _label_cube(label_cube) 12 | { 13 | _aut = nullptr; 14 | } 15 | 16 | struct GreaterThanByBddSize 17 | { 18 | bool operator()(bdd& f1, bdd& f2) const 19 | { 20 | int size_1 = bdd_nodecount(f1); 21 | int size_2 = bdd_nodecount(f2); 22 | if(size_1 < size_2) 23 | { 24 | return false; 25 | } 26 | return size_1 >= size_2; 27 | } 28 | }; 29 | 30 | /*-------------------------------------------------------------------*/ 31 | // binary operation construction for computing the disjunction of BDDs 32 | /*-------------------------------------------------------------------*/ 33 | bdd 34 | binary_disjunct_rec(vector & trans, vector & curr_st_bdd, unsigned left, unsigned right) 35 | { 36 | if(left > right) 37 | { 38 | return bddfalse; 39 | }else 40 | if(left == right) 41 | // return (s, a, t) 42 | { 43 | return curr_st_bdd[left] & trans[left]; 44 | }else 45 | // left < right 46 | { 47 | unsigned mid = (left + right) / 2; 48 | bdd op1 = binary_disjunct_rec(trans, curr_st_bdd, left, mid); 49 | bdd op2 = binary_disjunct_rec(trans, curr_st_bdd, mid + 1, right); 50 | return op1 | op2; 51 | } 52 | } 53 | /*-------------------------------------------------------------------*/ 54 | // initialize dd representation of a DFA 55 | // make complete dfa 56 | /*-------------------------------------------------------------------*/ 57 | dfwa::dfwa(twa_graph_ptr aut, bdd label_cube, set& finals, const char* name) 58 | :_state_vars(aut->get_dict(), aut, 2, name, 0, aut->num_states() - 1), _label_cube(label_cube) 59 | { 60 | _aut = aut; 61 | // label cube 62 | //cout << "construct state bdd #S = " << aut->num_states() << endl; 63 | vector curr_st_bdd; 64 | vector next_st_bdd; 65 | for(unsigned i = 0; i < aut->num_states(); i ++) 66 | { 67 | bdd dd = _state_vars.new_value(0, i); 68 | #ifdef DEBUG 69 | cout << "state i = " << i << endl; 70 | bdd_print_sat(cout, aut->get_dict(), dd); 71 | cout << endl; 72 | #endif 73 | curr_st_bdd.push_back(dd); 74 | dd = _state_vars.new_value(1, i); 75 | #ifdef DEBUG 76 | cout << "state i' = " << i << endl; 77 | bdd_print_sat(cout, aut->get_dict(), dd); 78 | cout << endl; 79 | #endif 80 | next_st_bdd.push_back(dd); 81 | } 82 | //cout << " curr_size = " << curr_st_bdd.size() << endl; 83 | _init = curr_st_bdd[aut->get_init_state_number()]; 84 | #ifdef DEBUG 85 | //cout << "init = " << aut->get_init_state_number() << endl; 86 | bdd_print_sat(cout, aut->get_dict(), _init); 87 | cout << endl; 88 | #endif 89 | _trans = bddfalse; 90 | _finals = bddfalse; 91 | // later if not needed, remove _reach 92 | _reach = bddfalse; 93 | cout << "Computing the transition relation..." << endl; 94 | // needs to be improved by huffman ? 95 | //priority_queue, GreaterThanByBddSize> pq; 96 | //vector map2tr; 97 | for(unsigned s = 0; s < aut->num_states(); s ++) 98 | { 99 | _reach = _reach | curr_st_bdd[s]; 100 | if(finals.find(s) != finals.end()) 101 | { 102 | _finals = _finals | curr_st_bdd[s]; 103 | } 104 | bdd sdd = curr_st_bdd[s]; 105 | bdd tdd = bddfalse; 106 | //bdd outs = bddfalse; 107 | for(auto& tr : aut->out(s)) 108 | { 109 | tdd = tdd | (tr.cond & next_st_bdd[tr.dst]); 110 | //outs = outs | tr.cond; 111 | } 112 | sdd = sdd & tdd; 113 | /* 114 | cout << "tr state i = " << s << endl; 115 | bdd_print_sat(cout, aut->get_dict(), sdd); 116 | cout << endl; 117 | cout << endl; 118 | */ 119 | //if(outs != bddtrue) 120 | //{ 121 | // add a sink state 122 | //sdd = sdd | (curr_st_bdd[s] & (! outs) & next_st_bdd[aut->num_states()]); 123 | //} 124 | _trans = _trans | sdd; 125 | 126 | //map2tr.push_back(sdd); 127 | //cout << "encoding state = " << s << endl; 128 | } 129 | // add a sink state 130 | // _trans = _trans | (curr_st_bdd[aut->num_states()] & next_st_bdd[aut->num_states()]); 131 | //cout << "Binary construction for transition relation" << endl; 132 | // binary divide and conquer disjunction of bdds 133 | //_trans = binary_disjunct_rec(map2tr, curr_st_bdd, 0, map2tr.size() - 1); 134 | // compute transitions 135 | /* 136 | while(pq.size() > 1) 137 | { 138 | bdd f1 = pq.top(); 139 | pq.pop(); 140 | bdd f2 = pq.top(); 141 | pq.pop(); 142 | bdd f = f1 | f2; 143 | pq.push(f); 144 | } 145 | _trans = pq.top(); 146 | pq.pop(); 147 | */ 148 | cout << "Finished computing the transition relation..." << endl; 149 | _curr_cube = _state_vars.get_cube(0); 150 | _next_cube = _state_vars.get_cube(1); 151 | // make pairs 152 | _curr_to_next_pairs = _state_vars.make_pair(0, 1); 153 | _next_to_curr_pairs = _state_vars.make_pair(1, 0); 154 | 155 | //bdd all = bdd_replace(_reach, _curr_to_next_pairs); 156 | //all = all & _reach; 157 | //_trans = _trans & all; 158 | #ifdef DEBUG 159 | cout << "trans = " << endl; 160 | bdd_print_sat(cout, aut->get_dict(), _trans); 161 | cout << endl; 162 | 163 | cout << "finals = " << endl; 164 | bdd_print_sat(cout, aut->get_dict(), _finals); 165 | cout << endl; 166 | #endif 167 | } 168 | 169 | dfwa::~dfwa() 170 | { 171 | //cout << "HELLO start" << _curr_to_next_pairs << endl; 172 | if(_curr_to_next_pairs != nullptr) 173 | { 174 | bdd_freepair(_curr_to_next_pairs); 175 | _curr_to_next_pairs = nullptr; 176 | } 177 | //cout << "HELLO second" << _next_to_curr_pairs << endl; 178 | if(_next_to_curr_pairs != nullptr) 179 | { 180 | bdd_freepair(_next_to_curr_pairs); 181 | _next_to_curr_pairs = nullptr; 182 | } 183 | 184 | //cout << "HELLO end" << endl; 185 | } 186 | 187 | /*-------------------------------------------------------------------*/ 188 | // compute next step image of curr 189 | // FIXED (note the returned image contains propositions) 190 | /*-------------------------------------------------------------------*/ 191 | bdd 192 | dfwa::next_image(bdd curr) 193 | { 194 | bdd next = bdd_relprod(_trans, curr, _curr_cube & _label_cube); 195 | next = bdd_replace(next, _next_to_curr_pairs); 196 | return next; 197 | } 198 | 199 | /*-------------------------------------------------------------------*/ 200 | // compute previous image of curr 201 | // FIXED (note the returned image contains propositions) 202 | /*-------------------------------------------------------------------*/ 203 | bdd 204 | dfwa::pre_image(bdd curr) 205 | { 206 | bdd next = bdd_replace(curr, _curr_to_next_pairs); 207 | bdd pre = bdd_relprod(_trans, next, _next_cube & _label_cube); 208 | return pre; 209 | } 210 | /*-------------------------------------------------------------------*/ 211 | // compute reachable state space 212 | /*-------------------------------------------------------------------*/ 213 | bdd 214 | dfwa::explore() 215 | { 216 | bdd s = _init; 217 | bdd sp = bddfalse; 218 | unsigned count = 1; 219 | while(sp != s) 220 | { 221 | cout << "Iteration number = " << count << endl; 222 | // record the states reached within last step 223 | sp = s; 224 | // compute image of next step 225 | #ifdef DEBUG 226 | 227 | cout << "reachable states in product: " << endl; 228 | bdd_print_set(cout, _state_vars.get_dict(), sp); 229 | cout << endl; 230 | #endif 231 | s = sp | next_image(sp); 232 | ++ count; 233 | } 234 | return s; 235 | } 236 | 237 | bdd 238 | dfwa::back_explore() 239 | { 240 | bdd s = _finals; 241 | bdd sp = bddfalse; 242 | unsigned count = 1; 243 | while(sp != s) 244 | { 245 | cout << "Iteration number = " << count << endl; 246 | // record the states reached within last step 247 | sp = s; 248 | // compute image of next step 249 | #ifdef DEBUG 250 | cout << "reachable states in product: " << endl; 251 | bdd_print_set(cout, _state_vars.get_dict(), sp); 252 | cout << endl; 253 | #endif 254 | s = sp | pre_image(sp); 255 | cout << "The number of node in reverse R(" << count << ") is " << bdd_nodecount(s) << endl; 256 | ++ count; 257 | } 258 | return s; 259 | } 260 | 261 | bool 262 | dfwa::is_empty() 263 | { 264 | _reach = explore(); 265 | return (_reach & _finals) == bddfalse; 266 | } 267 | /*-------------------------------------------------------------------*/ 268 | // get data from dfwa 269 | /*-------------------------------------------------------------------*/ 270 | bdd 271 | dfwa::get_init() 272 | { 273 | return _init; 274 | } 275 | 276 | bdd 277 | dfwa::get_trans() 278 | { 279 | return _trans; 280 | } 281 | 282 | bdd 283 | dfwa::get_finals() 284 | { 285 | return _finals; 286 | } 287 | 288 | void 289 | dfwa::output(ostream& os) 290 | { 291 | os << "dfwa: " << endl; 292 | os << "init: " << endl; 293 | bdd_print_set(os, _state_vars.get_dict(), _init); 294 | os << endl; 295 | 296 | os << "trans: " << endl; 297 | bdd_print_set(os, _state_vars.get_dict(), _trans); 298 | os << endl; 299 | 300 | os << "finals: " << endl; 301 | bdd_print_set(os, _state_vars.get_dict(), _finals); 302 | os << endl; 303 | 304 | } 305 | 306 | void 307 | dfwa::output_dfwa(ostream& os) 308 | { 309 | os << "LISA DFA: " << endl; 310 | //os << "//ID VAR HIGH LOW " << endl; 311 | 312 | string alive_ap(ALIVE_AP); 313 | bdd_dict_ptr dict = get_dict(); 314 | int index_alive = dict->varnum(formula::ap(alive_ap)); 315 | bdd dd_alive = bdd_ithvar(index_alive); 316 | bdd label_cube = bdd_exist(_label_cube, dd_alive); 317 | 318 | vector vars; 319 | get_list_var_indices(vars, label_cube); 320 | os << "LABEL VARS:"; 321 | for(unsigned i = 0; i < vars.size(); i ++) 322 | { 323 | os << " " << vars[i]; 324 | } 325 | os << endl; 326 | 327 | vars.clear(); 328 | get_list_var_indices(vars, _curr_cube); 329 | os << "CURR STATE VARS:"; 330 | for(unsigned i = 0; i < vars.size(); i ++) 331 | { 332 | os << " " << vars[i]; 333 | } 334 | os << endl; 335 | 336 | vars.clear(); 337 | get_list_var_indices(vars, _next_cube); 338 | os << "NEXT STATE VARS:"; 339 | for(unsigned i = 0; i < vars.size(); i ++) 340 | { 341 | os << " " << vars[i] ; 342 | } 343 | os << endl; 344 | 345 | os << "INIT: " << _init.id() << endl; 346 | output_bdd(os, _init); 347 | 348 | os << "FINAL: " << _finals.id() << endl; 349 | output_bdd(os, _finals); 350 | 351 | bdd tr = bdd_exist(_trans, dd_alive); 352 | 353 | os << "TRANS: " << tr.id() << endl; 354 | output_bdd(os, tr); 355 | 356 | } 357 | 358 | void 359 | dfwa::make_complete() 360 | { 361 | bdd trans = bddtrue; 362 | for(unsigned i = 0; i < _state_vars._dd_vars[0].size(); i ++) 363 | { 364 | bdd var_0 = _state_vars._dd_vars[0][i]; 365 | bdd var_1 = _state_vars._dd_vars[1][i]; 366 | 367 | trans = trans & bdd_biimp(var_0, var_1); 368 | } 369 | 370 | } 371 | /*-------------------------------------------------------------------*/ 372 | // intersection dfwa: 373 | // result is an empty dfwa 374 | /*-------------------------------------------------------------------*/ 375 | void 376 | intersect_dfwa(dfwa_ptr result, dfwa_ptr op1, dfwa_ptr op2) 377 | { 378 | // set the copies of state variables 379 | result._state_vars._copies = 2; 380 | // now we add variables from op1 and op2 381 | cout << "Computing the intersection product..." << endl; 382 | // check whether this part can be improved 383 | result._state_vars.add_bdd_vars(op1._state_vars); 384 | result._state_vars.add_bdd_vars(op2._state_vars); 385 | cout << "#AP1 = " << op1._state_vars._dd_vars[0].size() << " #AP2 = " << op2._state_vars._dd_vars[0].size() << endl; 386 | cout << "#PRO = " << result._state_vars._dd_vars[0].size() << endl; 387 | // 388 | result._init = op1.get_init() & op2.get_init(); 389 | // especially for the transition relation 390 | cout << "Computing transition relation in the intersection product..." << endl; 391 | result._trans = op1.get_trans() & op2.get_trans(); 392 | cout << "Finished computing transition relation in the intersection product..." << endl; 393 | result._finals = op1.get_finals() & op2.get_finals(); 394 | //result._reach = bddfalse; 395 | result._curr_cube = result._state_vars.get_cube(0); 396 | result._next_cube = result._state_vars.get_cube(1); 397 | // make pairs 398 | result._curr_to_next_pairs = result._state_vars.make_pair(0, 1); 399 | result._next_to_curr_pairs = result._state_vars.make_pair(1, 0); 400 | // compute reachable state space 401 | cout << "Computing reachable state space in the product..." << endl; 402 | result._reach = bddtrue;//result.explore(); 403 | cout << "Finished computing reachable state space in the product..." << endl; 404 | //cout << "reachable states in product: " << endl; 405 | //bdd_print_set(cout, result._state_vars.get_dict(), result._reach); 406 | //cout << endl; 407 | // needs to whether this is useful 408 | /* 409 | bdd all = bdd_replace(result._reach, result._curr_to_next_pairs); 410 | all = all & result._reach; 411 | result._trans = result._trans & all; 412 | */ 413 | cout << "Finished computing the intersection product..." << endl; 414 | } 415 | 416 | /*-------------------------------------------------------------------*/ 417 | // product for dfwa: func is passed for computing final states 418 | // ASSUMPTION: 419 | // 1. labels of op1 and op2 are the same 420 | // 2. the state variables of op1 and op2 are different 421 | /*-------------------------------------------------------------------*/ 422 | void 423 | check_assumption(dfwa_ptr op1, dfwa_ptr op2) 424 | { 425 | /* 426 | if(op1._label_cube != op2._label_cube) 427 | { 428 | cerr << "product: The propositions are not the same" << endl; 429 | cerr << "op1: "; 430 | bdd_print_set(cerr, op1._state_vars.get_dict(), op1._label_cube); 431 | cerr << endl << "op2: "; 432 | bdd_print_set(cerr, op1._state_vars.get_dict(), op2._label_cube); 433 | cerr << endl; 434 | exit(-1); 435 | } 436 | */ 437 | 438 | vector& vars_1 = op1._state_vars.get_bdd_vars(0); 439 | vector& vars_2 = op2._state_vars.get_bdd_vars(0); 440 | 441 | // check whether there are common variables 442 | set vars; 443 | for(unsigned i = 0; i < vars_1.size(); i ++) 444 | { 445 | vars.insert(bdd_var(vars_1[i])); 446 | } 447 | for(unsigned i = 0; i < vars_2.size(); i ++) 448 | { 449 | if(vars.find(bdd_var(vars_2[i])) != vars.end()) 450 | { 451 | cerr << "Product: The state variables are not different -> "; 452 | bdd_print_set(cerr, op1._state_vars.get_dict(), vars_2[i]); 453 | cerr << endl; 454 | for(unsigned j = 0; j < vars_1.size(); j ++) 455 | { 456 | bdd_print_set(cerr, op1._state_vars.get_dict(), vars_1[j]); 457 | cerr << endl; 458 | } 459 | exit(-1); 460 | } 461 | } 462 | } 463 | // keep the variables in increasing order 464 | dfwa_ptr 465 | product_dfwa(dfwa_ptr op1, dfwa_ptr op2, function func) 466 | { 467 | check_assumption(op1, op2); 468 | 469 | bdd label_cube = op1._label_cube & op2._label_cube; 470 | /* 471 | cout << "labels in op1: " << endl; 472 | bdd_print_set(cout, op1.get_dict(), op1._label_cube); 473 | cout << endl; 474 | cout << "labels in op2: " << endl; 475 | bdd_print_set(cout, op1.get_dict(), op2._label_cube); 476 | cout << endl; 477 | */ 478 | dfwa* result = new dfwa(op1.get_dict(), label_cube); 479 | //cout << "labels in product: " << endl; 480 | //bdd_print_set(cout, op1.get_dict(), result->_label_cube); 481 | //cout << endl; 482 | // set the copies of state variables 483 | result->_state_vars._copies = 2; 484 | // now we add variables from op1 and op2 485 | cout << "Computing the product of two DFAs..." << endl; 486 | // check whether this part can be improved 487 | result->_state_vars.add_bdd_vars(op1._state_vars); 488 | result->_state_vars.add_bdd_vars(op2._state_vars); 489 | //cout << "state vars in op1: " << endl; 490 | //bdd_print_set(cout, op1.get_dict(), op1._curr_cube); 491 | //cout << endl; 492 | //cout << "state vars in op2: " << endl; 493 | //bdd_print_set(cout, op1.get_dict(), op2._curr_cube); 494 | //cout << endl; 495 | cout << "Number of current state variables in the two DFAs are respectively: " << op1._state_vars._dd_vars[0].size() << ", " << op2._state_vars._dd_vars[0].size() << endl; 496 | cout << "Number of current state variables in the product is: " << result->_state_vars._dd_vars[0].size() << endl; 497 | //cout << "_init in op1: " << endl; 498 | //bdd_print_set(cout, op1.get_dict(), op1.get_init()); 499 | //cout << endl; 500 | //cout << "_init in op2: " << endl; 501 | //bdd_print_set(cout, op1.get_dict(), op2.get_init()); 502 | //cout << endl; 503 | result->_init = op1.get_init() & op2.get_init(); 504 | //cout << "initial in product: " << endl; 505 | //bdd_print_set(cout, op1.get_dict(), result->_init); 506 | //cout << endl; 507 | // especially for the transition relation 508 | //cout << "#trans1 = " << bdd_nodecount(op1.get_trans()) << " #trans2 = " << bdd_nodecount(op2.get_trans()) << endl; 509 | cout << "Computing transition relation in the intersection product..." << endl; 510 | result->_trans = op1.get_trans() & op2.get_trans(); 511 | //cout << "trans in product: " << endl; 512 | //bdd_print_set(cout, op1.get_dict(), result->_trans); 513 | //cout << endl; 514 | cout << "Finished computing transition relation in the intersection product..." << endl; 515 | cout << "Number of nodes in the transition BDD of the product is: " << bdd_nodecount(result->_trans) << endl; 516 | 517 | bdd finals_1 = op1.get_finals(); 518 | bdd finals_2 = op2.get_finals(); 519 | //cout << "_finals in op1: " << endl; 520 | //bdd_print_set(cout, op1.get_dict(), finals_1); 521 | //cout << endl; 522 | //cout << "_finals in op2: " << endl; 523 | //bdd_print_set(cout, op1.get_dict(), finals_2); 524 | //cout << endl; 525 | result->_finals = func(finals_1, finals_2); 526 | //cout << "finals in product: " << endl; 527 | //bdd_print_set(cout, op1.get_dict(), result->_finals); 528 | //cout << endl; 529 | result->_reach = bddtrue; 530 | //result->_label_cube = op1._label_cube & op2._label_cube; 531 | result->_curr_cube = result->_state_vars.get_cube(0); 532 | //cout << "state vars_0 in product: " << endl; 533 | //bdd_print_set(cout, op1.get_dict(), result->_curr_cube); 534 | //cout << endl; 535 | result->_next_cube = result->_state_vars.get_cube(1); 536 | //cout << "state vars_1 in product: " << endl; 537 | //bdd_print_set(cout, op1.get_dict(), result->_next_cube); 538 | //cout << endl; 539 | // make pairs 540 | result->_curr_to_next_pairs = result->_state_vars.make_pair(0, 1); 541 | result->_next_to_curr_pairs = result->_state_vars.make_pair(1, 0); 542 | // compute reachable state space 543 | //cout << "Computing reachable state space in the product..." << endl; 544 | //result->_reach = result->explore();//bddtrue;// 545 | //cout << "reachable : " << result->_reach << endl; 546 | //cout << "Finished computing reachable state space in the product..." << endl; 547 | //cout << "reachable finals: " << (result->_reach & result->_finals) << endl; 548 | //cout << "reachable states in product: " << endl; 549 | //bdd_print_set(cout, result._state_vars.get_dict(), result._reach); 550 | //cout << endl; 551 | // needs to whether this is useful 552 | // only for test 553 | 554 | //bdd all = bdd_replace(result->_reach, result->_curr_to_next_pairs); 555 | //all = all & result->_reach; 556 | //cout << "reachable states two copies: " << all << endl; 557 | //result->_trans = result->_trans & all; 558 | 559 | cout << "Finished computing the product..." << endl; 560 | return *result; 561 | } 562 | 563 | dfwa_ptr 564 | product_dfwa_and(dfwa_ptr op1, dfwa_ptr op2) 565 | { 566 | return product_dfwa(op1, op2, local_bdd_and); 567 | } 568 | 569 | dfwa_ptr 570 | product_dfwa_or(dfwa_ptr op1, dfwa_ptr op2) 571 | { 572 | return product_dfwa(op1, op2, local_bdd_or); 573 | } 574 | 575 | dfwa_ptr 576 | product_dfwa_minus(dfwa_ptr op1, dfwa_ptr op2) 577 | { 578 | // first make sure op2 is complete 579 | return product_dfwa(op1, op2, local_bdd_not_and); 580 | } 581 | 582 | -------------------------------------------------------------------------------- /src/lisa.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | // standard 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | // spot 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | #include "mona.hh" 42 | #include "spotutil.hh" 43 | #include "dfwavar.hh" 44 | #include "dfwa.hh" 45 | #include "debug.hh" 46 | #include "synt.hh" 47 | #include "dfwamin.hh" 48 | #include "dfwamin2.hh" 49 | //#include "dfwamin3.hh" 50 | 51 | using namespace spot; 52 | using namespace std; 53 | 54 | #define info(o) cout << "[INFO] " << ( o ) << endl 55 | #define erro(o) cerr << "[ERRO] " << ( o ) << endl 56 | 57 | // options 58 | 59 | static struct opt_t 60 | { 61 | const char* _ltlfile_name = nullptr; 62 | const char* _parfile_name = nullptr; 63 | 64 | bool _symbolic = true; 65 | bool _minimization = false; 66 | 67 | unsigned _num_ap_for_mona = 7; 68 | unsigned _num_product = 6; 69 | unsigned _num_st_for_single = 800; 70 | unsigned _num_st_for_product = 2500; 71 | int _num_last_automata = -1; 72 | 73 | bool _synthesis = false; 74 | bool _out_start = false; 75 | bool _env_first = false; 76 | 77 | uint8_t _bdd = 0; 78 | 79 | }* opt; 80 | 81 | 82 | void 83 | get_formulas(vector& lst, formula f) 84 | { 85 | cout << "Breaking formula into small pieces..." << endl; 86 | if(f.kind() == op::And) 87 | { 88 | // needs to limit the number of conjunctions if no minimization is used before producting two FAs 89 | for(formula child: f) 90 | { 91 | lst.push_back(child); 92 | //cout << "subformula: " << child << endl; 93 | } 94 | }else 95 | { 96 | lst.push_back(f); 97 | } 98 | //cout << "split formula " << endl; 99 | } 100 | 101 | class dfwa_pair 102 | { 103 | public: 104 | unsigned _num_states; 105 | bool _is_explicit; 106 | twa_graph_ptr _twa; 107 | dfwa* _dfa = nullptr; 108 | unsigned _num_propduct = 0; 109 | 110 | formula _formula; 111 | 112 | dfwa_pair(twa_graph_ptr aut, unsigned num_states, bool is_explicit, formula& f) 113 | : _num_states(num_states), _is_explicit(is_explicit), _formula(f) 114 | { 115 | _twa = aut; 116 | } 117 | dfwa_pair(dfwa* aut, unsigned num_states, bool is_explicit, formula& f) 118 | : _num_states(num_states), _is_explicit(is_explicit), _formula(f) 119 | { 120 | _dfa = aut; 121 | //_twa = new shared_ptr(new twa_graph); 122 | } 123 | }; 124 | 125 | struct GreaterThanByDfwaSize 126 | { 127 | bool operator()(dfwa_pair& p1, dfwa_pair& p2) const 128 | { 129 | if(p1._num_states < p2._num_states) 130 | { 131 | return false; 132 | }else 133 | if(p1._num_states == p2._num_states) 134 | { 135 | return !p1._is_explicit; 136 | } 137 | return p1._num_states >= p2._num_states; 138 | } 139 | }; 140 | 141 | bool 142 | compare_aut_size(twa_graph_ptr p1, twa_graph_ptr p2) 143 | { 144 | if(p1->num_states() == p2->num_states()) 145 | { 146 | return false; 147 | } 148 | return p1->num_states() > p2->num_states(); 149 | } 150 | 151 | twa_graph_ptr minimize_explicit(twa_graph_ptr A) 152 | { 153 | twa_graph_ptr C = spot::minimize_wdba(A); 154 | //A = spot::minimize_obligation(A); 155 | // check equivalence of two automata 156 | #ifdef DEBUG 157 | string word = is_twa_equivalent(A, C); 158 | if(word.size() == 0) 159 | { 160 | cout << "A: equivalent two automata" << endl; 161 | } 162 | #endif 163 | return C; 164 | } 165 | 166 | tuple 167 | minimize_symbolic(dfwa_ptr P) 168 | { 169 | unsigned num_states; 170 | tuple result; 171 | if(opt->_bdd == 1) 172 | { 173 | cudd manager; 174 | cudd_ptr mgr = &manager; 175 | // call dfa minimization 176 | dfwa_min min(mgr, P); 177 | min.minimize(); 178 | dfwa_ptr res = min.move_dfwa(); 179 | // check wehter the emptiness is changed 180 | num_states = min.get_num_min_states(); 181 | result = make_tuple<>(&res, num_states, true); 182 | }else 183 | if(opt->_bdd == 2) 184 | { 185 | dfwa_min_bdd min(P); 186 | min.minimize(); 187 | dfwa_ptr res = min.move_dfwa(); 188 | // check wehter the emptiness is changed 189 | num_states = min.get_num_min_states(); 190 | result = make_tuple<>(&res, num_states, true); 191 | }else 192 | { 193 | /* 194 | dfwa_min_sylvan min(P); 195 | min.minimize(); 196 | dfwa_ptr res = min.move_dfwa(); 197 | // check wehter the emptiness is changed 198 | num_states = min.get_num_min_states(); 199 | result = make_tuple<>(&res, num_states, true); 200 | 201 | */ 202 | } 203 | return result; 204 | } 205 | 206 | tuple 207 | make_product(bdd_dict_ptr dict, dfwa* A, dfwa* B, unsigned num_prod) 208 | { 209 | unsigned num_states; 210 | 211 | dfwa_ptr P = product_dfwa_and(*A, *B); 212 | //cout << "labels in product and: " << P._label_cube << endl; 213 | //cout << "state_0 in product and: " << P._curr_cube << endl; 214 | //cout << "state_1 in product and: " << P._next_cube << endl; 215 | //cout << "product: " << endl; 216 | //P.output(cout); 217 | 218 | //unsigned var_num = 1; 219 | //cout << "condition: " << (P._state_vars.get_var_num(0) > var_num) << endl; 220 | 221 | if(num_prod > (opt->_num_product)) 222 | { 223 | tuple result = minimize_symbolic(P); 224 | delete &P; 225 | cout << "return from minimal product..." << endl; 226 | return result; 227 | }else 228 | { 229 | num_states = bdd_nodecount(P._trans); 230 | return make_tuple<>(&P, num_states, false); 231 | } 232 | 233 | } 234 | 235 | 236 | 237 | void print_usage() 238 | { 239 | cout << "Usage: lisa [OPTION...] [FILENAME[/COL]...]" << endl; 240 | cout << "Read a formula file and output the number of states of the constructed DFA" << endl << endl; 241 | cout << " Input options:" << endl; 242 | cout << " -h " << " show this help page" << endl; 243 | cout << " -exp" << " use only explicit method (default false)" << endl; 244 | cout << " -min" << " minimize the last symbolic DFA (default false)" << endl; 245 | cout << " -syn" << " synthesize after DFA construction (default false)" << endl; 246 | cout << " -bdd" << " use buddy for DFA minimization" << endl; 247 | //cout << " -syl" << " use sylvan for DFA minimization (default)" << endl; 248 | cout << " -cdd" << " use cudd for DFA minimization" << endl; 249 | cout << " -nap" << " number of atomic propositions for calling mona (default 7)" << endl; 250 | cout << " -npr" << " number of products for calling minimization (default 6)" << endl; 251 | cout << " -nia" << " number of states of individual DFA for calling symbolic approach (default 800)" << endl; 252 | cout << " -npa" << " number of states of product DFA for calling symbolic approach (default 2500)" << endl; 253 | cout << " -lst" << " number of last automata for calling symbolic approach (default -1)" << endl; 254 | cout << " -out" << " print out the wining strategy if realizable" << endl; 255 | cout << " -part" << " the file specifying the input and output propositions" << endl; 256 | cout << " -ltlf" << " the file specifying the input LTLf formula" << endl; 257 | cout << " -env" << " environment plays first" << endl; 258 | } 259 | 260 | void parse_opt(int argc, char** argv) 261 | { 262 | // first one is lisa, separated by space 263 | if(argc == 1) 264 | { 265 | print_usage(); 266 | } 267 | for(int i = 1; i < argc; i ++) 268 | { 269 | string s(argv[i]); 270 | //cout << argv[i] << endl; 271 | if(s.size() == 0) 272 | { 273 | continue; 274 | } 275 | if(s == "-exp") 276 | { 277 | opt->_symbolic = false; 278 | //cout << "hello" << s << endl; 279 | continue; 280 | } 281 | if(s == "-min") 282 | { 283 | opt->_minimization = true; 284 | continue; 285 | } 286 | if(s == "-syn") 287 | { 288 | opt->_synthesis = true; 289 | continue; 290 | } 291 | if(s == "-out") 292 | { 293 | opt->_out_start = true; 294 | continue; 295 | } 296 | if(s == "-env") 297 | { 298 | opt->_env_first = true; 299 | continue; 300 | } 301 | if(s == "-nap" && i + 1 < argc) 302 | { 303 | opt->_num_ap_for_mona = stoi(argv[i + 1]); 304 | i ++; 305 | continue; 306 | } 307 | if(s == "-npr" && i + 1 < argc) 308 | { 309 | opt->_num_product = stoi(argv[i + 1]); 310 | i ++; 311 | continue; 312 | } 313 | if(s == "-nia" && i + 1 < argc) 314 | { 315 | opt->_num_st_for_single = stoi(argv[i + 1]); 316 | i ++; 317 | continue; 318 | } 319 | if(s == "-lst" && i + 1 < argc) 320 | { 321 | opt->_num_last_automata = stoi(argv[i + 1]); 322 | i ++; 323 | continue; 324 | } 325 | if(s == "-npa" && i + 1 < argc) 326 | { 327 | opt->_num_st_for_product = stoi(argv[i + 1]); 328 | i ++; 329 | continue; 330 | } 331 | if(s == "-ltlf" && i + 1 < argc) 332 | { 333 | opt->_ltlfile_name = argv[i + 1]; 334 | //cout << "hello" << argv[i+1] << endl; 335 | i ++; 336 | continue; 337 | } 338 | if(s == "-part" && i + 1 < argc) 339 | { 340 | opt->_parfile_name = argv[i + 1]; 341 | i ++; 342 | continue; 343 | } 344 | if(s == "-cdd") 345 | { 346 | opt->_bdd = 1; 347 | continue; 348 | } 349 | if(s == "-bdd") 350 | { 351 | opt->_bdd = 2; 352 | continue; 353 | } 354 | /* 355 | if(s == "-syl") 356 | { 357 | opt->_bdd = 0; 358 | continue; 359 | } 360 | */ 361 | if(s == "-h") 362 | { 363 | print_usage(); 364 | exit(0); 365 | }else 366 | { 367 | erro("wrong input options: " + s); 368 | print_usage(); 369 | exit(-1); 370 | } 371 | } 372 | // validity checking 373 | if(opt->_ltlfile_name == nullptr ) 374 | { 375 | erro( "missing LTLf file name"); 376 | exit(-1); 377 | } 378 | if(opt->_synthesis && ( opt->_parfile_name == nullptr)) 379 | { 380 | erro("missing proposition partition file name"); 381 | exit(-1); 382 | } 383 | 384 | } 385 | 386 | dfwa* 387 | symbolize_twa(bdd_dict_ptr dict, twa_graph_ptr aut) 388 | { 389 | // there is alive states 390 | bdd label_cube = bddtrue; 391 | for (auto f : aut->ap()) 392 | { 393 | bdd f_var = bdd_ithvar(aut->register_ap(f)); 394 | label_cube = label_cube & f_var; 395 | //cout << "formula : " << f << " index: " << aut->register_ap(f) << endl; 396 | } 397 | 398 | set finals_aut; 399 | compute_final_states(aut, finals_aut); 400 | /* 401 | cout << "final states: " << endl; 402 | for(unsigned k : finals_aut) 403 | { 404 | cout << "final: " << k << endl; 405 | }*/ 406 | /* 407 | if(aut->num_states() < 20) 408 | { 409 | ofstream outfile("output" + to_string(number) + ".hoa"); 410 | print_hoa(outfile, aut); 411 | for(unsigned k : finals_aut) 412 | { 413 | cout << "output: " << k << endl; 414 | } 415 | number ++; 416 | }*/ 417 | // now compute dfwa 418 | dfwa* A = new dfwa(aut, label_cube, finals_aut); 419 | return A; 420 | } 421 | void 422 | read_from_part_file(const char *file_name, vector& input, vector& output) 423 | { 424 | // const char * file_name 425 | ifstream part_file(file_name); 426 | if (part_file.is_open()) 427 | { 428 | bool flag = false; 429 | string line; 430 | while(getline(part_file, line)) 431 | { 432 | if(str_contain(line, "inputs")) 433 | { 434 | string delimiter = ":"; 435 | line = line.substr(line.find(delimiter) + 1); 436 | str_split(line, input, ' '); 437 | }else 438 | if(str_contain(line, "outputs")) 439 | { 440 | string delimiter = ":"; 441 | line = line.substr(line.find(delimiter) + 1); 442 | str_split(line, output, ' '); 443 | }else 444 | { 445 | cout << "read partfile error!" <_ltlfile_name); 463 | string line; 464 | priority_queue, GreaterThanByDfwaSize> autlist; 465 | clock_t c_start = clock(); 466 | spot::bdd_dict_ptr dict = spot::make_bdd_dict(); 467 | formula input_f; 468 | cout << "Starting the decomposition phase" << endl; 469 | if (ltlfile.is_open()) 470 | { 471 | getline (ltlfile, line); 472 | //cout << "formula: " << line << endl; 473 | auto pf1 = spot::parse_infix_psl(line.c_str()); 474 | if (pf1.format_errors(std::cerr)) 475 | { 476 | std::cerr << "Error: " << line << std::endl; 477 | return -1; 478 | } 479 | // formula 480 | input_f = pf1.f; 481 | vector lst; 482 | //cout << "parsed: " << pf1.f << endl; 483 | get_formulas(lst, pf1.f); 484 | /* 485 | set ap_set; 486 | get_formula_aps(input_f, ap_set); 487 | for(formula f : ap_set) 488 | { 489 | int index = dict->register_acceptance_variable(f, opt); 490 | cout << f << "->" << index << endl; 491 | }*/ 492 | //reorganize_formulas(lst); 493 | while(lst.size() > 0) 494 | { 495 | // translating automata 496 | formula f = lst.back(); 497 | lst.pop_back(); 498 | // cout << str_psl(f, true) << endl; 499 | twa_graph_ptr aut = trans_formula(f, dict, opt->_num_ap_for_mona); 500 | // cout << aut->num_states() << endl; 501 | dfwa_pair pair(aut, aut->num_states(), true, f); 502 | pair._num_propduct = 0; 503 | // cout << "st = " << aut->num_states() << endl; 504 | autlist.push(pair); 505 | } 506 | ltlfile.close(); 507 | } 508 | 509 | //cout << "splited formulas" << endl; 510 | // do products 511 | bdd_autoreorder(BDD_REORDER_WIN2ITE); 512 | cout << "Starting the composition phase" << endl; 513 | 514 | set optimized; 515 | while(autlist.size() > 1) 516 | { 517 | cout << "Number of DFAs in the set: " << autlist.size() << endl; 518 | dfwa_pair first = autlist.top(); 519 | autlist.pop(); 520 | dfwa_pair second = autlist.top(); 521 | autlist.pop(); 522 | cout << "Number of states or nodes in M1 and M2: " << first._num_states 523 | << ", " << second._num_states << endl; 524 | formula result_formula = formula::And({first._formula, second._formula}); 525 | //cout << result_formula << endl; 526 | bool must_symbolic = opt->_num_last_automata > 0 && autlist.size() + 2 <= opt->_num_last_automata; 527 | if(first._is_explicit && second._is_explicit) 528 | { 529 | twa_graph_ptr A = first._twa; 530 | twa_graph_ptr B = second._twa; 531 | if(optimized.find(A) == optimized.end()) 532 | { 533 | A = minimize_explicit(A); 534 | optimized.insert(A); 535 | } 536 | if(optimized.find(B) == optimized.end()) 537 | { 538 | B = minimize_explicit(B); 539 | optimized.insert(B); 540 | } 541 | 542 | if( !opt->_symbolic || (! must_symbolic && (A->num_states() < opt->_num_st_for_single && B->num_states() < opt->_num_st_for_single 543 | && (A->num_states() * B->num_states() < opt->_num_st_for_product)))) 544 | { 545 | // explict representation used 546 | twa_graph_ptr P = spot::product(A, B); 547 | //cout << "explicit minimization starts..." << endl; 548 | P = spot::minimize_wdba(P); 549 | optimized.insert(P); 550 | dfwa_pair pair(P, P->num_states(), true, result_formula); 551 | pair._num_propduct = 1; 552 | cout << "Number of states in explicit product is: " << P->num_states() << endl; 553 | autlist.push(pair); 554 | }else 555 | { 556 | dfwa* fst = symbolize_twa(dict, A); 557 | dfwa* snd = symbolize_twa(dict, B); 558 | tuple result = make_product(dict, fst, snd, 2); 559 | dfwa_pair pair(get<0>(result), get<1>(result), false, result_formula); 560 | if(get<2>(result)) 561 | { 562 | pair._num_propduct = 1; 563 | }else 564 | { 565 | pair._num_propduct = 2; 566 | } 567 | cout << "Number of nodes in symbolic product is: " << get<1>(result) << endl; 568 | autlist.push(pair); 569 | delete fst; 570 | delete snd; 571 | } 572 | }else if(first._is_explicit || second._is_explicit) 573 | { 574 | // needs symbolic automata 575 | dfwa* A = nullptr; 576 | dfwa* B = nullptr; 577 | 578 | if(first._is_explicit) 579 | { 580 | twa_graph_ptr aut = first._twa; 581 | B = second._dfa; 582 | // make sure it is weak DBA 583 | if (optimized.find(aut) == optimized.end()) 584 | { 585 | aut = minimize_explicit(aut); 586 | } 587 | // now compute dfwa 588 | A = symbolize_twa(dict, aut); 589 | }else 590 | { 591 | twa_graph_ptr aut = second._twa; 592 | B = first._dfa; 593 | if (optimized.find(aut) == optimized.end()) 594 | { 595 | aut = minimize_explicit(aut); 596 | } 597 | // now compute dfwa 598 | A = symbolize_twa(dict, aut); 599 | } 600 | unsigned num = first._num_propduct + second._num_propduct + 1; 601 | tuple result = make_product(dict, A, B, num); 602 | dfwa_pair pair(get<0>(result), get<1>(result), false, result_formula); 603 | if(get<2>(result)) 604 | { 605 | pair._num_propduct = 1; 606 | }else 607 | { 608 | pair._num_propduct = num; 609 | } 610 | cout << "Number of nodes in symbolic product is: " << get<1>(result) << endl; 611 | autlist.push(pair); 612 | delete B; 613 | }else 614 | { 615 | // two symbolic automata 616 | dfwa* A = first._dfa; 617 | dfwa* B = second._dfa; 618 | unsigned num = first._num_propduct + second._num_propduct; 619 | tuple result = make_product(dict, A, B, num); 620 | dfwa_pair pair(get<0>(result), get<1>(result), false, result_formula); 621 | cout << "Number of nodes in symbolic product is: " << get<1>(result) << endl; 622 | autlist.push(pair); 623 | if(get<2>(result)) 624 | { 625 | pair._num_propduct = 1; 626 | }else 627 | { 628 | pair._num_propduct = num; 629 | } 630 | 631 | delete A; 632 | delete B; 633 | } 634 | } 635 | clock_t c_end = clock(); 636 | cout << "Finished constructing minimal dfa in " 637 | << 1000.0 * (c_end - c_start)/CLOCKS_PER_SEC << "ms ..." << endl; 638 | dfwa_pair pair = autlist.top(); 639 | cout << "Number of states (or nodes) is: " << pair._num_states << endl; 640 | if(pair._is_explicit && optimized.find(pair._twa) == optimized.end()) 641 | { 642 | // in case we only have one DFA and it is not minimized 643 | pair._twa = minimize_explicit(pair._twa); 644 | } 645 | cout << "Final result (or number of nodes): " << pair._num_states << endl; 646 | if(! pair._is_explicit && ! opt->_synthesis) 647 | { 648 | if(opt->_minimization) 649 | { 650 | minimize_symbolic(*pair._dfa); 651 | } 652 | delete pair._dfa; 653 | exit(0); 654 | } 655 | if(pair._is_explicit && ! opt->_synthesis) 656 | { 657 | if(opt->_out_start) 658 | { 659 | // output 660 | ofstream outfile("output.hoa"); 661 | print_hoa(outfile, pair._twa); 662 | } 663 | exit(0); 664 | } 665 | dfwa* aut = nullptr; 666 | if(! pair._is_explicit) 667 | { 668 | aut = pair._dfa; 669 | }else 670 | { 671 | aut = symbolize_twa(dict, pair._twa); 672 | } 673 | // synthesis 674 | vector input; 675 | vector output; 676 | //cout << "read part file " << endl; 677 | if(opt->_parfile_name != nullptr) 678 | { 679 | read_from_part_file(opt->_parfile_name, input, output); 680 | }else 681 | { 682 | cerr << "Please input the file name for inputs and outputs" << endl; 683 | exit(-1); 684 | } 685 | //cout << "The number of nodes in transition is " << bdd_nodecount(aut->_trans) << endl; 686 | //cout << "finished reading part file " << endl; 687 | // NOTE that some propositions may not be used in DFA 688 | bdd input_cube = bddtrue; 689 | bdd output_cube = bddtrue; 690 | //set set_aps; 691 | //get_formula_aps(input_f, set_aps); 692 | //set::iterator it; 693 | map& var_map = dict->var_map; 694 | #ifdef DEBUG 695 | map::const_iterator iter = var_map.begin(); 696 | while (iter != var_map.end()) 697 | { 698 | formula key = iter->first; 699 | int value = iter->second; 700 | cout << key << " -> " << value << endl; 701 | iter ++; 702 | } 703 | #endif 704 | //cout << dict->var_map << endl; 705 | //cout << "partition of propositions" << endl; 706 | for(string& in : input) 707 | { 708 | formula f = formula::ap(in); 709 | // not in var map 710 | if(var_map.count(f) == 0) 711 | { 712 | continue; 713 | } 714 | //cout << "in: " << in << " "; 715 | int var_index = dict->varnum(f); 716 | //cout << var_index << endl; 717 | bdd p = bdd_ithvar(var_index); 718 | input_cube = input_cube & p; 719 | } 720 | //cout << "done with input propositions" << endl; 721 | for(string& out : output) 722 | { 723 | formula f = formula::ap(out); 724 | // not in var map 725 | if(var_map.count(f) == 0) 726 | { 727 | continue; 728 | } 729 | //cout << "out: " << out << " "; 730 | int var_index = dict->varnum(f); 731 | //cout << var_index << endl; 732 | bdd p = bdd_ithvar(var_index); 733 | output_cube = output_cube & p; 734 | } 735 | string alive_ap(ALIVE_AP); 736 | int var_index = dict->varnum(formula::ap(alive_ap)); 737 | bdd p = bdd_ithvar(var_index); 738 | output_cube = output_cube & p; 739 | //cout << "out: " << alive_ap << " " << var_index << endl; 740 | 741 | //aut->output(cout); 742 | { 743 | clock_t c_start = clock(); 744 | auto t_start = chrono::high_resolution_clock::now(); 745 | //aut->output_dfwa(cout); 746 | synt syn(*aut, input_cube, output_cube); 747 | cout << "Starting to synthesize " << endl; 748 | if(opt->_env_first) 749 | { 750 | syn.env_play_first(); 751 | cout << "Environment will play first" << endl; 752 | }else{ 753 | cout << "System will play first" << endl; 754 | } 755 | syn.is_realizable(); 756 | if(opt->_out_start) 757 | { 758 | syn.synthesize(); 759 | } 760 | cout << "Finished synthesizing" << endl; 761 | 762 | clock_t c_end = clock(); 763 | cout << 1000.0 * (c_end - c_start) / CLOCKS_PER_SEC << " ms\n"; 764 | auto t_end = chrono::high_resolution_clock::now(); 765 | cout << "Total CPU time used: " 766 | << 1000.0 * (c_end - c_start) / CLOCKS_PER_SEC << " ms\n" 767 | << "Total wall clock time passed: " 768 | << std::chrono::duration(t_end-t_start).count() 769 | << " ms\n"; 770 | } 771 | if(aut != nullptr) 772 | { 773 | delete aut; 774 | } 775 | opt = nullptr; 776 | //dict->unregister_all_my_variables(opt); 777 | //dict->unregister_acceptance_variable(opt); 778 | } 779 | -------------------------------------------------------------------------------- /src/dfwamin2.cc: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------*/ 2 | // Yong Li (liyong@ios.ac.cn) 3 | /*-------------------------------------------------------------------*/ 4 | 5 | #include "dfwamin2.hh" 6 | 7 | dfwa_min_bdd::dfwa_min_bdd(dfwa_ptr aut) 8 | : _aut (aut) 9 | { 10 | //bdd_gbc(); 11 | prepare(); 12 | } 13 | 14 | /*-------------------------------------------------------------------*/ 15 | // prepare state, label and block variables for DFA minimization 16 | /*-------------------------------------------------------------------*/ 17 | void 18 | dfwa_min_bdd::prepare_variables() 19 | { 20 | _label_to_anony_pair = bdd_newpair(); 21 | _anony_to_label_pair = bdd_newpair(); 22 | _curr_to_next_block_pair = bdd_newpair(); 23 | _next_to_curr_block_pair = bdd_newpair(); 24 | // 0. create duplicate label variables for dfa minimization 25 | vector state_vars; 26 | get_list_var_indices(state_vars, _aut._curr_cube & _aut._next_cube); 27 | // A' duplicate variables for labels 28 | //unsigned num_state_var = _aut._state_vars.get_bdd_vars(0); 29 | #ifdef __ORIGINAL__ 30 | _curr_to_next_state_pair = bdd_newpair(); 31 | _next_to_curr_state_pair = bdd_newpair(); 32 | _state_to_anony_pair = bdd_newpair(); 33 | 34 | vector curr_state_vars = _aut._state_vars.get_bdd_vars(0); 35 | vector next_state_vars = _aut._state_vars.get_bdd_vars(1); 36 | //get_list_var_indices(next_state_vars, _aut._next_cube ); 37 | _curr_cube = bddtrue; 38 | _next_cube = bddtrue; 39 | // start of the state index 40 | int buddy_index = 0; // state_vars.back() + 1 41 | for(unsigned i = 0; i < curr_state_vars.size(); i ++) 42 | { 43 | int curr_index = bdd_var(curr_state_vars[i]); 44 | bdd_setpair(_state_to_anony_pair, curr_index, buddy_index); 45 | _map[curr_index] = buddy_index; 46 | //_map[buddy_index] = buddy_index; 47 | _curr_cube = _curr_cube & bdd_ithvar(buddy_index); 48 | ++ buddy_index; 49 | int next_index = bdd_var(next_state_vars[i]); 50 | bdd_setpair(_state_to_anony_pair, next_index, buddy_index); 51 | _map[next_index] = buddy_index; 52 | //_map[buddy_index] = buddy_index; 53 | _next_cube = _next_cube & bdd_ithvar(buddy_index); 54 | bdd_setpair(_curr_to_next_state_pair, buddy_index - 1, buddy_index); 55 | bdd_setpair(_next_to_curr_state_pair, buddy_index, buddy_index - 1); 56 | ++ buddy_index; 57 | } 58 | cout << "Number of state variables is " << buddy_index << endl; 59 | // the first position for label variables 60 | _max_states_var = buddy_index + 1; 61 | #else 62 | _curr_cube = _aut._curr_cube; 63 | _next_cube = _aut._next_cube; 64 | _max_states_var = state_vars.back() + 1; 65 | #endif 66 | vector label_vars; 67 | get_list_var_indices(label_vars, _aut._label_cube); 68 | // create anonymous variables for labels 69 | _label_cube = bddtrue; 70 | for(unsigned i = 0; i < label_vars.size(); i ++) 71 | { 72 | int buddy_index = _max_states_var + i; 73 | buddy_bdd var_dd = bdd_ithvar(buddy_index); 74 | _label_cube = _label_cube & var_dd; 75 | _map[label_vars[i]] = buddy_index; 76 | //_map[label_vars[i]] = label_vars[i]; 77 | bdd_setpair(_label_to_anony_pair, label_vars[i], buddy_index); 78 | bdd_setpair(_anony_to_label_pair, buddy_index, label_vars[i]); 79 | //_anony_to_label[buddy_index] = label_vars[i]; 80 | } 81 | _last_pos_labels = _max_states_var + label_vars.size(); 82 | 83 | // 3. create block vectors 84 | // K block variables 85 | vector curr_block; 86 | _block_vars.push_back(curr_block); 87 | vector next_block; 88 | _block_vars.push_back(next_block); 89 | int num_block_var = 2 * _aut._state_vars.get_var_num(0); 90 | for(int i = 0; i < num_block_var; i +=2) 91 | { 92 | int buddy_index = _last_pos_labels + i; 93 | //cout << "block variable " << var_dd << endl; 94 | buddy_bdd var_dd = bdd_ithvar(buddy_index); 95 | _block_vars[0].push_back(var_dd); 96 | var_dd = bdd_ithvar(buddy_index + 1); 97 | _block_vars[1].push_back(var_dd); 98 | bdd_setpair(_curr_to_next_block_pair, buddy_index, buddy_index + 1); 99 | bdd_setpair(_next_to_curr_block_pair, buddy_index + 1, buddy_index); 100 | } 101 | } 102 | 103 | /*-------------------------------------------------------------------*/ 104 | // prepare CUDD DFA minimization 105 | /*-------------------------------------------------------------------*/ 106 | void 107 | dfwa_min_bdd::prepare() 108 | { 109 | // create variables of dfwa_min_bdd:: 110 | cout << "minimized before prepare " << _aut._label_cube << endl; 111 | prepare_variables(); 112 | // copy the initial state 113 | clock_t c_start = clock(); 114 | #ifdef __ORIGINAL__ 115 | _init = bdd_replace(_aut._init, _state_to_anony_pair); 116 | #else 117 | _init = _aut._init; 118 | #endif 119 | cout << "minimized init: " << _init << endl; 120 | int count = bdd_nodecount(_aut._trans); 121 | cout << "The number of nodes in transition after reach is " << bdd_nodecount(_aut._trans) << endl; 122 | #ifdef __ORIGINAL__ 123 | //bddPair* result_pair = bdd_mergepairs(_state_to_anony_pair, _label_to_anony_pair); 124 | //_trans = bdd_replace(_aut._trans, result_pair); 125 | _trans = move_to(_aut._trans); 126 | //bdd_freepair(result_pair); 127 | 128 | #else 129 | _trans = bdd_replace(_aut._trans, _label_to_anony_pair); 130 | #endif 131 | cout << "The number of nodes in transition after renaming is " << bdd_nodecount(_trans) << endl; 132 | //_trans = bdd_replace(_trans, _state_to_anony_pair); 133 | // copy the final states 134 | //cout << "minimized trans: " << _trans << endl; 135 | #ifdef __ORIGINAL__ 136 | _finals = bdd_replace(_aut._finals, _state_to_anony_pair); 137 | #else 138 | _finals = _aut._finals; 139 | #endif 140 | //cout << "minimized finals " << _finals << endl; 141 | //cout << "minimized labels " << _aut._label_cube << endl; 142 | clock_t c_end = clock(); 143 | cout << "Finished renaming BDD in " 144 | << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << "ms ..." 145 | << "node for trans" << count << endl; 146 | 147 | } 148 | 149 | buddy_bdd 150 | dfwa_min_bdd::move_to(buddy_bdd dd) 151 | { 152 | unordered_map computed_table; 153 | return move_to(dd, computed_table); 154 | } 155 | 156 | buddy_bdd 157 | dfwa_min_bdd::move_to(buddy_bdd dd, unordered_map& computed_table) 158 | { 159 | int dd_id = dd.id(); 160 | unordered_map::const_iterator it = computed_table.find(dd_id); 161 | if(it != computed_table.end()) 162 | { 163 | return it->second; 164 | } 165 | if(dd == bddtrue || dd == bddfalse) 166 | { 167 | //cout << "true: node id = " << dd_id << endl; 168 | return dd; 169 | }else 170 | { 171 | //nodes_num ++; 172 | //cout << "visited " << nodes_num << endl; 173 | buddy_bdd high = move_to(bdd_high(dd), computed_table); 174 | buddy_bdd low = move_to(bdd_low(dd), computed_table); 175 | int buddy_index = bdd_var(dd); 176 | int anony_var_index = _map[buddy_index]; 177 | buddy_bdd var_dd = bdd_ithvar(anony_var_index); 178 | buddy_bdd result = bdd_ite(var_dd, high, low); 179 | computed_table[dd_id] = result; 180 | return result; 181 | } 182 | } 183 | 184 | dfwa_min_bdd::~dfwa_min_bdd() 185 | { 186 | if (_label_to_anony_pair != nullptr) 187 | { 188 | bdd_freepair(_label_to_anony_pair); 189 | _label_to_anony_pair = nullptr; 190 | } 191 | if (_anony_to_label_pair != nullptr) 192 | { 193 | bdd_freepair(_anony_to_label_pair); 194 | _anony_to_label_pair = nullptr; 195 | } 196 | if (_curr_to_next_block_pair != nullptr) 197 | { 198 | bdd_freepair(_curr_to_next_block_pair); 199 | _curr_to_next_block_pair = nullptr; 200 | } 201 | if (_next_to_curr_block_pair != nullptr) 202 | { 203 | bdd_freepair(_next_to_curr_block_pair); 204 | _next_to_curr_block_pair = nullptr; 205 | } 206 | #ifdef __ORIGINAL__ 207 | if (_state_to_anony_pair != nullptr) 208 | { 209 | bdd_freepair(_state_to_anony_pair); 210 | _state_to_anony_pair = nullptr; 211 | } 212 | 213 | if(_curr_to_next_state_pair != nullptr) 214 | { 215 | bdd_freepair(_curr_to_next_state_pair); 216 | _curr_to_next_state_pair = nullptr; 217 | } 218 | if(_next_to_curr_state_pair != nullptr) 219 | { 220 | bdd_freepair(_next_to_curr_state_pair); 221 | _next_to_curr_state_pair = nullptr; 222 | } 223 | #endif 224 | } 225 | 226 | void 227 | dfwa_min_bdd::output(ostream& os) 228 | { 229 | os << "dfa: " << endl; 230 | os << "init: " << endl; 231 | os << _init << endl; 232 | 233 | os << "trans: " << endl; 234 | os << _trans << endl; 235 | 236 | os << "finals: " << endl; 237 | os << _finals << endl; 238 | } 239 | 240 | // -------------- Symbolic DFA Minimization Algorithms ---------------- 241 | 242 | /*-------------------------------------------------------------------*/ 243 | // create num block variables 244 | /*-------------------------------------------------------------------*/ 245 | 246 | buddy_bdd 247 | dfwa_min_bdd::new_block_number(int block_number, int copy) 248 | { 249 | // now check whether block_number can be represented with current 250 | // number of block variables 251 | //cout << "block_number = " << block_number << endl; 252 | buddy_bdd dd = bddtrue; 253 | int bit = 1; 254 | for (buddy_bdd& bit_var : _block_vars[copy]) 255 | { 256 | buddy_bdd bit_var_not = !bit_var; 257 | dd = dd & ((block_number & bit) != 0 ? bit_var : bit_var_not); 258 | bit <<= 1; 259 | } 260 | //cout << "returned block dd = " << dd << endl; 261 | 262 | return dd; 263 | } 264 | 265 | /*-------------------------------------------------------------------*/ 266 | // traverse BDD structure to compute refined partition 267 | // 1. increase the number of block variables on-the-fly: will need exponential 268 | // more times of BDD traversing 269 | // 2. set to the number of state variables and then remove unessential variables: 270 | // much less times of BDD traversing 271 | /*-------------------------------------------------------------------*/ 272 | buddy_bdd 273 | dfwa_min_bdd::refine_partition_rec(buddy_bdd_ptr dd, unsigned & block_number 274 | , unordered_map &computed_table) 275 | { 276 | int dd_id = dd.id(); 277 | cout << "Compute new partition from sigf(s, a, k) in refine_partition_rec " << endl; 278 | // check whether the node has been visited before 279 | unordered_map::const_iterator it = computed_table.find(dd_id); 280 | if(it != computed_table.end()) 281 | { 282 | return it->second; 283 | } 284 | // false means cannot reach a block 285 | if(dd == bddfalse) 286 | { 287 | return dd; 288 | } 289 | 290 | buddy_bdd result; 291 | const int top_index = bdd_var(dd); 292 | // check whether it is a state variable 293 | if(! is_state_variable(top_index) || dd == bddtrue) 294 | { 295 | // This is a node which representing a block 296 | cout << "block " << block_number << endl; 297 | result = new_block_number(block_number, 0); 298 | ++ block_number; 299 | 300 | // debug info 301 | vector label_block(_label_vars); 302 | label_block.insert(label_block.end(), _block_vars[0].begin(), _block_vars[0].end()); 303 | //generate_all_bits(label_block, 0, dd, _manager->bddOne()); 304 | }else 305 | { 306 | // Traverse the BDD further. 307 | cout << "State variables identified " << endl; 308 | buddy_bdd dd_var = bdd_ithvar(top_index); 309 | buddy_bdd low_cofactor = bdd_low(dd); 310 | buddy_bdd low = refine_partition_rec(low_cofactor, block_number, computed_table); 311 | buddy_bdd high_cofactor = bdd_high(dd); 312 | buddy_bdd high = refine_partition_rec(high_cofactor, block_number, computed_table); 313 | result = bdd_ite(dd_var, high, low); 314 | } 315 | computed_table[dd_id] = result; 316 | return result; 317 | } 318 | 319 | pair 320 | dfwa_min_bdd::refine_partition(buddy_bdd_ptr sig) 321 | { 322 | unsigned int block_number = 0; 323 | unordered_map computed_table; 324 | buddy_bdd partition = refine_partition_rec(sig, block_number, computed_table); 325 | return make_pair<>(partition, block_number); 326 | } 327 | 328 | /*-------------------------------------------------------------------*/ 329 | // permute variables for from and to 330 | // can be improved by outgoing transitions 331 | /*-------------------------------------------------------------------*/ 332 | 333 | /*-------------------------------------------------------------------*/ 334 | // compute next step image of curr 335 | // FIXED (note the returned image contains propositions) 336 | /*-------------------------------------------------------------------*/ 337 | buddy_bdd 338 | dfwa_min_bdd::next_image(buddy_bdd_ptr curr) 339 | { 340 | buddy_bdd next = bdd_relprod(curr, _trans, _curr_cube & _label_cube); 341 | // next to current 342 | #ifdef __ORIGINAL__ 343 | next = bdd_replace(next, _next_to_curr_state_pair); 344 | #else 345 | next = bdd_replace(next, _aut._next_to_curr_pairs); 346 | #endif 347 | return next; 348 | } 349 | 350 | /*-------------------------------------------------------------------*/ 351 | // compute previous image of curr 352 | /*-------------------------------------------------------------------*/ 353 | buddy_bdd 354 | dfwa_min_bdd::pre_image(buddy_bdd_ptr curr) 355 | { 356 | #ifdef __ORIGINAL__ 357 | buddy_bdd next = bdd_replace(curr, _curr_to_next_state_pair); 358 | #else 359 | buddy_bdd next = bdd_replace(curr, _aut._curr_to_next_pairs); 360 | #endif 361 | // and exist 362 | buddy_bdd pre = bdd_relprod(next, _trans, _next_cube & _label_cube); 363 | return pre; 364 | } 365 | /*-------------------------------------------------------------------*/ 366 | // compute reachable state space 367 | /*-------------------------------------------------------------------*/ 368 | buddy_bdd 369 | dfwa_min_bdd::forward_explore() 370 | { 371 | clock_t c_start = clock(); 372 | buddy_bdd s = _init; 373 | buddy_bdd sp = bddfalse; 374 | unsigned count = 1; 375 | while(sp != s) 376 | { 377 | cout << "Iteration number = " << count << endl; 378 | // record the states reached within last step 379 | sp = s; 380 | // compute image of next step 381 | #ifdef DEBUG 382 | 383 | cout << "reachable states in product: " << endl; 384 | bdd_print_set(cout, _state_vars.get_dict(), sp); 385 | cout << endl; 386 | #endif 387 | s = sp | next_image(sp); 388 | ++ count; 389 | } 390 | clock_t c_end = clock(); 391 | cout << "Finished forward exploration in " << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"; 392 | return s; 393 | } 394 | 395 | buddy_bdd 396 | dfwa_min_bdd::backward_explore() 397 | { 398 | clock_t c_start = clock(); 399 | buddy_bdd s = _finals; 400 | buddy_bdd sp = bddfalse; 401 | unsigned count = 1; 402 | while(sp != s) 403 | { 404 | cout << "Iteration number = " << count << endl; 405 | // record the states reached within last step 406 | sp = s; 407 | // compute image of next step 408 | #ifdef DEBUG 409 | cout << "reachable states in product: " << endl; 410 | bdd_print_set(cout, _state_vars.get_dict(), sp); 411 | cout << endl; 412 | #endif 413 | s = sp | pre_image(sp); 414 | ++ count; 415 | } 416 | clock_t c_end = clock(); 417 | cout << "Finished backward exploration in " << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"; 418 | return s; 419 | } 420 | 421 | buddy_bdd 422 | dfwa_min_bdd::initialize_partition() 423 | { 424 | 425 | clock_t c_start = clock(); 426 | buddy_bdd reach = forward_explore(); 427 | reach = reach & backward_explore(); 428 | clock_t c_end = clock(); 429 | cout << "Finished buddy exploration in " << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"; 430 | 431 | // buddy is a bit fast than cudd. Not sure whether it is due to the encoding or 432 | // that buddy is just faster than cudd 433 | #ifdef DEBUG 434 | c_start = clock(); 435 | buddy_bdd b_reach = _aut.explore(); 436 | b_reach = b_reach & _aut.back_explore(); 437 | c_end = clock(); 438 | cout << "Finished buddy exploration in " << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"; 439 | #endif 440 | 441 | cout << "reachable non-final states: " << endl; 442 | buddy_bdd non_finals = (! _finals) & reach; 443 | //vector curr_states(_state_vars[0]); 444 | //generate_all_bits(curr_states, 0, non_finals, _manager->bddOne()); 445 | // get block variables 446 | buddy_bdd block_0 = new_block_number(0, 0); 447 | // careful about nonreachable states 448 | buddy_bdd block_1 = new_block_number(1, 0); 449 | buddy_bdd partition = (block_0 & _finals & reach) | (block_1 & non_finals); 450 | // debug info 451 | cout << "Initial partition: " << endl; 452 | //curr_states.insert(curr_states.end(), _block_vars[0].begin(), _block_vars[0].end()); 453 | //generate_all_bits(curr_states, 0, partition, _manager->bddOne()); 454 | // check whether we need to add sink transitions 455 | // s <-> s' 456 | //buddy_bdd nonreach = ! cudd_reach; 457 | #ifdef __ORIGINAL__ 458 | buddy_bdd next_reach = bdd_replace(reach, _curr_to_next_state_pair); 459 | #else 460 | buddy_bdd next_reach = bdd_replace(reach, _aut._curr_to_next_pairs); 461 | #endif 462 | _trans = _trans & reach & next_reach; 463 | return partition; 464 | } 465 | 466 | 467 | /*-------------------------------------------------------------------*/ 468 | // symbolic DFA minimization 469 | /*-------------------------------------------------------------------*/ 470 | void 471 | dfwa_min_bdd::minimize() 472 | { 473 | clock_t c_start = clock(); 474 | cout << "Starting DFA minimization..." << endl; 475 | // sigref based minimization for algorithms 476 | // 1. P(X, K) is the initial partition of states 477 | buddy_bdd partition = initialize_partition(); 478 | unsigned prev_block_number = 2; 479 | unsigned iteration_num = 0; 480 | 481 | while(true) 482 | { 483 | clock_t iter_start = clock(); 484 | ++ iteration_num; 485 | cout << "The number of blocks at iteration " << iteration_num << " is " << prev_block_number << endl; 486 | // compute the signature sigf(s, a, k) = exists X'. T(X, A, X') and P(X', K) 487 | // first P(X, K) => P(X', K) 488 | cout << "Permute P(X, K) => P(X', K) " << endl; 489 | #ifdef __ORIGINAL__ 490 | buddy_bdd state_next_partition = bdd_replace(partition, _curr_to_next_state_pair); 491 | #else 492 | buddy_bdd state_next_partition = bdd_replace(partition, _aut._curr_to_next_pairs); 493 | #endif 494 | // sigf(s, a, k) = exists X'. T(X, A, X') and P(X', K) 495 | cout << "Compute sigf(s, a, k) = exists X'. T(X, A, X') and P(X', K) " << endl; 496 | buddy_bdd sigf = bdd_relprod(state_next_partition, _trans, _next_cube); 497 | 498 | cout << "Permute P(X, K) => P(X, K') " << endl; 499 | buddy_bdd block_next_partition = bdd_replace(partition, _curr_to_next_block_pair); 500 | cout << "sigf(s, a, k) = sigf(s, a, k) & P(s, k')" << endl; 501 | cout << "#sigf = " << bdd_nodecount(sigf) << " #p = " << bdd_nodecount(block_next_partition) << endl; 502 | sigf = sigf & block_next_partition; 503 | //sigf(s, a, k) [X, A, K] 504 | //vector new_state_label_block_1(_state_vars[0]); 505 | //new_state_label_block_1.insert(new_state_label_block_1.end(), _label_vars.begin(), _label_vars.end()); 506 | //new_state_label_block_1.insert(new_state_label_block_1.end(), _block_vars[0].begin(), _block_vars[0].end()); 507 | //generate_all_bits(new_state_label_block_1, 0, sigf, _manager->bddOne()); 508 | // refine the partition, traverse the BDD to compute block numbers 509 | cout << "Compute new partition from sigf(s, a, k) " << endl; 510 | //print(sigf); 511 | pair result = refine_partition(sigf); 512 | unsigned curr_block_number = result.second; 513 | // if the number of blocks is not changed, then get out of the loop 514 | clock_t iter_end = clock(); 515 | cout << "Finished iteration "<< iteration_num << " in " << 1000.0 * (iter_end - iter_start) / CLOCKS_PER_SEC << " ms\n"; 516 | if(prev_block_number == curr_block_number) 517 | { 518 | break; 519 | } 520 | prev_block_number = curr_block_number; 521 | // set refined partition 522 | partition = result.first; 523 | // debug info 524 | //cout << "refined partition: " << endl << partition << endl; 525 | //vector new_state_label_block(_state_vars[0]); 526 | //new_state_label_block.insert(new_state_label_block.end(), _block_vars[0].begin(), _block_vars[0].end()); 527 | //generate_all_bits(new_state_label_block, 0, partition, _manager->bddOne()); 528 | } 529 | 530 | _num_min_states = prev_block_number; 531 | cout << "Finished DFA minimization after "<< iteration_num 532 | << " iterations. The number of states in minimal DFA is " << _num_min_states << endl; 533 | // construct new dfa 534 | // determine whether we can remove some variables 535 | reduce_block_variables(partition); 536 | 537 | cout << "minimized dfa: " << endl; 538 | for(unsigned i = 0; i < _block_vars.size(); i ++) 539 | { 540 | for(unsigned j = 0; j < _block_vars[i].size(); j ++) 541 | { 542 | cout << "var_" << i << " " << _block_vars[i][j] << endl; 543 | } 544 | } 545 | 546 | //cout << "label cube = " << _label_cube << endl; 547 | cout << "init: " << endl; 548 | //cout << "before: " << _init << endl; 549 | cout << "_curr_cube =" << _curr_cube << endl; 550 | // I(K) = exists X. I(X) and P(X, K) 551 | _init = bdd_relprod(_init, partition, _curr_cube); 552 | // cout << "after: " << _init << endl; 553 | 554 | cout << "finals: " << endl; 555 | // F(K) = exists X. F(X) and P(X, K) 556 | //cout << "before: " << _finals << endl; 557 | //cout << "and: " << (_finals & partition) << endl; 558 | _finals = bdd_relprod(_finals, partition, _curr_cube); 559 | //cout << "after: " << _finals << endl; 560 | 561 | cout << "trans: " << endl; 562 | // P(X', K') 563 | //vector curr_states(_state_vars[0]); 564 | //curr_states.insert(curr_states.end(), _block_vars[0].begin(), _block_vars[0].end()); 565 | //vector next_states(_state_vars[1]); 566 | //next_states.insert(next_states.end(), _block_vars[1].begin(), _block_vars[1].end()); 567 | 568 | cout << "P(X, K) => P(X', K')" << endl; 569 | #ifdef __ORIGINAL__ 570 | bddPair* curr_to_next = bdd_mergepairs(_curr_to_next_state_pair, _curr_to_next_block_pair); 571 | buddy_bdd next_partition = bdd_replace(partition, curr_to_next); 572 | #else 573 | bddPair* curr_to_next = bdd_mergepairs(_aut._curr_to_next_pairs, _curr_to_next_block_pair); 574 | buddy_bdd next_partition = bdd_replace(partition, curr_to_next); 575 | #endif 576 | bdd_freepair(curr_to_next); 577 | cout << "Computing the transition relation for minimal DFA..." << endl; 578 | clock_t t_start = clock(); 579 | 580 | // R(s, a, k') := (∃t : T (s, a, t) ∧ P(t, k')) 581 | cout << "R(s, a, k') := ∃t : T (s, a, t) ∧ P(t, k')" << endl; 582 | cout << "#nodes in partition: " << bdd_nodecount(partition) << endl; 583 | cout << "#nodes in trans: " << bdd_nodecount(_trans) << endl; 584 | 585 | buddy_bdd minimized_trans = bdd_relprod(_trans, next_partition, _next_cube); 586 | // T P (s, a, t') := (∃s : R(s, a, k') ∧ P(s, k)) 587 | cout << "T(k, a, k') := ∃s :R(s, a, k') ∧ P(s, k)" << endl; 588 | minimized_trans = bdd_relprod(minimized_trans, partition, _curr_cube); 589 | //cout << minimized_trans << endl; 590 | /* 591 | buddy_bdd minimized_trans = make_quotient_trans(_trans, partition, next_partition); 592 | */ 593 | clock_t t_end = clock(); 594 | cout << "Finished transition relation computation in " << 1000.0 * (t_end - t_start) / CLOCKS_PER_SEC << " ms\n"; 595 | cout << "Output Transitions" << endl; 596 | //vector label_block(_label_vars); 597 | //label_block.insert(label_block.end(), _block_vars[0].begin(), _block_vars[0].end()); 598 | //label_block.insert(label_block.end(), _block_vars[1].begin(), _block_vars[1].end()); 599 | //generate_all_bits(label_block, 0, minimized_trans, _manager->bddOne()); 600 | cout << "The number of nodes in minimal transitions" << bdd_nodecount(minimized_trans) << endl; 601 | _trans = minimized_trans; 602 | cout << endl; 603 | clock_t c_end = clock(); 604 | 605 | cout << "Finished DFA minimization in " << 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC << " ms\n"; 606 | } 607 | 608 | /*-------------------------------------------------------------------*/ 609 | // reduce the number of block variables as much as possible 610 | /*-------------------------------------------------------------------*/ 611 | void 612 | dfwa_min_bdd::reduce_block_variables(buddy_bdd_ptr partition) 613 | { 614 | // determine whether we can remove some variables 615 | cout << "Reduced block variables..." << endl; 616 | unsigned num = 0; 617 | while(true) 618 | { 619 | buddy_bdd var_dd = _block_vars[0].back(); 620 | buddy_bdd result = (! var_dd) & partition; 621 | if(result != partition || _block_vars[0].size() < 2) 622 | { 623 | break; 624 | } 625 | ++ num; 626 | _block_vars[0].pop_back(); 627 | cout << "number of vars: " << _aut._state_vars.get_var_num(0) << endl 628 | << "block[0].size() = " << _block_vars[0].size() << endl 629 | << "block[1].size() = " << _block_vars[1].size() << endl; 630 | _block_vars[1].pop_back(); 631 | // remove redundant variables 632 | partition = bdd_exist(partition, var_dd); 633 | } 634 | cout << "Finished reducing " << num << " block variables..." << endl; 635 | } 636 | 637 | /*-------------------------------------------------------------------*/ 638 | // move the minimal DFA from CUDD to BuDDy 639 | // the ordering of dfa is (A, X, X') 640 | /*-------------------------------------------------------------------*/ 641 | dfwa_ptr 642 | dfwa_min_bdd::move_dfwa() 643 | { 644 | cout << "labels in previous dfa: " << _aut._label_cube << endl; 645 | bdd_print_set(cout, _aut.get_dict(), _aut._label_cube); 646 | cout << endl; 647 | dfwa* result = new dfwa(_aut.get_dict(), _aut._label_cube); 648 | cout << "labels in minimal dfa: " << endl; 649 | bdd_print_set(cout, result->get_dict(), result->_label_cube); 650 | cout << endl; 651 | //mapping block variables back to buddy variables 652 | unordered_map cudd_to_buddy_map; 653 | // K -> S -> BUDDY 654 | //vector block_vars; 655 | result->_state_vars._copies = 2; 656 | // now we add variables from op1 and op2 657 | cout << "Moving minimal DFA to BuDDy..." << endl; 658 | // check whether this part can be improved 659 | 660 | // compute mapping for state variables 661 | // needs to reuse the variables in _aut and the ordering of variables 662 | // should be increasing to get a better performance 663 | result->_state_vars.add_ordered_bdd_vars(_aut._state_vars); 664 | assert(result->_state_vars._dd_vars[0].size() >= _block_vars[0].size()); 665 | cout << "Now remove useless variables" << endl; 666 | int pop_num = result->_state_vars.get_bdd_vars(0).size() - _block_vars[0].size(); 667 | while(pop_num > 0) 668 | { 669 | result->_state_vars.pop_back_vars(); 670 | -- pop_num; 671 | } 672 | bddPair* block_to_states_pair = bdd_newpair(); 673 | //_map.clear(); 674 | for(unsigned i = 0; i < _block_vars[0].size(); i ++) 675 | { 676 | // current version of state variables 677 | int index = bdd_var(_block_vars[0][i]); 678 | int result_index = bdd_var(result->_state_vars.get_var(0, i)); 679 | bdd_setpair(block_to_states_pair, index, result_index); 680 | //_map[index] = result_index; 681 | //cout << "map: " << index << " -> " << bdd_var(result->_state_vars.get_var(0, i)) << endl; 682 | //curr_state_vars.push_back(bdd_ithvar(buddy_index)); 683 | //++ num; 684 | // next version of state variables 685 | index = bdd_var(_block_vars[1][i]); 686 | //buddy_index = _cudd_to_buddy_vars[num]; 687 | result_index = bdd_var(result->_state_vars.get_var(1, i)); 688 | //_map[index] = result_index; 689 | bdd_setpair(block_to_states_pair, index, result_index); 690 | } 691 | //vector> state_vars; 692 | //state_vars.push_back(curr_state_vars); 693 | //state_vars.push_back(next_state_vars); 694 | //result._state_vars.add_bdd_vars(curr_state_vars); 695 | //result._state_vars.add_bdd_vars(next_state_vars); 696 | // compute mapping for labels 697 | bddPair* result_pair = bdd_mergepairs(block_to_states_pair, _anony_to_label_pair); 698 | cout << "Migrating dfa representation from CUDD to BuDDy..." << endl; 699 | clock_t c_start = clock(); 700 | //cout << "cudd init: " << _init << endl; 701 | // compute the initial states 702 | result->_init = bdd_replace(_init, block_to_states_pair); 703 | //cout << "buddy init: " << result->_init << endl; 704 | //cout << "cudd _finals: " << _finals << endl; 705 | result->_finals = bdd_replace(_finals, block_to_states_pair); 706 | //cout << "buddy finals: " << result->_finals << endl; 707 | cout << "The number of nodes in minimal transition is " << bdd_nodecount(_trans) << endl; 708 | //_map.insert(_anony_to_label.begin(), _anony_to_label.end()); 709 | 710 | result->_trans = bdd_replace(_trans, result_pair); 711 | //result->_trans = move_to(_trans); 712 | //cout << "buddy trans: " << result->_trans << endl; 713 | clock_t c_end = clock(); 714 | cout << "Finished migrating dfa representation in " 715 | << 1000.0 * (c_end - c_start)/CLOCKS_PER_SEC << "ms ..." << endl; 716 | 717 | result->_curr_cube = result->_state_vars.get_cube(0); 718 | result->_next_cube = result->_state_vars.get_cube(1); 719 | // make pairs 720 | 721 | result->_curr_to_next_pairs = result->_state_vars.make_pair(0, 1); 722 | result->_next_to_curr_pairs = result->_state_vars.make_pair(1, 0); 723 | result->_reach = bddtrue;//result.explore(); 724 | cout << "Finished computing dfa representation in BuDDy..." << endl; 725 | 726 | bdd_freepair(block_to_states_pair); 727 | bdd_freepair(result_pair); 728 | /* 729 | cout << "is_even(8) = " << is_even(8) << endl; 730 | cout << "is_even(9) = " << is_even(9) << endl; 731 | cout << "is_even(0) = " << is_even(0) << endl; 732 | cout << "is_even(1) = " << is_even(1) << endl; 733 | */ 734 | return *result; 735 | } 736 | 737 | // ------------------ printing functions ------------------------------ 738 | 739 | void 740 | dfwa_min_bdd::print(buddy_bdd bdd) 741 | { 742 | cout << "formula : " << bdd << endl; 743 | } 744 | 745 | /*-------------------------------------------------------------------*/ 746 | // generate all possible truth values of a vector of variables 747 | /*-------------------------------------------------------------------*/ 748 | void 749 | dfwa_min_bdd::generate_all_bits(vector& vars, unsigned index, buddy_bdd_ptr dd, buddy_bdd temp) 750 | { 751 | #ifdef DEBUG 752 | if (index == vars.size()) 753 | { 754 | buddy_bdd inter = temp & dd; 755 | if(! inter.IsZero()) 756 | { 757 | cout << "SAT: "; 758 | for(unsigned i = 0; i < vars.size(); i ++) 759 | { 760 | inter = temp & vars[i]; 761 | if(inter.IsZero()) 762 | { 763 | cout << " !"; 764 | }else 765 | { 766 | cout << " "; 767 | } 768 | cout << vars[i] ; 769 | } 770 | cout << endl; 771 | } 772 | return; 773 | } 774 | // true 775 | generate_all_bits(vars, index + 1, dd, temp & vars[index]); 776 | // false 777 | generate_all_bits(vars, index + 1, dd, temp & (!vars[index])); 778 | #endif 779 | } 780 | --------------------------------------------------------------------------------