From e034e268f984394e84f350a83efc327b448eaa9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorsten=20Wi=C3=9Fmann?= <uni@thorsten-wissmann.de> Date: Sat, 25 Jan 2014 00:03:52 +0100 Subject: [PATCH] Add GMLMIP-0.1 tool --- GMLMIP-0.1/README.txt | 79 ++++++ GMLMIP-0.1/clean.sh | 15 + GMLMIP-0.1/compile.sh | 15 + GMLMIP-0.1/formulas/GML_formula.cpp | 80 ++++++ GMLMIP-0.1/formulas/GML_formula.h | 14 + GMLMIP-0.1/formulas/PML_formula.cpp | 102 +++++++ GMLMIP-0.1/formulas/PML_formula.h | 14 + GMLMIP-0.1/formulas/formula.cpp | 284 +++++++++++++++++++ GMLMIP-0.1/formulas/formula.h | 159 +++++++++++ GMLMIP-0.1/formulas/makefile | 22 ++ GMLMIP-0.1/formulas/rational.cpp | 29 ++ GMLMIP-0.1/formulas/rational.h | 26 ++ GMLMIP-0.1/formulas/satisfyingassignment.cpp | 64 +++++ GMLMIP-0.1/formulas/satisfyingassignment.h | 26 ++ GMLMIP-0.1/input | 2 + GMLMIP-0.1/main.cpp | 70 +++++ GMLMIP-0.1/makefile | 15 + GMLMIP-0.1/parser/makefile | 34 +++ GMLMIP-0.1/parser/mlf-driver.cpp | 60 ++++ GMLMIP-0.1/parser/mlf-driver.h | 62 ++++ GMLMIP-0.1/parser/mlf-parser.yy | 111 ++++++++ GMLMIP-0.1/parser/mlf-scanner.ll | 124 ++++++++ GMLMIP-0.1/parser/test.cpp | 16 ++ GMLMIP-0.1/rand.pl | 98 +++++++ GMLMIP-0.1/rules/GML_premise.cpp | 251 ++++++++++++++++ GMLMIP-0.1/rules/GML_premise.h | 33 +++ GMLMIP-0.1/rules/PML_premise.cpp | 17 ++ GMLMIP-0.1/rules/PML_premise.h | 26 ++ GMLMIP-0.1/rules/makefile | 34 +++ GMLMIP-0.1/rules/node.cpp | 46 +++ GMLMIP-0.1/rules/node.h | 34 +++ GMLMIP-0.1/rules/premise.cpp | 110 +++++++ GMLMIP-0.1/rules/premise.h | 76 +++++ GMLMIP-0.1/rules/radixtree.cpp | 55 ++++ GMLMIP-0.1/rules/radixtree.h | 36 +++ GMLMIP-0.1/rules/setofconclusions.cpp | 35 +++ GMLMIP-0.1/rules/setofconclusions.h | 38 +++ GMLMIP-0.1/rules/sizefunctions.cpp | 26 ++ GMLMIP-0.1/rules/sizefunctions.h | 11 + GMLMIP-0.1/rules/test.cpp | 60 ++++ GMLMIP-0.1/rules/valuation.cpp | 71 +++++ GMLMIP-0.1/rules/valuation.h | 34 +++ GMLMIP-0.1/satisfyingstack.h | 12 + GMLMIP-0.1/timeoutwrapper.sh | 91 ++++++ INSTALL | 8 +- 45 files changed, 2624 insertions(+), 1 deletion(-) create mode 100644 GMLMIP-0.1/README.txt create mode 100755 GMLMIP-0.1/clean.sh create mode 100755 GMLMIP-0.1/compile.sh create mode 100644 GMLMIP-0.1/formulas/GML_formula.cpp create mode 100644 GMLMIP-0.1/formulas/GML_formula.h create mode 100644 GMLMIP-0.1/formulas/PML_formula.cpp create mode 100644 GMLMIP-0.1/formulas/PML_formula.h create mode 100644 GMLMIP-0.1/formulas/formula.cpp create mode 100644 GMLMIP-0.1/formulas/formula.h create mode 100644 GMLMIP-0.1/formulas/makefile create mode 100644 GMLMIP-0.1/formulas/rational.cpp create mode 100644 GMLMIP-0.1/formulas/rational.h create mode 100644 GMLMIP-0.1/formulas/satisfyingassignment.cpp create mode 100644 GMLMIP-0.1/formulas/satisfyingassignment.h create mode 100644 GMLMIP-0.1/input create mode 100644 GMLMIP-0.1/main.cpp create mode 100644 GMLMIP-0.1/makefile create mode 100644 GMLMIP-0.1/parser/makefile create mode 100644 GMLMIP-0.1/parser/mlf-driver.cpp create mode 100644 GMLMIP-0.1/parser/mlf-driver.h create mode 100644 GMLMIP-0.1/parser/mlf-parser.yy create mode 100644 GMLMIP-0.1/parser/mlf-scanner.ll create mode 100644 GMLMIP-0.1/parser/test.cpp create mode 100644 GMLMIP-0.1/rand.pl create mode 100644 GMLMIP-0.1/rules/GML_premise.cpp create mode 100644 GMLMIP-0.1/rules/GML_premise.h create mode 100644 GMLMIP-0.1/rules/PML_premise.cpp create mode 100644 GMLMIP-0.1/rules/PML_premise.h create mode 100644 GMLMIP-0.1/rules/makefile create mode 100644 GMLMIP-0.1/rules/node.cpp create mode 100644 GMLMIP-0.1/rules/node.h create mode 100644 GMLMIP-0.1/rules/premise.cpp create mode 100644 GMLMIP-0.1/rules/premise.h create mode 100644 GMLMIP-0.1/rules/radixtree.cpp create mode 100644 GMLMIP-0.1/rules/radixtree.h create mode 100644 GMLMIP-0.1/rules/setofconclusions.cpp create mode 100644 GMLMIP-0.1/rules/setofconclusions.h create mode 100644 GMLMIP-0.1/rules/sizefunctions.cpp create mode 100644 GMLMIP-0.1/rules/sizefunctions.h create mode 100644 GMLMIP-0.1/rules/test.cpp create mode 100644 GMLMIP-0.1/rules/valuation.cpp create mode 100644 GMLMIP-0.1/rules/valuation.h create mode 100644 GMLMIP-0.1/satisfyingstack.h create mode 100755 GMLMIP-0.1/timeoutwrapper.sh diff --git a/GMLMIP-0.1/README.txt b/GMLMIP-0.1/README.txt new file mode 100644 index 0000000..f31b51f --- /dev/null +++ b/GMLMIP-0.1/README.txt @@ -0,0 +1,79 @@ +=============================== +Author: William Snell +Check http://project.williamsnell.co.uk for future updates. +================================ + +Requirements: + +GNU LPK, Flex, Bison, Googlesparsehash package, BuDDy BDD package. + +(Extensively tested with GNU-LPK 4.38) + +================================= +Compiling: + +To compile you will need to edit the makefiles in the sub-folders and this folder to point to the location of your compiler/bison/flex. + +Also need to edit the include directory and linking directories in all 4 make files to point to where you have installed GLPK, sparsehash and BuDDy. If you install these properly in /bin /usr (unlike the lab set-up) you should be able to just remove these parts and have it compile fine. + +Then if you run the compile.sh script, everything should compile properly for you. + +================================= +Usage: + +Input is written in a separate file and then this file is is passed as an argument on the command line. + +./main input + +You can use the -v flag for output. At each step of the top level tableau calculus algorithm it tells you how many satisfying assignments and how many rules it has found. + +Included is Dmitry V Golovashkin's timeout script. The following would run the program on the input file with a timeout of 300 seconds. + +./timeoutwrapper.sh -t 300 ./src/main input + + +================================= +Input file specification: + +First we specify which logic then use the following notation: + +<a> GML diamond ('more than a successors ...') +[a] GML box ('fails at most a times ...') +<a/b> PML diamond +[a/b] PML box +~ not +v or +& and +( +) + +Examples: + +Logic:PML +<1/2>p0 & ~<1/4>p2 v [1/8]p3 + +Logic:GML +<1>p0 & <1>(p0 v p0) + + +================================= +Known Issues & Notes: + +1) The following warning is generated by the C code generated by flex. + position.hh:136: warning: suggest parentheses around ‘&&’ within ‘||’ + +2) Use of deprecated header <ext/hash_map>. + +3) You may need to alter the line "using __gnu_cxx::hash;" line in formula.h depending on your compiler. + +4) I received "./main: error while loading shared libraries: libbdd.so.0: cannot open shared object file: No such file or directory" errors. +Fixed by adding "export LD_LIBRARY_PATH=~/lib/lib:$LD_LIBRARY_PATH" to my .bashrc file. Where ~/lib/lib is where I locally installed the required libraries. (No root access for lab machines.) + +5) If you receive error "BDD error: unknown variable" you have not declared enough variables in the BDD initialisation in main.cpp. The line "bdd_setvarnum(int)" needs increasing. + +6) What report describes as TruthAssignment class is implemented as Valuation. + + + + + diff --git a/GMLMIP-0.1/clean.sh b/GMLMIP-0.1/clean.sh new file mode 100755 index 0000000..567d321 --- /dev/null +++ b/GMLMIP-0.1/clean.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +cd ./parser/ +make clean +cd .. + +cd ./formulas/ +make clean +cd .. + +cd ./rules/ +make clean +cd .. + +make clean diff --git a/GMLMIP-0.1/compile.sh b/GMLMIP-0.1/compile.sh new file mode 100755 index 0000000..f205a8b --- /dev/null +++ b/GMLMIP-0.1/compile.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +cd ./parser/ +make all +cd .. + +cd ./formulas/ +make all +cd .. + +cd ./rules/ +make all +cd .. + +make diff --git a/GMLMIP-0.1/formulas/GML_formula.cpp b/GMLMIP-0.1/formulas/GML_formula.cpp new file mode 100644 index 0000000..1fc45b4 --- /dev/null +++ b/GMLMIP-0.1/formulas/GML_formula.cpp @@ -0,0 +1,80 @@ +#include "GML_formula.h" + +bdd GML_Formula::modal(bdd *b, int n, int m){ + return modal_var(b, n); +} + +void GML_Formula::load_linear_program(glp_prob* problem, Premise<int>& prem){ + int n = prem.get_n(); + int m = prem.get_m(); + int no_of_valuations = prem.get_total_valuations(); + + //glp_set_obj_dir(sc, GLP_MIN); + glp_add_rows(problem, no_of_valuations+1); + glp_add_cols(problem, n+m); + + for(int i = 1; i < no_of_valuations+1; i++) + glp_set_row_bnds(problem, i, GLP_UP, 0.0, 0.0); // <= 0 + + // Set row bounds for side condition + glp_set_row_bnds(problem, no_of_valuations+1, GLP_LO, 1.0, 0.0); // >= 1 + + for(int i=1; i < (n+m+1); i++){ + glp_set_col_kind(problem, i, GLP_IV); //integer variables + glp_set_col_bnds(problem, i, GLP_LO, 0, 0); // r_i, s_i >= 0 + } + + // Arrays for inputting into glpk + const int size = (no_of_valuations+1)*(n+m); + double ar[size+1]; + int ia[size+1]; + int ja[size+1]; + + // Recall GLKP takes arrays with 1 - size not 0 - size-1. + for(int i=0; i < size; i++){ + ia[i+1] = (i / (n+m)) + 1; + ja[i+1] = (i % (n+m)) + 1; + } + + int counter=1; + + // Load all valuations + for(int i=0; i < no_of_valuations; i++){ + int temp = i; + for(int j=0; j < n; j++){ + ar[counter] = temp & 1; + temp >>= 1; + counter++; + } + for(int j=0; j < m; j++){ + ar[counter] = -(temp & 1); + temp >>= 1; + counter++; + } + } + + // Load side condition at the bottom + for(int i=0; i < n; i++){ + ar[counter]= prem.get_a_i(i)+1; + counter++; + } + + for(int j=0; j < m; j++){ + ar[counter]= -(prem.get_b_i(j)); + counter++; + } + + /* + for(int i=1; i < size+1; i++) + cout << ia[i] << " "; + cout << endl; + for(int i=1; i < size+1; i++) + cout << ja[i] << " "; + cout << endl << endl; + for(int i=1; i < size+1; i++) + cout << ar[i] << " "; + cout << endl; + */ + + glp_load_matrix(problem, size, ia, ja, ar); +} diff --git a/GMLMIP-0.1/formulas/GML_formula.h b/GMLMIP-0.1/formulas/GML_formula.h new file mode 100644 index 0000000..a24a13b --- /dev/null +++ b/GMLMIP-0.1/formulas/GML_formula.h @@ -0,0 +1,14 @@ +#ifndef GML_FORMULA_HH +#define GML_FORMULA_HH + +#include "formula.h" + +class GML_Formula : public Formula<int> { + private: + void load_linear_program(glp_prob* problem, Premise<int>& prem); + + public: + bdd modal(bdd *b, int n, int m); + +}; +#endif diff --git a/GMLMIP-0.1/formulas/PML_formula.cpp b/GMLMIP-0.1/formulas/PML_formula.cpp new file mode 100644 index 0000000..c4c04ab --- /dev/null +++ b/GMLMIP-0.1/formulas/PML_formula.cpp @@ -0,0 +1,102 @@ +#include "PML_formula.h" + +bdd PML_Formula::modal(bdd *b, int n, int m){ + if(n > m){ + cout << "error: " << n << "/" << m << " is not in [0,1]" << endl; + exit(1); + } + Rational r(n,m); + return modal_var(b, r); +} + + +void PML_Formula::load_linear_program(glp_prob* problem, Premise<Rational>& prem) { + int n = prem.get_n(); + int m = prem.get_m(); + int no_of_valuations = prem.get_total_valuations(); + + // Additional 2 for side condition and requirements that at least one r_i,s_j is non zero + glp_add_rows(problem, no_of_valuations+2); + + // Additional column for k + glp_add_cols(problem, n+m+1); + + for(int i = 1; i < no_of_valuations+1; i++) + glp_set_row_bnds(problem, i, GLP_UP, 0.0, 0.0); // <= 0 + + // Set row bounds for side condition - recall we have -k in the extra column. + if(m==0) + glp_set_row_bnds(problem, no_of_valuations+1, GLP_LO, 1.0, 0.0); // >= 1 + else + glp_set_row_bnds(problem, no_of_valuations+1, GLP_LO, 0.0, 0.0); // >= 0 + + // Set row bounds for additional constraint + glp_set_row_bnds(problem, no_of_valuations+2, GLP_LO, 1.0, 0.0); // >= 1 + + // Set variable bounds + for(int i=1; i < (n+m+1); i++){ + glp_set_col_kind(problem, i, GLP_IV); //integer variables + glp_set_col_bnds(problem, i, GLP_LO, 0, 0); // r_i, s_i >= 0 + } + + // K is positive integer + glp_set_col_kind(problem, n+m+1, GLP_IV); //integer k + glp_set_col_bnds(problem, n+m+1, GLP_LO, 1.0, 0.0); // k >= 1 + + + // Arrays for inputting into glpk + const int size = (no_of_valuations+2)*(n+m+1); + double ar[size+1]; + int ia[size+1]; + int ja[size+1]; + + // Recall GLKP takes arrays with 1 - size not 0 - size-1. + for(int i=0; i < size; i++){ + ia[i+1] = (i / (n+m+1)) + 1; + ja[i+1] = (i % (n+m+1)) + 1; + } + + int counter=1; + + // Load all valuations + for(int i=0; i < no_of_valuations; i++){ + int temp = i; + for(int j=0; j < n; j++){ + ar[counter] = temp & 1; + temp >>= 1; + counter++; + } + for(int j=0; j < m; j++){ + ar[counter] = -(temp & 1); + temp >>= 1; + counter++; + } + ar[counter] = -1; // - k on each valuation. + counter++; + } + + // Load side condition + for(int i=0; i < n; i++){ + ar[counter] = prem.get_a_i(i).get(); + counter++; + } + + for(int j=0; j < m; j++){ + ar[counter]= -(prem.get_b_i(j).get()); + counter++; + } + //side condition has coefficent k of -1 + ar[counter] = -1; + counter++; + + //Finally load condition that one must be nonzero. + for(int i=0; i < n+m; i++){ + ar[counter] = 1; + counter++; + } + // k coefficient here is zero + ar[counter] = 0; + + glp_load_matrix(problem, size, ia, ja, ar); + //glp_write_lp(problem, NULL, "testy.txt"); +} diff --git a/GMLMIP-0.1/formulas/PML_formula.h b/GMLMIP-0.1/formulas/PML_formula.h new file mode 100644 index 0000000..8e04b3f --- /dev/null +++ b/GMLMIP-0.1/formulas/PML_formula.h @@ -0,0 +1,14 @@ +#ifndef PML_FORMULA_HH +#define PML_FORMULA_HH + +#include "formula.h" + +class PML_Formula : public Formula<Rational> { + private: + void load_linear_program(glp_prob* problem, Premise<Rational>& prem); + + public: + bdd modal(bdd *b, int n, int m); + +}; +#endif diff --git a/GMLMIP-0.1/formulas/formula.cpp b/GMLMIP-0.1/formulas/formula.cpp new file mode 100644 index 0000000..0a9ef1e --- /dev/null +++ b/GMLMIP-0.1/formulas/formula.cpp @@ -0,0 +1,284 @@ +#include "formula.h" + +template<class ModalValueType> +Formula<ModalValueType>::Formula(){ + number_of_variables = 0; + variables.set_empty_key(-1); // + variables_back.set_empty_key(-1); // + data d; + modal_variables.set_empty_key(d); + modal_variables_back.set_empty_key(-1); // + Premise<ModalValueType> p; + rule_cache.set_empty_key(p); +} + +template<class ModalValueType> +bdd Formula<ModalValueType>::variable(int n){ + if(variables.count(n) == 0){ + variables[n] = number_of_variables; + variables_back[number_of_variables] = n; + number_of_variables++; + } + return bdd_ithvarpp(variables[n]); +} + +template<class ModalValueType> +bdd Formula<ModalValueType>::modal_var(bdd *b, ModalValueType &n){ + data d(n, b); + if(modal_variables.count(d) == 0){ + modal_variables[d] = number_of_variables; + modal_variables_back[number_of_variables] = d; + number_of_variables++; + } + return bdd_ithvarpp(modal_variables[d]); +} + + +template<class ModalValueType> +void Formula<ModalValueType>::print_back_vars(){ + cout << setw(10) << "BDD number " << setw(10) << "Input Number" << endl; + for(int i=0; i < 1000; i++) + if(variables_back.count(i) > 0 ) + cout << setw(10) << i << setw(10) << variables_back[i] << endl; + cout << endl; +} + +void sat_handler(char *varset, int size){ + SatisfyingAssignment s(size, varset); + sat_ass_stack.push_back(s); +} + +template<class ModalValueType> +bool Formula<ModalValueType>::check_satisfiability(bdd b){ + bool sat = false; // handle the case of no satisfying assignments. + //bdd_printdot(b); + bdd_allsat(b, sat_handler); // pushes satisfying assignment onto stack + vector<SatisfyingAssignment> sat_ass = sat_ass_stack; + sat_ass_stack.clear(); + for(unsigned int i=0; i < sat_ass.size() && !sat; i++){ // we break if proved sat + sat = apply_rules(sat_ass[i]); + } + return sat; +} + +template<class ModalValueType> +bool Formula<ModalValueType>::apply_rules(SatisfyingAssignment& sat){ + bool result = true; + + int no_of_positive = 0; + int no_of_negative = 0; + bdd **underlying_formulae; + ModalValueType *positive_modal_indices, *negative_modal_indices; + + // We first find the size of the required arrays. + for(int v=0; v < sat.get_size(); v++){ + if(sat.get_array_i(v)==1 && modal_variables_back.count(v)) // if true and represents a modal formula. + no_of_positive++; + else if(sat.get_array_i(v)==0 && modal_variables_back.count(v)) // if false and ... + no_of_negative++; + } + // cout << no_of_positive + no_of_negative << endl; + if(no_of_positive + no_of_negative > 0){ + + // We then initialize our new arrays. + underlying_formulae = new bdd* [no_of_positive+no_of_negative]; + + positive_modal_indices = new ModalValueType[no_of_positive]; + negative_modal_indices = new ModalValueType[no_of_negative]; + + // We then fill our underlying formulae and modal value arrays. + int i=0, j=0; + for(int v=0; v < sat.get_size(); v++){ + if(sat.get_array_i(v)==1 && modal_variables_back.count(v)){ + underlying_formulae[i] = (modal_variables_back[v]).argument; + positive_modal_indices[i] = (modal_variables_back[v]).value; + i++; + } + else if(sat.get_array_i(v)==0 && modal_variables_back.count(v)){ //if false and represents a modal formula. + underlying_formulae[no_of_positive+j] = (modal_variables_back[v]).argument; + negative_modal_indices[j] = (modal_variables_back[v]).value; + j++; + } + } + + // Construct a GML premise + Premise<ModalValueType> premise(no_of_positive, no_of_negative, positive_modal_indices, negative_modal_indices); + // Check the rule cache + if(rule_cache.count(premise)){ // if in cache + SetOfConclusions concs = rule_cache[premise]; + for(int i = 0; i < concs.number_of_conclusions() && result; i++){ + bdd b = concs.get_jth_conclusion(underlying_formulae, i); + result = check_satisfiability(b); + } + } else { + result = enumerate_rules(premise, underlying_formulae); + } + + delete [] underlying_formulae; + delete [] positive_modal_indices; + delete [] negative_modal_indices; + } + + return result; +} + +template<class ModalValueType> +bool Formula<ModalValueType>::enumerate_rules(Premise<ModalValueType>& prem, bdd** underlying_formulae){ + bool result = true; + vector<vector<bool> > valid_nodes; + vector<pair<vector<bool>, int> > anti_nodes; + vector<vector<bool> > node_queue; + int total_valuations = prem.get_total_valuations(); + + glp_prob *problem = glp_create_prob(); + + // Parameters while solving with glpk + glp_iocp* parameters = new glp_iocp; + glp_init_iocp(parameters); + parameters->presolve = GLP_ON; + + parameters->msg_lev = GLP_MSG_ERR; + //parameters->msg_lev = GLP_MSG_ALL; + + load_linear_program(problem, prem); + + vector<bool> zero(total_valuations, false); + + if (run_solver(problem, parameters, false, zero, -1)) { + if (run_solver(problem, parameters, true, zero, 0)) + result = false; + else { + node_queue.push_back(zero); + //int i = 0; + while(result && node_queue.size()) { + //cout << "outer space: " << i++ << " runs: " << test_counter << " queue: " << node_queue.size() << " sols: " << valid_nodes.size() << " antisols: " << anti_nodes.size() << endl; + result = enum_rules_intern(problem, parameters, prem, underlying_formulae, node_queue, valid_nodes, anti_nodes); + } + if (result && !rule_cache.count(prem)) { + rule_cache[prem] = SetOfConclusions(prem.get_n() + prem.get_m(), valid_nodes); + } + //cout << "runs: " << test_counter << " sols: " << valid_nodes.size() << " antisols: " << anti_nodes.size() << endl; + } + } + + //Clean-up + delete parameters; + glp_delete_prob(problem); + + return result; +} + +template<class ModalValueType> +bool Formula<ModalValueType>::enum_rules_intern(glp_prob* problem, glp_iocp* parameters, Premise<ModalValueType>& prem, bdd** underlying_formulae, + vector<vector<bool> >& node_queue, vector<vector<bool> >& valid_nodes, vector<pair<vector<bool>, int> >& anti_nodes){ + bool result = true; + vector<vector<bool> > new_node_queue; + int total_valuations = prem.get_total_valuations(); + + for (unsigned int k = 0; k < node_queue.size() && result; k++) { + vector<bool> current_node = node_queue[k]; + + int power = total_valuations-1; + while(power >= 0 && !current_node[power]) + power--; + for(int i = power+1; i < total_valuations && result; i++){ + vector<bool> new_node(current_node); + new_node[i] = true; + + // Check node isn't superset of something already valid + bool isSubnode = false; + for(unsigned int i1=0; i1 < valid_nodes.size() && !isSubnode; i1++){ + bool isSub = true; + for(int j1=0; j1 < total_valuations; j1++){ + if (valid_nodes[i1][j1] && !new_node[j1]) { + isSub = false; + break; + } + } + if (isSub) isSubnode = true; + } + // Check node isn't superset of something of an anti-solution + for(unsigned int i1=0; i1 < anti_nodes.size() && !isSubnode; i1++){ + bool isSub = true; + int idx = anti_nodes[i1].second; + vector<bool> antinode = anti_nodes[i1].first; + for(int j1=0; j1 < total_valuations; j1++){ + if ((j1 <= idx && antinode[j1] != new_node[j1]) || (j1 > idx && antinode[j1] && !new_node[j1])) { + isSub = false; + break; + } + } + if (isSub) isSubnode = true; + } + + if (!isSubnode) { + if (run_solver(problem, parameters, false, new_node, i)) { + if (run_solver(problem, parameters, true, new_node, 0)) { + valid_nodes.push_back(new_node); + //cout << "solution found " << valid_nodes.size() << endl; + //for (int l = 0; l < total_valuations; l++) + // cout << " " << new_node[l] << endl; + vector<vector<bool> > singleton; + singleton.push_back(new_node); + SetOfConclusions temp = SetOfConclusions(prem.get_n() + prem.get_m(), singleton); + bdd b = temp.get_jth_conclusion(underlying_formulae, 0); + result = check_satisfiability(b); + } else { + new_node_queue.push_back(new_node); + } + } + else { + pair<vector<bool>, int> antipair = pair<vector<bool>, int>(new_node, i); + anti_nodes.push_back(antipair); + } + } + } + } + node_queue = new_node_queue; + return result; +} + +template<class ModalValueType> +bool Formula<ModalValueType>::run_solver(glp_prob *problem, glp_iocp* parameters, bool strict, vector<bool> current_node, int index){ + test_counter++; + + // Modify glp problem to match node + for(unsigned int i = 0; i < current_node.size(); i++){ + if(current_node[i]) + glp_set_row_bnds(problem, i+1, GLP_LO, 1.0, 0.0); // > 0 + //+1 since valuations go zero to 2^(n+m)-1, glpk rows go 1 to 2^(n+m). + else if (strict || static_cast<int>(i) <= index) + glp_set_row_bnds(problem, i+1, GLP_UP, 0.0, 0.0); // leq 0 + else + glp_set_row_bnds(problem, i+1, GLP_FR, 0.0, 0.0); // don't care + } + + if (!strict) { + parameters->tm_lim = 1000; + } else { + parameters->tm_lim = 1000000000; + } + + // Solve the LP + int result = glp_intopt(problem, parameters); + + if(result == 0 || result == GLP_ENOPFS) { //if no errors from solver or a relaxtion feasibility error + if(glp_mip_status(problem)==GLP_OPT || glp_mip_status(problem)==GLP_FEAS){ // if feasible + return true; + } + else { + return false; + } + } + else if (!strict && result == GLP_ETMLIM) { // if the solver timed out for non-strict problems + //cout << "timeout" << endl; + return true; + } else { // if error but not a feasibility error + cout << "glpk error: " << result << endl; + exit(1); + } +} + + +template class Formula<int>; +template class Formula<Rational>; diff --git a/GMLMIP-0.1/formulas/formula.h b/GMLMIP-0.1/formulas/formula.h new file mode 100644 index 0000000..a5931d1 --- /dev/null +++ b/GMLMIP-0.1/formulas/formula.h @@ -0,0 +1,159 @@ +#ifndef FORMULA_HH +#define FORMULA_HH + +#include <iostream> +#include <cstdlib> +#include <cstring> +#include <iomanip> +#include <sstream> +#include <string> +#include <time.h> + +#include "bdd.h" +#include "glpk.h" + +#include <vector> +#include <utility> + +#include "google/dense_hash_map" +#include <ext/hash_map> +/* will become #include <unordered_set> */ + +#include "rational.h" +#include "../rules/premise.h" +#include "../rules/setofconclusions.h" +#include "../satisfyingstack.h" + +using namespace std; + +using std::cout; +using std::endl; +using std::vector; +using google::dense_hash_map; +using __gnu_cxx::hash; + +// Formula interface so we can have abstract template class pointers. +class IFormula { + public: + virtual bdd variable(int n)=0; + virtual void set_bdd(bdd &b)=0; + virtual bdd get_bdd()=0; + virtual bdd modal(bdd *b, int n, int m)=0; + virtual bool satisfiability(int option)=0; + virtual void clear_maps()=0; +}; + +template<class ModalValueType> +class Formula : public IFormula{ + protected: + /* REQUIRED DEFINITIONS FOR HASH_MAPS */ + class data { + public: + ModalValueType value; + bdd* argument; + data() : value(-1) {argument = NULL; }; + data(ModalValueType v, bdd* arg) : value(v){ argument = arg; }; + ~data(){ if(argument) delete argument; }; + data& operator=(const data& other){ + if (this!=&other){ + if(argument) + delete argument; + value = other.value; + argument = NULL; + if(other.argument) + argument = new bdd(*(other.argument)); + } + return *this; + }; + data(const data& other){ + value = other.value; + argument = NULL; + if(other.argument) + argument = new bdd(*(other.argument)); + }; + }; + + // Required for dense_hash_map - how to compare keys. + struct eqkey { + bool operator()(const string s1, const string s2) const{ + return s1 == s2; + } + + bool operator()(const int s1, const int s2) const{ + return (s1 == s2); + } + + bool operator()(const data& d1, const data& d2) const{ + return ((d1.value == d2.value) && ((d1.argument==d2.argument) || (d1.argument && d2.argument && (*(d1.argument) == *(d2.argument))))); + } + }; + + // Number of variables. Set to zero by constructor and + // incremented as variables and modal variables are added. + // (Used for building the hash_maps). + int number_of_variables; + + // Map of parsed variable numbers to BDD package numbers + dense_hash_map<int, int, hash<int>, eqkey> variables; + // Map of BDD package numbers to input numbers + dense_hash_map<int, int, hash<int>, eqkey> variables_back; + + // How to hash data items. + struct datahash { + hash <const char*> charhash; + hash <int> inthash; + size_t operator ()(const data& d) const { + stringstream ss; + string s; + ss << d.value << " " << *d.argument << '\0'; + s = ss.str(); + char buf[s.size()+1]; + for(unsigned int i=0; i < s.size(); i++) + buf[i] = s[i]; + buf[s.size()]='\0'; + return charhash(buf); + } + }; + + dense_hash_map<data, int, datahash, eqkey> modal_variables; + dense_hash_map<int, data, hash<int>, eqkey> modal_variables_back; + + dense_hash_map<Premise<ModalValueType>, SetOfConclusions, typename Premise<ModalValueType>::Premise_hash, typename Premise<ModalValueType>::Premise_equal> rule_cache; + + int test_counter; + + bool check_satisfiability(bdd b); + bool apply_rules(SatisfyingAssignment& sat); + bool enumerate_rules(Premise<ModalValueType>& prem, bdd** underlying_formulae); + bool enum_rules_intern(glp_prob* problem, glp_iocp* parameters, Premise<ModalValueType>& prem, bdd** underlying_formulae, vector<vector<bool> >& node_queue, vector<vector<bool> >& valid_nodes, vector<pair<vector<bool>, int> >& anti_nodes); + bool run_solver(glp_prob *problem, glp_iocp* parameters, bool strict, vector<bool> current_node, int index); + + virtual void load_linear_program(glp_prob* problem, Premise<ModalValueType>& prem)=0; + + public: + Formula(); + // The parsed formula + bdd bdd_rep; + + // Used by the driver to set bdd_rep + void set_bdd(bdd &b){ bdd_rep=b; }; + bdd get_bdd(){ return bdd_rep;}; + + // Called by parser to construct variable or modal variable. + // Also constructs appropriate data structures. + bdd variable(int n); + bdd modal_var(bdd *b, ModalValueType &n); + + void print_back_vars(); + //virtual void print_back_modal()=0; + + bool satisfiability(int option){ return check_satisfiability(bdd_rep); }; + + void clear_maps(){ + variables.clear(); + variables_back.clear(); + modal_variables.clear(); + modal_variables_back.clear(); + rule_cache.clear(); }; +}; +#endif diff --git a/GMLMIP-0.1/formulas/makefile b/GMLMIP-0.1/formulas/makefile new file mode 100644 index 0000000..59be103 --- /dev/null +++ b/GMLMIP-0.1/formulas/makefile @@ -0,0 +1,22 @@ +GCC = g++ +GCCFLAGS = -Wall -Wno-deprecated + +all: formula.o PML_formula.o GML_formula.o rational.o satisfyingassignment.o + +satisfyingassignment.o: satisfyingassignment.h satisfyingassignment.cpp + $(GCC) $(GCCFLAGS) -c satisfyingassignment.cpp + +formula.o: formula.h formula.cpp + $(GCC) $(GCCFLAGS) -c formula.cpp + +PML_formula.o: formula.h rational.h PML_formula.cpp PML_formula.h ../rules/PML_premise.h ../rules/setofconclusions.h + $(GCC) $(GCCFLAGS) -c PML_formula.cpp + +GML_formula.o: formula.h GML_formula.cpp GML_formula.h ../rules/GML_premise.h ../rules/setofconclusions.h + $(GCC) $(GCCFLAGS) -c GML_formula.cpp + +rational.o: rational.h rational.cpp + $(GCC) $(GCCFLAGS) -c rational.cpp + +clean: + rm -rf *~ *.o test diff --git a/GMLMIP-0.1/formulas/rational.cpp b/GMLMIP-0.1/formulas/rational.cpp new file mode 100644 index 0000000..a0b5a10 --- /dev/null +++ b/GMLMIP-0.1/formulas/rational.cpp @@ -0,0 +1,29 @@ +#include "rational.h" + +Rational::Rational(int i){ + if(i==-1){ //For empty key in hash maps + top = 0; + bottom = 0; + } + else{ + top = i; + bottom = 1; + } +} + +double Rational::get(){ + return (static_cast<double>(top)/bottom); +} + +ostream& operator<<(ostream &o, const Rational &r){ + o << r.top << "/" << r.bottom; + return o; +} + +bool operator==(const Rational &r1, const Rational &r2){ + return((r1.top*r2.bottom) == (r2.top*r1.bottom)); +} + +bool operator!=(const Rational &r1, const Rational &r2){ + return !(r1==r2); +} diff --git a/GMLMIP-0.1/formulas/rational.h b/GMLMIP-0.1/formulas/rational.h new file mode 100644 index 0000000..2e41dd4 --- /dev/null +++ b/GMLMIP-0.1/formulas/rational.h @@ -0,0 +1,26 @@ +#ifndef RATIONAL_H +#define RATIONAL_H + +#include <iostream> + +using namespace std; + +class Rational { + private: + int top; + int bottom; + public: + Rational(){ top=0; bottom=0; }; + Rational(int i); + Rational(int t, int b){top=t; bottom=b;}; + int get_top(){ return top;}; + int get_bot(){ return bottom;}; + double get(); + + friend ostream& operator<<(ostream &o, const Rational &r); + friend bool operator==(const Rational &r1, const Rational &r2); + friend bool operator!=(const Rational &r1, const Rational &r2); +}; + +#endif + diff --git a/GMLMIP-0.1/formulas/satisfyingassignment.cpp b/GMLMIP-0.1/formulas/satisfyingassignment.cpp new file mode 100644 index 0000000..3f9b1b0 --- /dev/null +++ b/GMLMIP-0.1/formulas/satisfyingassignment.cpp @@ -0,0 +1,64 @@ +#include "satisfyingassignment.h" + +SatisfyingAssignment::SatisfyingAssignment(int _size, char* _array){ + size = _size; + + if(size) + array = new char [size]; + else + array = NULL; + + for(int i=0; i < size; i++) + array[i]=_array[i]; +} + +SatisfyingAssignment::SatisfyingAssignment(const SatisfyingAssignment& a){ + size = a.size; + + if(size) + array = new char [size]; + else + array = NULL; + + for(int i=0; i < size; i++) + array[i]=a.array[i]; +} + +SatisfyingAssignment& SatisfyingAssignment::operator=(const SatisfyingAssignment& a){ + if(this != &a){ + if(array) + delete [] array; + size = a.size; + + if(size) + array = new char [size]; + else + array = NULL; + + for(int i=0; i < size; i++) + array[i]=a.array[i]; + } + return *this; +} + + +SatisfyingAssignment::~SatisfyingAssignment(){ + if(array) + delete [] array; +} + +char SatisfyingAssignment::get_array_i(int i){ + if(array) + return array[i]; + return '\0'; +} + +bool SatisfyingAssignment::operator==(const SatisfyingAssignment& other) const{ + if(size == other.size){ + for(int i = 0; i < size; i++) + if(array[i]!=other.array[i]) + return false; + return true; + } + return false; + } diff --git a/GMLMIP-0.1/formulas/satisfyingassignment.h b/GMLMIP-0.1/formulas/satisfyingassignment.h new file mode 100644 index 0000000..7ad5565 --- /dev/null +++ b/GMLMIP-0.1/formulas/satisfyingassignment.h @@ -0,0 +1,26 @@ +#ifndef SATISFYINGASSIGNMENT_H +#define SATISFYINGASSIGNMENT_H + +#include <iostream> + +using namespace std; + +class SatisfyingAssignment { + private: + int size; + char* array; + public: + SatisfyingAssignment(){ size = 0; array = NULL; }; + SatisfyingAssignment(int _size, char* _array); + SatisfyingAssignment(const SatisfyingAssignment& a); + SatisfyingAssignment& operator=(const SatisfyingAssignment& a); + ~SatisfyingAssignment(); + + bool operator==(const SatisfyingAssignment& other) const; + + + int get_size(){ return size;}; + char get_array_i(int i); +}; + +#endif diff --git a/GMLMIP-0.1/input b/GMLMIP-0.1/input new file mode 100644 index 0000000..66bbf4f --- /dev/null +++ b/GMLMIP-0.1/input @@ -0,0 +1,2 @@ +Logic:GML +<3>p0 & <3>~p0 & ~<5>true diff --git a/GMLMIP-0.1/main.cpp b/GMLMIP-0.1/main.cpp new file mode 100644 index 0000000..1e88620 --- /dev/null +++ b/GMLMIP-0.1/main.cpp @@ -0,0 +1,70 @@ +#include <iostream> +#include <vector> +#include <time.h> + +#include "./parser/mlf-driver.h" +#include "./formulas/formula.h" +#include "./formulas/satisfyingassignment.h" +#include "satisfyingstack.h" + +#include "bdd.h" + +using namespace std; + +vector<SatisfyingAssignment> sat_ass_stack; + +/* Error handler for running out of BDD nodes */ +void error_handler(int errorcode){ + if(errorcode==BDD_VAR) + bdd_extvarnum(1000); + else + cout << "BDD package error number " << errorcode << endl; +} + +void parse(IFormula* &formula, int argc, char *argv[], int& verbose); + +int main (int argc, char *argv[]){ + clock_t total_time = clock(); + IFormula* f = NULL; + int verbose = 0; + //initalize buddy + bdd_init(100000, 10000); + bdd_setvarnum(100); // Minimum is two. + bdd_error_hook(error_handler); + parse(f, argc, argv, verbose); + if(f){ + // bdd_varblockall(); + // bdd_reorder(BDD_REORDER_WIN3ITE); + // bdd_printdot((driver.formula)->bdd_rep); + //bdd_printset(f->get_bdd()); + //cout << endl; + //(driver.formula)->print_back_vars(); + if(f->satisfiability(verbose)) + cout << "Satisfiable" << endl; + else + cout << "Unsatisfiable" << endl; + f->clear_maps(); + delete f; + } + bdd_done(); + total_time = clock() - total_time; + cout << "Total Time: " << static_cast<float>(total_time) / CLOCKS_PER_SEC << endl; + return 0; +} + +void parse(IFormula* &formula, int argc, char *argv[], int& option){ + mlf_driver driver; + for (++argv; argv[0]; ++argv) + if (*argv == std::string ("-p")) + driver.trace_parsing = true; + else if (*argv == std::string ("-v")) + option = 1; + else if (*argv == std::string ("-t")) + option = 2; + else if (*argv == std::string ("-s")) + driver.trace_scanning = true; + else if (!driver.parse (*argv)) + driver.extract_formula(formula); +} + + diff --git a/GMLMIP-0.1/makefile b/GMLMIP-0.1/makefile new file mode 100644 index 0000000..9576cd7 --- /dev/null +++ b/GMLMIP-0.1/makefile @@ -0,0 +1,15 @@ +GCC = g++ +GCCFLAGS = -Wall -Wno-deprecated + +POBJS = ./parser/lex.yy.o ./parser/mlf-parser.tab.o ./parser/mlf-driver.o +FOBJS = ./formulas/formula.o ./formulas/GML_formula.o ./formulas/PML_formula.o ./formulas/rational.o ./formulas/satisfyingassignment.o +ROBJS = ./rules/premise.o ./rules/GML_premise.o ./rules/PML_premise.o ./rules/valuation.o ./rules/setofconclusions.o ./rules/sizefunctions.o ./rules/radixtree.o + +main: main.o $(POBJS) $(FOBJS) $(ROBJS) + $(GCC) $(GCCFLAGS) $(POBJS) $(FOBJS) $(ROBJS) -lbdd -lm -lglpk main.o -o main + +main.o: main.cpp ./parser/mlf-driver.h ./formulas/formula.h ./formulas/satisfyingassignment.h + $(GCC) $(GCCFLAGS) -c main.cpp + +clean: + rm -rf *~ *.o main diff --git a/GMLMIP-0.1/parser/makefile b/GMLMIP-0.1/parser/makefile new file mode 100644 index 0000000..f39e8ee --- /dev/null +++ b/GMLMIP-0.1/parser/makefile @@ -0,0 +1,34 @@ +BISON = bison +LEX = flex +GCC = g++ + +GCCFLAGS = -Wall -Wno-deprecated + +all: parser lex.yy.o mlf-parser.tab.o mlf-driver.o + +lex.yy.o: lex.yy.h lex.yy.c + $(GCC) $(GCCFLAGS) -c lex.yy.c + +mlf-parser.tab.o: mlf-parser.tab.h mlf-parser.tab.cc ../formulas/GML_formula.h ../formulas/PML_formula.h + $(GCC) $(GCCFLAGS) -c mlf-parser.tab.cc + +mlf-driver.o: mlf-driver.h mlf-driver.cpp mlf-parser.tab.h lex.yy.h ../formulas/formula.h + $(GCC) $(GCCFLAGS) -c mlf-driver.cpp + +mlf-parser.tab.h: mlf-parser.yy + $(BISON) --defines=mlf-parser.tab.h mlf-parser.yy + +lex.yy.h: mlf-scanner.ll + $(LEX) --header-file=lex.yy.h mlf-scanner.ll + +parser: mlf-parser.tab.h lex.yy.h ../formulas/formula.h + + +test: parser lex.yy.o mlf-parser.tab.o mlf-driver.o test.o + $(GCC) $(GCCFLAGS) test.o lex.yy.o mlf-parser.tab.o mlf-driver.o -o test + +test.o: test.cpp mlf-driver.h + $(GCC) $(GCCFLAGS) -c test.cpp + +clean: + rm -rf *~ *.o location.hh stack.hh mlf-parser.tab.h mlf-parser.tab.cc position.hh lex.yy.c lex.yy.h test diff --git a/GMLMIP-0.1/parser/mlf-driver.cpp b/GMLMIP-0.1/parser/mlf-driver.cpp new file mode 100644 index 0000000..09279c6 --- /dev/null +++ b/GMLMIP-0.1/parser/mlf-driver.cpp @@ -0,0 +1,60 @@ +#include "mlf-driver.h" +#include "mlf-parser.tab.h" + +mlf_driver::mlf_driver() : trace_scanning (false), trace_parsing (false){ + formula = NULL; +} + +int mlf_driver::parse (const std::string &f){ + file = f; + scan_begin (); + yy::mlf_parser parser (*this); + parser.set_debug_level (trace_parsing); + int res = parser.parse (); + scan_end (); + return res; +} + +void mlf_driver::error (const yy::location& l, const std::string& m){ + std::cerr << l << ": " << m << std::endl; +} + +void mlf_driver::error (const std::string& m){ + std::cerr << m << std::endl; +} + +bdd mlf_driver::variable(int n){ + if(!formula){ + cout << "driver.formula was null!" << endl; + exit(1); + } + return formula->variable(n); +} + +bdd mlf_driver::modal(bdd *b, int n, int m){ + if(!formula){ + cout << "driver.formula was null!" << endl; + exit(1); + } + return formula->modal(b, n, m); +} + + +void mlf_driver::set_formula_bdd(bdd b){ + if(!formula){ + cout << "driver.formula was null!" << endl; + exit(1); + } + formula->set_bdd(b); +} + +void mlf_driver::extract_formula(IFormula* &ptr){ + ptr = formula; + formula = NULL; +} + +mlf_driver::~mlf_driver(){ + if(formula!=NULL) + delete formula; +} + diff --git a/GMLMIP-0.1/parser/mlf-driver.h b/GMLMIP-0.1/parser/mlf-driver.h new file mode 100644 index 0000000..2c6666c --- /dev/null +++ b/GMLMIP-0.1/parser/mlf-driver.h @@ -0,0 +1,62 @@ +#ifndef MLF_DRIVER_HH +#define MLF_DRIVER_HH +#include <string> +#include "mlf-parser.tab.h" +#include "lex.yy.h" +#include "../formulas/formula.h" + +using namespace std; + + +//Tell Flex the lexer's prototype: +# define YY_DECL \ + yy::mlf_parser::token_type \ +yylex (yy::mlf_parser::semantic_type* yylval, \ + yy::mlf_parser::location_type* yylloc, \ + mlf_driver& driver) +// ... and declare it for the parser's sake. +YY_DECL; + + +class mlf_driver{ + public: + mlf_driver(); + ~mlf_driver(); + + // The parsed formula object will be construced here + IFormula* formula; + + private: + char logic; + + public: + char get_logic(){ return logic; }; + + void set_formula_bdd(bdd b); + void set_formula_gml(){ logic='g'; formula = new GML_Formula; }; + void set_formula_pml(){ logic='p'; formula = new PML_Formula; }; + + /* Calls formula->variable and formula->modal respectively + requires ints to be pre-loaded into upper and lower. In the + case of only one integer being required we load it into n.*/ + bdd variable(int n); + bdd modal(bdd *b, int n, int m); + + // Extract the formula object + void extract_formula(IFormula* &ptr); + + // Handling the scanner. + void scan_begin (); + void scan_end (); + bool trace_scanning; + + // Run the parser. Return 0 on success. + int parse (const std::string& f); + std::string file; + bool trace_parsing; + + // Error handling. + void error (const yy::location& l, const std::string& m); + void error (const std::string& m); +}; +#endif diff --git a/GMLMIP-0.1/parser/mlf-parser.yy b/GMLMIP-0.1/parser/mlf-parser.yy new file mode 100644 index 0000000..8a2b9e0 --- /dev/null +++ b/GMLMIP-0.1/parser/mlf-parser.yy @@ -0,0 +1,111 @@ +%skeleton "lalr1.cc" +%require "2.4" +%defines +%define parser_class_name "mlf_parser" + +%code requires { + #include <string> + #include "bdd.h" + #include "../formulas/GML_formula.h" + #include "../formulas/PML_formula.h" + #include "../formulas/rational.h" + + using namespace std; + + class mlf_driver; + #define YYSTYPE ParserType + + struct ParserType +{ + int number; + struct fraction { + int numerator; + int denominator; + } fraction; + bdd binarydd; +}; +} + + + +// Parsing context +%parse-param { mlf_driver& driver} +%lex-param { mlf_driver& driver} + +%locations +%initial-action { + // Initialize the initial location. + @$.begin.filename = @$.end.filename = &driver.file; +}; + +%debug +%error-verbose + +%code { + #include "mlf-driver.h" +} + +/* operators and precendences */ + %nonassoc IFF + %right IMP + %left OR + %left AND + %nonassoc <number> GMDIA GMBOX + %nonassoc <fraction> PMDIA PMBOX + %nonassoc <binarydd> PVAR + %nonassoc NOT TRUE FALSE + + /* auxiliary */ + %token END 0 "end of file" + %token LPAREN + %token RPAREN + + %token GML + %token PML + //%token PMLI + + // %printer { debug_stream () << $$; } "identifier" + %destructor { delete &$$; } "identifier" + + %type <binarydd> formula + +%% +input: + spec + formula {driver.set_formula_bdd($2); } + ; + +spec: + GML {driver.set_formula_gml();} + | PML {driver.set_formula_pml();} + //| PMLI {} + ; + +formula: + formula IFF formula { $$ = bdd_biimp($1,$3); } + | formula IMP formula { $$ = bdd_imp($1,$3); } + | formula OR formula { $$ = bdd_or($1,$3); } + | formula AND formula { $$ = bdd_and($1,$3); } + + | GMDIA formula { bdd* b = new bdd($2); $$ = driver.modal(b, $1, 0); } + | GMBOX formula { bdd* b = new bdd(bdd_not($2)); $$ = bdd_not(driver.modal(b, $1, 0)); } // box is not-dia-not + + | PMDIA formula { bdd* b = new bdd($2); $$ = driver.modal(b, $1.numerator, $1.denominator); } + | PMBOX formula { bdd* b = new bdd(bdd_not($2)); $$ = bdd_not(driver.modal(b, $1.numerator, $1.denominator)); } + + | NOT formula { $$ = bdd_not($2); } + | PVAR { $$ = $$; } + | TRUE { $$ = bdd_true(); } + | FALSE { $$ = bdd_false(); } + | LPAREN formula RPAREN { $$ = $2; } + ; +%% + + +void yy::mlf_parser::error (const yy::mlf_parser::location_type& l, const std::string& m){ + driver.error (l, m); +} + + + + diff --git a/GMLMIP-0.1/parser/mlf-scanner.ll b/GMLMIP-0.1/parser/mlf-scanner.ll new file mode 100644 index 0000000..acdf0ad --- /dev/null +++ b/GMLMIP-0.1/parser/mlf-scanner.ll @@ -0,0 +1,124 @@ +%{ +# include <cstdlib> +# include <errno.h> +# include <limits.h> +# include <string> +# include "mlf-driver.h" +# include "mlf-parser.tab.h" + +/* Added since it fixes compile errors */ +#define YY_NEW_FILE yyrestart(yyin ) + +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ +/* %% [2.0] code to fiddle yytext and yyleng for yymore() goes here \ */\ + yyleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ +/* %% [3.0] code to copy yytext_ptr to yytext[] goes here, if %array \ */\ + (yy_c_buf_p) = yy_cp; +/* ----------------------- */ + +/* Work around an incompatibility in flex (at least versions + 2.5.31 through 2.5.33): it generates code that does + not conform to C89. See Debian bug 333231 + <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=333231>. */ +# undef yywrap +# define yywrap() 1 + +/* By default yylex returns int, we use token_type. + Unfortunately yyterminate by default returns 0, which is + not of token_type. */ +#define yyterminate() return token::END +%} + +%option noyywrap nounput batch debug + + + +%{ +# define YY_USER_ACTION yylloc->columns (yyleng); +%} + +%{ + typedef yy::mlf_parser::token token; +%} + + +%% +[ \t\n]+ /*eat white space*/ +"Logic:GML" { return token::GML; } +"Logic:PML" { return token::PML; } +"Logic: GML" { return token::GML; } +"Logic: PML" { return token::PML; } +"&" { return token::AND; } +"->" { return token::IMP; } +"<->" { return token::IFF; } +"<"[0-9]+">" { if(driver.get_logic()!='g') + driver.error(*yylloc, "Invalid operator type for specified logic!"); + else { + yylval->number = atoi(yytext + 1); + return token::GMDIA; + } + } +"["[0-9]+"]" { if(driver.get_logic()!='g') + driver.error(*yylloc, "Invalid operator type for specified logic!"); + else { + yylval->number = atoi(yytext + 1); + return token::GMBOX; + } + } +"<"[0-9]+"/"[0-9]+">" { if(driver.get_logic()!='p') + driver.error(*yylloc, "Invalid operator type for specified logic!"); + else { + (yylval->fraction).numerator = atoi(yytext + 1); + /*TODO: find more elegant way to perform this - skipping through until "/" */ + int a = 1; + int b = atoi(yytext + 1); + while(b > 0){ + b = b/10; + a++; + } + (yylval->fraction).denominator = atoi(yytext + a + 1); + return token::PMDIA; + } + } +"["[0-9]+"/"[0-9]+"]" { if(driver.get_logic()!='p') + driver.error(*yylloc, "Invalid operator type for specified logic!"); + else { + (yylval->fraction).numerator = atoi(yytext + 1); + int a = 1; + int b = atoi(yytext + 1); + while(b > 0){ + b = b/10; + a++; + } + (yylval->fraction).denominator = atoi(yytext + a + 1); + return token::PMBOX; + } + } +"v" { return token::OR; } +"~" { return token::NOT; } +p[0-9]+ { yylval->binarydd = driver.variable(atoi(yytext + 1)); return token::PVAR; } +"(" { return token::LPAREN; } +")" { return token::RPAREN; } +"true" { return token::TRUE; } +"false" { return token::FALSE; } +. driver.error (*yylloc, "invalid character!"); +%% + +void mlf_driver::scan_begin (){ + yy_flex_debug = trace_scanning; + if (file == "-") + yyin = stdin; + else if (!(yyin = fopen (file.c_str (), "r"))) + { + error (std::string ("cannot open ") + file); + exit (1); + } +} + +void mlf_driver::scan_end (){ + fclose (yyin); +} + diff --git a/GMLMIP-0.1/parser/test.cpp b/GMLMIP-0.1/parser/test.cpp new file mode 100644 index 0000000..8679303 --- /dev/null +++ b/GMLMIP-0.1/parser/test.cpp @@ -0,0 +1,16 @@ +#include <iostream> +#include "mlf-driver.h" + +int main (int argc, char *argv[]){ + mlf_driver driver; + for (++argv; argv[0]; ++argv) + if (*argv == std::string ("-p")) + driver.trace_parsing = true; + else if (*argv == std::string ("-s")) + driver.trace_scanning = true; + else if (!driver.parse (*argv)){ + std::cout << driver.result << std::endl; + std::cout << (driver.formula)->logic << std::endl; + } + return 0; +} diff --git a/GMLMIP-0.1/rand.pl b/GMLMIP-0.1/rand.pl new file mode 100644 index 0000000..7c54e91 --- /dev/null +++ b/GMLMIP-0.1/rand.pl @@ -0,0 +1,98 @@ +#!/usr/bin/perl +use Switch; + +$size = 25; +$prefix = "test"; +$num_formulas = 1000; +$num_propvars = 5; +$max_index = 100; + +for ($i = 0; $i < $num_formulas; $i++) { + $factfilename = "size" . $size . $prefix . $i . ".fact"; + $willfilename = "size" . $size . $prefix . $i . ".will"; + open FACT, ">", $factfilename; + # satisfy fact syntax + print FACT "(equal_c SAT "; + open WILL, ">", $willfilename; + # satisfy will syntax + print WILL "Logic: GML\n"; + random_formula($size); + print FACT ")\n"; + close FACT; + close WILL; +} + +sub random_formula { + local ($size) = $_[0]; + + # terminate on size 1 and return prop variable + if ($size == 1) { + $num = int(rand($num_propvars)); + print FACT "p" . $num . " "; + print WILL "p" . $num . " ";; + } + if ($size == 2) { + # guess unary connective + $conn = int(rand(2)); + switch ($conn) { + case 0 { + print WILL "(~"; + print FACT "(not "; + random_formula(1); + print WILL ")"; + print FACT ")"; + } + case 1 { + $n = int(rand($max_index)); + print WILL "(<" . $n . ">"; + print FACT "(min " . ($n+1) . " r "; + random_formula(1); + print WILL ")"; + print FACT ")"; + } + } + } + if ($size > 2) { + # guess a connective + $conn = int(rand(4)); + switch ($conn) { + case 0 { + $split = 1 + int(rand($size - 2)); + print WILL "("; + print FACT "(and "; + random_formula($split); + print WILL " & "; + random_formula ($size - $split - 1); + print WILL ")"; + print FACT ")"; + } + case 1 { + $split = 1 + int(rand($size - 2)); + print WILL "("; + print FACT "(or "; + random_formula($split); + print WILL " v "; + random_formula ($size - $split - 1); + print WILL ")"; + print FACT ")"; + } + case 2 { + print WILL "(~"; + print FACT "(not "; + random_formula ($size -1); + print WILL ")"; + print FACT ")"; + } + case 3 { + $n = int(rand($max_index)); + print WILL "(<" . $n . ">"; + print FACT "(min " . ($n+1) . " r "; + random_formula($size-1); + print WILL ")"; + print FACT ")"; + } + } + } +} + + diff --git a/GMLMIP-0.1/rules/GML_premise.cpp b/GMLMIP-0.1/rules/GML_premise.cpp new file mode 100644 index 0000000..3c24658 --- /dev/null +++ b/GMLMIP-0.1/rules/GML_premise.cpp @@ -0,0 +1,251 @@ +#include "GML_premise.h" + +GML_Premise::GML_Premise() : Premise<int>(){ +} + +GML_Premise::GML_Premise(int _n, int _m, int* _a, int *_b) : Premise<int>(_n,_m,_a,_b){ +//test_counter = 0; +} + + +/* Deprecated Functions which searched for solutions to the side condition first. +vector<Conclusion> GML_Premise::construct_conclusions(){ + double limit = bound(); + vector<Conclusion> set; + glp_prob *side_condition = glp_create_prob(); + + // Parameters while solving with glpk + glp_iocp* parameters = new glp_iocp; + glp_init_iocp(parameters); + parameters->presolve = GLP_ON; + parameters->msg_lev = GLP_MSG_ERR; + + // Load numbers into LP + load_side_condition(side_condition, limit); + + // output for testing. + //glp_write_lp(side_condition, NULL, "output.txt"); + + // Solve depth first + solve_side_condition(side_condition, parameters, 0, 0, 0, limit, set); + + //Clean-up + delete parameters; + glp_delete_prob(side_condition); + + return set; +} + +void GML_Premise::load_side_condition(glp_prob* sc, double limit){ + glp_set_obj_dir(sc, GLP_MIN); + glp_add_rows(sc, 1); + glp_set_row_bnds(sc, 1, GLP_LO, 1.0, 0.0); + + glp_add_cols(sc, n+m); + + for(int i=1; i < (n+m+1); i++){ + glp_set_col_kind(sc, i, GLP_IV); //integer variables + glp_set_col_bnds(sc, i, GLP_DB, 0, limit); + } + + // Arrays for inputting into glpk + double ar[n+m+1]; + int ia[n+m+1]; + int ja[n+m+1]; + + for(int i=1; i < n+m+1; i++){ + ia[i]=1; + ja[i]=i; + } + + int counter=1; + for(int i=0; i < n; i++){ + ar[counter]= a[i]+1; + counter++; + } + + for(int j=0; j < m; j++){ + ar[counter]=(-b[j]); + counter++; + } + + // Set objective function + for(int i=1; i < n+m+1; i++) + glp_set_obj_coef(sc, i, ar[i]); + + glp_load_matrix(sc, n+m, ia, ja, ar); +} + +void GML_Premise::solve_side_condition(glp_prob* sc, glp_iocp* parameters, int r_or_s, int index, int new_bound, double limit, vector<Conclusion>& set){ + int r[n]; + int s[m]; + int old_bound; + Conclusion conc; + + if(r_or_s == 1){ + if(new_bound < 1) + return; + // add r_i < bound + old_bound = glp_get_col_ub(sc, index+1); + if(new_bound == 1) + glp_set_col_bnds(sc, index+1, GLP_FX, 0, 0); + else + glp_set_col_bnds(sc, index+1, GLP_DB, 0, new_bound-1); // Minus once since need strictly less than. Glpk is less or equal. + } + + if(r_or_s == 2){ + if(new_bound+1 > limit) + return; + // add bound s_j > bound + old_bound = glp_get_col_lb(sc, index+n+1); + if(new_bound+1 == limit) + glp_set_col_bnds(sc, index+n+1, GLP_FX, limit, limit); + else + glp_set_col_bnds(sc, index+n+1, GLP_DB, new_bound+1, limit); + } + + //Test output + //char str[15]; + //sprintf(str, "output%d.txt", test_counter); + //glp_write_lp(sc, NULL, str); + //test_counter++; + + + // Solve + int result = glp_intopt(sc, parameters); + + if(result == 0) { //if no errors from solver + if(glp_mip_status(sc)==GLP_OPT || glp_mip_status(sc)==GLP_FEAS){ // if feasible + + // Load r and s from solution + for(int i=0; i < n; i++) + r[i] = static_cast<int>(glp_mip_col_val(sc, i+1)); + + for(int j=0; j < m; j++) + s[j] = static_cast<int>(glp_mip_col_val(sc, j+n+1)); + + // do all valuations + all_valuations(parameters, r, s, conc); + + + //if result isnt in list of conclusions then add it + bool already_have = false; + for(unsigned int i=0; i < set.size(); i++) + if( conc == set[i]) + already_have = true; + if(!already_have) + set.push_back(conc); + + // Recursively branch and solve the others - depth first + for(int i=0; i < n; i++) + solve_side_condition(sc, parameters, 1, i, r[i], limit, set); + for(int j=0; j < m; j++) + solve_side_condition(sc, parameters, 2, j, s[j], limit, set); + } + } + else if (result != GLP_ENOPFS) { // if not a feasibility error + cout << "glpk error: " << result << endl; + exit(1); + } + //remove bounds (go back up before branching down again). + if(r_or_s == 1) + glp_set_col_bnds(sc, index+1, GLP_DB, 0, old_bound); + + if(r_or_s == 2) + glp_set_col_bnds(sc, index+n+1, GLP_DB, old_bound, limit); +} + +void GML_Premise::all_valuations(glp_iocp* parameters, int* r, int* s, Conclusion& result){ +//Testing output +cout << "====================" << endl; + for(int i=0; i < n; i++) + cout << "r[" << i << "] = " << r[i] << endl; + + for(int j=0; j < m; j++) + cout << "s[" << j << "] = " << s[j] << endl; + + +glp_prob *conclusion = glp_create_prob(); +glp_set_obj_dir(conclusion, GLP_MIN); +glp_add_rows(conclusion, 2); +glp_set_row_bnds(conclusion, 1, GLP_LO, 1, 0); // strictly greater than zero + +glp_add_cols(conclusion, n+m); + +for(int i=1; i < (n+m+1); i++) + glp_set_col_kind(conclusion, i, GLP_BV); + +// Arrays for inputting into glpk + double ar[2*(n+m)+1]; + int ia[2*(n+m)+1]; + int ja[2*(n+m)+1]; + + for(int i=1; i < n+m+1; i++){ + ia[i]=1; + ia[n+m+i]=2; + ja[i]=i; + ja[n+m+i]=i; + } + + int counter=1; + for(int i=0; i < n; i++){ + ar[counter]= r[i]; + counter++; + } + + for(int j=0; j < m; j++){ + ar[counter]=(-s[j]); + counter++; + } + + for(int i=0; i < n+m; i++){ + ar[counter]=pow(2,i); + counter++; + } + + // Set objective function + for(int i=1; i < n+m+1; i++) + glp_set_obj_coef(conclusion, i, pow(2,i-1)); + + glp_load_matrix(conclusion, 2*(n+m), ia, ja, ar); + + glp_set_row_bnds(conclusion, 2, GLP_LO, 0, 0); + + // output for testing + //glp_write_lp(conclusion, NULL, "valuations.txt"); + + solve_conclusion_lp(conclusion, parameters, 0, result); + + glp_delete_prob(conclusion); +} + +void GML_Premise::solve_conclusion_lp(glp_prob* conclusion, glp_iocp* parameters, int min_limit, Conclusion& conc){ + glp_set_row_bnds(conclusion, 2, GLP_LO, min_limit, 0); + + int result = glp_intopt(conclusion, parameters); + + if(result == 0){//if no errors from solver + if(glp_mip_status(conclusion)==GLP_OPT || glp_mip_status(conclusion)==GLP_FEAS){ // if feasible + int p[n+m]; + for(int i=0; i<n+m; i++) + p[i]=glp_mip_col_val(conclusion, i+1); + //cout << glp_mip_col_val(conclusion, i+1); + Clause c(n+m,p); + conc.push_back(c); + + solve_conclusion_lp(conclusion, parameters, glp_mip_obj_val(conclusion)+1, conc); + } + } + else if (result != GLP_ENOPFS) { // if not a feasibility error + cout << "glpk error: " << result << endl; + exit(1); + } +} + + +double GML_Premise::bound(){ + return 2; + //return pow(2,6 * sizeoflp(n, m, a, b) * (n+m) * (n+m) * (n+m)); +} + +END OF DEPRECATED FUNCTIONS */ diff --git a/GMLMIP-0.1/rules/GML_premise.h b/GMLMIP-0.1/rules/GML_premise.h new file mode 100644 index 0000000..513012f --- /dev/null +++ b/GMLMIP-0.1/rules/GML_premise.h @@ -0,0 +1,33 @@ +#ifndef GML_PREMISE_H +#define GML_PREMISE_H + +#include <cmath> +#include <vector> + +#include "premise.h" +#include "sizefunctions.h" +#include "setofconclusions.h" + +class GML_Premise : public Premise<int>{ + private: + + /* Deprecated Functions which searched for solutions to the side condition first. + void load_side_condition(glp_prob* sc, double limit); + void solve_side_condition(glp_prob* side_condition, glp_iocp* parameters, int r_or_s, int index, int new_bound, double limit, vector<Conclusion>& set); + //r_or_s = 0 for neither, 1 for r, 2 for 2. + + void all_valuations(glp_iocp* parameters, int* r, int* s, Conclusion& result); + void solve_conclusion_lp(glp_prob* conclusion, glp_iocp* parameters, int min_limit, Conclusion& conc); + */ + + // for testing + //int test_counter; + public: + GML_Premise(); + GML_Premise(int _n, int _m, int* _a, int *_b); + + //double bound(); // Deprecated. + +}; + +#endif diff --git a/GMLMIP-0.1/rules/PML_premise.cpp b/GMLMIP-0.1/rules/PML_premise.cpp new file mode 100644 index 0000000..307c6fc --- /dev/null +++ b/GMLMIP-0.1/rules/PML_premise.cpp @@ -0,0 +1,17 @@ +#include "PML_premise.h" +PML_Premise::PML_Premise() : Premise<Rational>(){ +} + +PML_Premise::PML_Premise(int _n, int _m, Rational* _a, Rational* _b) : Premise<Rational>(_n,_m,_a,_b){ +//test_counter = 0; +} + + +/* Deprecated function +double PML_Premise::bound(){ + return pow(2,6 * (sizeoflp(n, m, a, b) + 1) * (n+m+1) * (n+m+1) * (n+m+1)); + // +1 for the free k. +} +*/ + + diff --git a/GMLMIP-0.1/rules/PML_premise.h b/GMLMIP-0.1/rules/PML_premise.h new file mode 100644 index 0000000..acdf0c0 --- /dev/null +++ b/GMLMIP-0.1/rules/PML_premise.h @@ -0,0 +1,26 @@ +#ifndef PML_PREMISE_H +#define PML_PREMISE_H + +#include <cmath> +#include <vector> + +#include "premise.h" +#include "sizefunctions.h" + + +class PML_Premise : public Premise<Rational>{ + private: + + /* Deprecated function + double bound(); + */ + + // for testing + //int test_counter; + public: + PML_Premise(); + PML_Premise(int _n, int _m, Rational* _a, Rational* _b); + +}; + +#endif diff --git a/GMLMIP-0.1/rules/makefile b/GMLMIP-0.1/rules/makefile new file mode 100644 index 0000000..cac0ed3 --- /dev/null +++ b/GMLMIP-0.1/rules/makefile @@ -0,0 +1,34 @@ +GCC = g++ +GCCFLAGS = -Wall -Wno-deprecated + +all: premise.o GML_premise.o PML_premise.o valuation.o setofconclusions.o sizefunctions.o radixtree.o + +sizefunctions.o: sizefunctions.h sizefunctions.cpp + $(GCC) $(GCCFLAGS) -c sizefunctions.cpp + +premise.o: premise.h premise.cpp + $(GCC) $(GCCFLAGS) -c premise.cpp + +GML_premise.o: sizefunctions.h premise.h GML_premise.h GML_premise.cpp + $(GCC) $(GCCFLAGS) -c GML_premise.cpp + +PML_premise.o: sizefunctions.h premise.h PML_premise.h PML_premise.cpp + $(GCC) $(GCCFLAGS) -c PML_premise.cpp + +valuation.o: valuation.h valuation.cpp + $(GCC) $(GCCFLAGS) -c valuation.cpp + +setofconclusions.o: setofconclusions.h valuation.h premise.h setofconclusions.cpp + $(GCC) $(GCCFLAGS) -c setofconclusions.cpp + +radixtree.o: radixtree.h radixtree.cpp + $(GCC) $(GCCFLAGS) -c radixtree.cpp + +test: all test.o + $(GCC) $(GCCFLAGS) -lglpk -lbdd ../formulas/rational.o test.o premise.o GML_premise.o PML_premise.o valuation.o setofconclusions.o sizefunctions.o -o test + +test.o: test.cpp GML_premise.h valuation.h + $(GCC) $(GCCFLAGS) -c test.cpp + +clean: + rm -rf *~ *.o test *.txt diff --git a/GMLMIP-0.1/rules/node.cpp b/GMLMIP-0.1/rules/node.cpp new file mode 100644 index 0000000..aac26a7 --- /dev/null +++ b/GMLMIP-0.1/rules/node.cpp @@ -0,0 +1,46 @@ +#include "node.h" + +void Node::allow(int a){ + valuations[a] = 1; +} + +void Node::disallow(int d){ + valuations[d] = 0; +} + +Node::Node(int no_of_atoms) : size (static_cast<int>(pow(2, no_of_atoms))), valuations(size, 0){ + //valuations.resize(size, 0); + + // needs to be replaced with actually initing the stuff + //for(int i=0; i < size; i++) + //valuations[i]=0; +} + +bool Node::operator==(const Node& other) const{ + if(size == other.size){ + for(int i=0; i < size; i++) + if(valuations[i] != other.valuations[i]) + return false; + return true; + } + return false; +} + + +bool Node::operator<(const Node& other) const{ + if(size == other.size){ + for(int i=0; i < size; i++) + if(valuations[i]==1 && other.valuations[i]==0) + return false; + return true; + } + cout << "you checked for supersets with nodes of different sizes - you probably didn't mean to do this..." << endl; + return false; +} + +ostream& operator<<(ostream& out, const Node& n){ + out << n.size << endl; + for(int i=0; i < n.size; i++) + out << n.valuations[i] << " "; + out << endl; +} diff --git a/GMLMIP-0.1/rules/node.h b/GMLMIP-0.1/rules/node.h new file mode 100644 index 0000000..55d6ec7 --- /dev/null +++ b/GMLMIP-0.1/rules/node.h @@ -0,0 +1,34 @@ +#ifndef NODE_H +#define NODE_H + +#include <iostream> +#include <cmath> +#include <vector> + +using namespace std; + +class Node { + friend ostream& operator<<(ostream& out, const Node& n); + private: + //size comes from the premise. Premise with n literals gives 2^n size. + int size; + + // bit vector: 0 = valuation not admitted, 1 = valuation is. + vector<bool> valuations; + + public: + Node(){size = 0;}; + Node(int no_of_atoms); + + void allow(int a); + void disallow(int d); + + //Copyable, assignable and comparable for use in STL + bool operator==(const Node& other) const; + + // For checking supersets. + bool operator<(const Node& other) const; + +}; + +#endif diff --git a/GMLMIP-0.1/rules/premise.cpp b/GMLMIP-0.1/rules/premise.cpp new file mode 100644 index 0000000..0db48b3 --- /dev/null +++ b/GMLMIP-0.1/rules/premise.cpp @@ -0,0 +1,110 @@ +#include "premise.h" + +template<class T> +Premise<T>::Premise(){ + n = 0; + m = 0; + total_valuations = 1 << (n+m); + a = NULL; + b = NULL; +} + +template<class T> +Premise<T>::Premise(int _n, int _m, T* _a, T* _b){ + n =_n; + m =_m; + if (n+m > 30) { + cout << "Too many (>30) modal formulae in node." << endl; + exit(1); + } + total_valuations = 1 << (n+m); + + if(n) + a = new T [n]; + else + a = NULL; + if(m) + b = new T [m]; + else + b = NULL; + + for(int i=0; i < n; i++) + a[i]=_a[i]; + for(int j=0; j < m; j++) + b[j]=_b[j]; +} + +template<class T> +Premise<T>::Premise(const Premise<T>& p){ + n = p.n; + m = p.m; + total_valuations = p.total_valuations; + + if(n) + a = new T [n]; + else + a = NULL; + + if(m) + b = new T [m]; + else + b = NULL; + + for(int i=0; i < n; i++) + a[i]=p.a[i]; + for(int j=0; j < m; j++) + b[j]=p.b[j]; +} + +template<class T> +Premise<T>& Premise<T>::operator=(const Premise<T>& p){ + if(this != &p){ + if(a) + delete [] a; + if(b) + delete [] b; + n = p.n; + m = p.m; + total_valuations = p.total_valuations; + + if(n) + a = new T [n]; + else + a = NULL; + if(m) + b = new T [m]; + else + b = NULL; + + for(int i=0; i < n; i++) + a[i]=p.a[i]; + for(int j=0; j < m; j++) + b[j]=p.b[j]; + } + return *this; +} + +template<class T> +Premise<T>::~Premise(){ + if(a) + delete [] a; + if(b) + delete [] b; +} + +template<class T> +T Premise<T>::get_a_i(int i){ + if(a) + return a[i]; + return -1; +} + +template<class T> +T Premise<T>::get_b_i(int i){ + if(b) + return b[i]; + return -1; +} + +template class Premise<int>; +template class Premise<Rational>; diff --git a/GMLMIP-0.1/rules/premise.h b/GMLMIP-0.1/rules/premise.h new file mode 100644 index 0000000..5f2882f --- /dev/null +++ b/GMLMIP-0.1/rules/premise.h @@ -0,0 +1,76 @@ +#ifndef PREMISE_HH +#define PREMISE_HH + +#include <iostream> +#include <sstream> +#include <string> + +#include <ext/hash_map> + +#include "../formulas/rational.h" + +using __gnu_cxx::hash; +using namespace std; + +template<class T> +class Premise { + protected: + // Naming follows from the names of the rules - kept as one letter for succinctness. + int n; // number of positive + int m; // number of negative + int total_valuations; + T* a; // modal indicies - positive + T* b; // modal indicies - negative + + public: + Premise(); + Premise(int _n, int _m, T* _a, T* _b); + Premise(const Premise<T>& p); + Premise<T>& operator=(const Premise<T>& p); + ~Premise(); + + int get_n(){ return n; }; + int get_m(){ return m; }; + int get_total_valuations(){ return total_valuations; }; + T get_a_i(int i); + T get_b_i(int i); + + struct Premise_hash { + hash <const char*> charhash; + size_t operator ()(const Premise<T>& p) const { + stringstream ss; + string s; + ss << p.n << " " << p.m << " "; + for(int i=0; i < p.n; i++) + ss << p.a[i] << " "; + for(int j=0; j < p.m; j++) + ss << p.b[j] << " "; + ss << '\0'; + s = ss.str(); + char buf[s.size()+1]; + for(unsigned int i=0; i < s.size(); i++) + buf[i] = s[i]; + buf[s.size()]='\0'; + return charhash(buf); + } + }; + + struct Premise_equal { //TODO: this could be improved if we sort them as we input them + bool operator()(const Premise<T>& p1, const Premise<T>& p2) const{ + if(p1.n!=p2.n) + return false; + if(p1.m!=p2.m) + return false; + for(int i=0; i < p1.n; i++) + if(p1.a[i]!=p2.a[i]) + return false; + for(int j=0; j < p1.m; j++) + if(p1.b[j]!=p2.b[j]) + return false; + return true; + } + }; +}; + + +#endif diff --git a/GMLMIP-0.1/rules/radixtree.cpp b/GMLMIP-0.1/rules/radixtree.cpp new file mode 100644 index 0000000..d639213 --- /dev/null +++ b/GMLMIP-0.1/rules/radixtree.cpp @@ -0,0 +1,55 @@ +#include "radixtree.h" + +void Radixtree::removeNodes(node* nd) { + if (nd->left) + removeNodes(nd->left); + if (nd->right) + removeNodes(nd->right); + delete nd; +} + +void Radixtree::add_element(vector<bool>& elem) { + node *index = root; + for (int i = 0; i < depth; i++) { + if (elem[i]) { + if (!index->left) + index->left = new node; + index = index->left; + } + else { + if (!index->right) + index->right = new node; + index = index->right; + } + } +} + +bool Radixtree::contains_element(vector<bool>& elem) { + node *index = root; + for (int i = 0; i < depth; i++) { + if (elem[i]) + if (!index->left) + return false; + else + index = index->left; + else + if(!index->right) + return false; + else + index = index->right; + } + return true; +} + +int Radixtree::size_intern(int d, node* nd) { + int size = 0; + if (!d) + size = 1; + else { + if (nd->left) + size += size_intern(d-1, nd->left); + if (nd->right) + size += size_intern(d-1, nd->right); + } + return size; +} diff --git a/GMLMIP-0.1/rules/radixtree.h b/GMLMIP-0.1/rules/radixtree.h new file mode 100644 index 0000000..e78d54f --- /dev/null +++ b/GMLMIP-0.1/rules/radixtree.h @@ -0,0 +1,36 @@ +#ifndef RADIXTREE_HH +#define RADIXTREE_HH + +#include <vector> + +using namespace std; + +class Radixtree { + private: + typedef struct nd { + struct nd *left; + struct nd *right; + nd() { left = right = NULL; }; + } node; + + int depth; + node *root; + + void removeNodes(node* nd); + int size_intern(int d, node* nd); + + public: + Radixtree(int n) { + depth = n; + root = new node(); + }; + + ~Radixtree(){ removeNodes(root); }; + + int size() { return size_intern(depth, root); }; + void clear() { removeNodes(root); root = new node(); }; + void add_element(vector<bool>& elem); + bool contains_element(vector<bool>& elem); +}; + +#endif diff --git a/GMLMIP-0.1/rules/setofconclusions.cpp b/GMLMIP-0.1/rules/setofconclusions.cpp new file mode 100644 index 0000000..d85e192 --- /dev/null +++ b/GMLMIP-0.1/rules/setofconclusions.cpp @@ -0,0 +1,35 @@ +#include "setofconclusions.h" + +SetOfConclusions::SetOfConclusions(int n, const vector<vector<bool> >& set){ + no_of_literals=n; + + /* To limitate code change the new type given in (vector<unsigned int>) is converted to the old type vector<vector<TruthAssignment>> + Each unsigned int corresponds to a rule instance (a node of the tree). Each node is a set of truth assignments. */ + int limit = 1 << n; + for(unsigned int i=0; i < set.size(); i++){ + vector<bool> node = set[i]; + vector<TruthAssignment> rule; + for(int j=0; j < limit; j++){ + if(node[j]) + rule.push_back(TruthAssignment(j,n)); + } + rules.push_back(rule); + } +} + +bdd SetOfConclusions::get_jth_conclusion(bdd** underlying, int j){ + bdd b = bdd_false(); + for(unsigned int i=0; i < rules[j].size(); i++){ + bdd clause = bdd_true(); + for(int k=0; k < no_of_literals; k++){ + if(rules[j][i].get_p_i(k)==1) + clause = bdd_and(clause, *(underlying[k])); + if(rules[j][i].get_p_i(k)==0) + clause = bdd_and(clause, bdd_not(*(underlying[k]))); + } + b = bdd_or(clause, b); + + } + return b; +} + diff --git a/GMLMIP-0.1/rules/setofconclusions.h b/GMLMIP-0.1/rules/setofconclusions.h new file mode 100644 index 0000000..5a7d2af --- /dev/null +++ b/GMLMIP-0.1/rules/setofconclusions.h @@ -0,0 +1,38 @@ +#ifndef SETOFCONCLUSIONS_H +#define SETOFCONCLUSIONS_H + + +#include <vector> + +#include <stdio.h> +#include <cmath> + +#include "glpk.h" +#include "bdd.h" + +#include "../formulas/rational.h" +#include "valuation.h" + + +using namespace std; + +typedef vector<TruthAssignment> Conclusion; + +class SetOfConclusions{ + private: + int no_of_literals; + vector<Conclusion> rules; + + public: + SetOfConclusions(){no_of_literals = 0;}; + SetOfConclusions(int n, const vector<vector<bool> >& set); + + int number_of_conclusions(){return rules.size();}; + bdd get_jth_conclusion(bdd** underlying, int j); + + + + + //bdd get_ith_conclusion(int i, bdd* bddarray); +}; +#endif diff --git a/GMLMIP-0.1/rules/sizefunctions.cpp b/GMLMIP-0.1/rules/sizefunctions.cpp new file mode 100644 index 0000000..bf15efc --- /dev/null +++ b/GMLMIP-0.1/rules/sizefunctions.cpp @@ -0,0 +1,26 @@ +#include "sizefunctions.h" + +/* Functions for calculating size of a linear program */ +int sizeofcoef(int a){ + int result = 1; + while (a >>= 1) + ++result; + return result; +} + +int sizeofcoef(Rational a){ + return 1 + sizeofcoef(a.get_top()) + sizeofcoef(a.get_bot()); +} + +template <class T> +int sizeoflp(const int n, const int m, T* a, T* b){ + int sum = 1 + n + m; + for(int i=0; i < n; i++) + sum+=sizeofcoef(a[i]); + for(int j=0; j < m; j++) + sum+=sizeofcoef(b[j]); + return sum; +} + +template int sizeoflp<int>(const int, const int, int*, int*); +template int sizeoflp<Rational>(const int, const int, Rational*, Rational*); diff --git a/GMLMIP-0.1/rules/sizefunctions.h b/GMLMIP-0.1/rules/sizefunctions.h new file mode 100644 index 0000000..3210fac --- /dev/null +++ b/GMLMIP-0.1/rules/sizefunctions.h @@ -0,0 +1,11 @@ +#ifndef SIZEFUNCTIONS_H +#define SIZEFUNCTIONS_H + +#include "../formulas/rational.h" + +int sizeofcoef(int a); +int sizeofcoef(Rational a); +template <class T> +int sizeoflp(const int n, const int m, T* a, T* b); + +#endif diff --git a/GMLMIP-0.1/rules/test.cpp b/GMLMIP-0.1/rules/test.cpp new file mode 100644 index 0000000..4a48ce3 --- /dev/null +++ b/GMLMIP-0.1/rules/test.cpp @@ -0,0 +1,60 @@ +#include "GML_premise.h" + +#include "bdd.h" + +int main() { + +bdd_init(10000, 1000); +bdd_setvarnum(100); + +// Create a premise object +const int n = 1; +const int m = 1; + +int a[n] = {2}; +int b[m] = {1}; + +GML_Premise p(n,m,a,b); +//p.construct_conclusions(); + +//SetOfConclusions s(p.get_n_plus_m(), p.construct_conclusions()); + +/* +bdd underlying[3]; +for(int i = 0; i < 3; i++) +underlying[i] = bdd_ithvarpp(i); + +//bdd_printdot(underlying[0]); + +bdd_printdot(s.get_jth_conclusion(underlying,2)); +*/ + + +vector<Conclusion> vec = p.construct_conclusions(); + for(unsigned int i=0; i < vec.size(); i++){ + cout << "Rule " << i << endl; + for(unsigned int j=0; j < vec[i].size(); j++){ + cout << "Valuation " << j << ": "; + for(int k=0; k < vec[i][j].get_n(); k++){ + cout << "p[" << k << "] = " << vec[i][j].get_p_i(k) << ", "; + } + cout << endl; + } + cout << "==================" << endl; +} + +/* Testing new clause/valuation constructor */ +/* +for(unsigned int j=0; j < 8; j++){ + Clause c(j,3); + for(int k=0; k < 3; k++){ + cout << "p[" << k << "] = " << c.get_p_i(k) << ", "; + } + cout << endl; +} +*/ + + +return 0; +} + diff --git a/GMLMIP-0.1/rules/valuation.cpp b/GMLMIP-0.1/rules/valuation.cpp new file mode 100644 index 0000000..9bf0ed4 --- /dev/null +++ b/GMLMIP-0.1/rules/valuation.cpp @@ -0,0 +1,71 @@ +#include "valuation.h" + +Valuation::Valuation(int i, int no_of_vars){ + int limit = 1 << no_of_vars; + if(i >= limit){ + cout << "cannot make clause " << i << " out of " << limit << endl; +} + n = no_of_vars; + + p = new int [n]; + + int ui = i; + + for(int j=0; j < no_of_vars; j++){ + p[j] = ui & 1; + ui >>=1; + } + +} + + +Valuation::Valuation(int _n, int* _p){ + n = _n; + p = new int [n]; + + for(int i=0; i < n; i++) + p[i]=_p[i]; +} + +Valuation::Valuation(const Valuation& c){ + n = c.n; + p = new int [n]; + + for(int i=0; i < n; i++) + p[i]=c.p[i]; +} + +Valuation& Valuation::operator=(const Valuation& c){ + if(this != &c){ + if(p) + delete [] p; + n = c.n; + p = new int [n]; + + for(int i=0; i < n; i++) + p[i]=c.p[i]; + } + return *this; +} + + +Valuation::~Valuation(){ + if(p) + delete [] p; +} + +int Valuation::get_p_i(int i){ + if(p) + return p[i]; + return -1; +} + +bool Valuation::operator==(const Valuation& other) const{ + if(n == other.n){ + for(int i = 0; i < n; i++) + if(p[i]!=other.p[i]) + return false; + return true; + } + return false; + } diff --git a/GMLMIP-0.1/rules/valuation.h b/GMLMIP-0.1/rules/valuation.h new file mode 100644 index 0000000..7f303b0 --- /dev/null +++ b/GMLMIP-0.1/rules/valuation.h @@ -0,0 +1,34 @@ +#ifndef VALUATION_H +#define VALUATION_H + +#include <cmath> +#include<iostream> + +using namespace std; + +/* This is a truth assignment */ + +class Valuation { + private: + int n; + int* p; + public: + Valuation(){n=0; p=NULL;}; + Valuation(int i, int total); // Gives valuation corresponding to ith valuation. + Valuation(int _n, int* p); + Valuation(const Valuation& c); + Valuation& operator=(const Valuation& c); + ~Valuation(); + bool operator==(const Valuation& other) const; + + + int get_n(){ return n;}; + int get_p_i(int i); +}; + +typedef Valuation Clause; +// Since each valuation gives rise to a clause. +// Valuation is used by deprecated side condition first code. +typedef Valuation TruthAssignment; +#endif + diff --git a/GMLMIP-0.1/satisfyingstack.h b/GMLMIP-0.1/satisfyingstack.h new file mode 100644 index 0000000..97021dd --- /dev/null +++ b/GMLMIP-0.1/satisfyingstack.h @@ -0,0 +1,12 @@ +#ifndef SATISFYINGSTACK_H +#define SATISFYINGSTACK_H + +#include <vector> +#include "./formulas/satisfyingassignment.h" + +using namespace std; + +//GLOBAL VARIABLE STACK FOR SATISFYING ASSIGNMENTS +extern vector<SatisfyingAssignment> sat_ass_stack; + +#endif diff --git a/GMLMIP-0.1/timeoutwrapper.sh b/GMLMIP-0.1/timeoutwrapper.sh new file mode 100755 index 0000000..5c19d2e --- /dev/null +++ b/GMLMIP-0.1/timeoutwrapper.sh @@ -0,0 +1,91 @@ +#!/bin/bash +# +# The Bash shell script executes a command with a time-out. +# Upon time-out expiration SIGTERM (15) is sent to the process. If the signal +# is blocked, then the subsequent SIGKILL (9) terminates it. +# +# Based on the Bash documentation example. + +# Hello Chet, +# please find attached a "little easier" :-) to comprehend +# time-out example. If you find it suitable, feel free to include +# anywhere: the very same logic as in the original examples/scripts, a +# little more transparent implementation to my taste. +# +# Dmitry V Golovashkin <Dmitry.Golovashkin@sas.com> + +scriptName="${0##*/}" + +declare -i DEFAULT_TIMEOUT=9 +declare -i DEFAULT_INTERVAL=1 +declare -i DEFAULT_DELAY=1 + +# Timeout. +declare -i timeout=DEFAULT_TIMEOUT +# Interval between checks if the process is still alive. +declare -i interval=DEFAULT_INTERVAL +# Delay between posting the SIGTERM signal and destroying the process by SIGKILL. +declare -i delay=DEFAULT_DELAY + +function printUsage() { + cat <<EOF + +Synopsis + $scriptName [-t timeout] [-i interval] [-d delay] command + Execute a command with a time-out. + Upon time-out expiration SIGTERM (15) is sent to the process. If SIGTERM + signal is blocked, then the subsequent SIGKILL (9) terminates it. + + -t timeout + Number of seconds to wait for command completion. + Default value: $DEFAULT_TIMEOUT seconds. + + -i interval + Interval between checks if the process is still alive. + Positive integer, default value: $DEFAULT_INTERVAL seconds. + + -d delay + Delay between posting the SIGTERM signal and destroying the + process by SIGKILL. Default value: $DEFAULT_DELAY seconds. + +As of today, Bash does not support floating point arithmetic (sleep does), +therefore all delay/time values must be integers. +EOF +} + +# Options. +while getopts ":t:i:d:" option; do + case "$option" in + t) timeout=$OPTARG ;; + i) interval=$OPTARG ;; + d) delay=$OPTARG ;; + *) printUsage; exit 1 ;; + esac +done +shift $((OPTIND - 1)) + +# $# should be at least 1 (the command to execute), however it may be strictly +# greater than 1 if the command itself has options. +if (($# == 0 || interval <= 0)); then + printUsage + exit 1 +fi + +# kill -0 pid Exit code indicates if a signal may be sent to $pid process. +( + ((t = timeout)) + + while ((t > 0)); do + sleep $interval + kill -0 $$ || exit 0 + ((t -= interval)) + done + + # Be nice, post SIGTERM first. + # The 'exit 0' below will be executed if any preceeding command fails. + kill -s SIGTERM $$ && kill -0 $$ || exit 0 + sleep $delay + kill -s SIGKILL $$ +) 2> /dev/null & + +exec "$@" diff --git a/INSTALL b/INSTALL index b727996..2bfd33e 100644 --- a/INSTALL +++ b/INSTALL @@ -11,6 +11,13 @@ Dependencies: - ocamlfind (package called ocaml-findlib) - ocamlgraph (package ocaml-ocamlgraph) + - Dependencies for GMLMIP-0.1: + * GNU LPK + * Flex + * Bison + * Googlesparsehash package + * BuDDy BDD package. + Build ----- @@ -41,7 +48,6 @@ Some formulas are <{ 1 2 }> C & <{ 1 2 3 4 5 6 7 8 9 }> ~C <{ 1 2 }> C & <{ 1 2 }> ~C <{ 1 2 }> C & [{ 1 2 }] ~C - <{ 1 2 }> C & [{ 1 2 }] ~C So call for example: -- GitLab