diff --git a/.hooks/README.md b/.hooks/README.md index 7828bc0..b649986 100644 --- a/.hooks/README.md +++ b/.hooks/README.md @@ -1,3 +1,3 @@ Configure hooks locally by running: -git config core.hooksPath .hooks +git config --local core.hooksPath .hooks diff --git a/.hooks/pre-commit b/.hooks/pre-commit index a41e2d9..cd34bb6 100755 --- a/.hooks/pre-commit +++ b/.hooks/pre-commit @@ -7,13 +7,13 @@ def get_files(): '--name-only', 'HEAD']).split() def apply_code_style(): - files = filter(lambda x: x.find('tests/*') == -1, get_files()) + files = filter(lambda x: x.find(b'tests/system/gt_data') == -1, get_files()) - files = filter(lambda x: x.endswith('.c') or - x.endswith('.h') or - x.endswith('.cpp'), files) + files = filter(lambda x: x.endswith(b'.c') or + x.endswith(b'.h') or + x.endswith(b'.cpp'), files) for f in files: - print("Apply code style to: " + f) + print("Apply code style to: " + str(f)) subprocess.check_output(['clang-format-7', '-i', f]) subprocess.check_output(['git', 'add', f]) @@ -21,4 +21,4 @@ def main(): apply_code_style() if (__name__ == '__main__'): - main() + main() \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index c5a704e..1bfcee8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -25,6 +25,55 @@ "type_traits": "cpp", "utility": "cpp", "iostream": "cpp", - "thread": "cpp" - } + "thread": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "csignal": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "chrono": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstdint": "cpp", + "map": "cpp", + "set": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "exception": "cpp", + "functional": "cpp", + "iterator": "cpp", + "numeric": "cpp", + "optional": "cpp", + "ratio": "cpp", + "source_location": "cpp", + "system_error": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ranges": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeindex": "cpp", + "typeinfo": "cpp", + "variant": "cpp", + "cfenv": "cpp", + "valarray": "cpp", + "rope": "cpp", + "slist": "cpp", + "regex": "cpp" + }, + "sonarlint.pathToCompileCommands": "${workspaceFolder}/compile_commands.json" } \ No newline at end of file diff --git a/causalize/sbg_implementation/Makefile.include b/causalize/sbg_implementation/Makefile.include index c1f5638..e9a0052 100644 --- a/causalize/sbg_implementation/Makefile.include +++ b/causalize/sbg_implementation/Makefile.include @@ -8,6 +8,8 @@ all: $(CAUSALIZE_SBG) # Sources CAUSALIZE_SBG_SRC := \ $(CAUSALIZE_SBG_DIR)/main.cpp\ + $(CAUSALIZE_SBG_DIR)/generate_sbg_input.cpp\ + $(UTIL_DIR)/ast_visitors/constant_expression.cpp \ $(UTIL_DIR)/ast_visitors/matching_exps.cpp \ $(UTIL_DIR)/ast_visitors/pwl_map_values.cpp \ $(UTIL_DIR)/logger.cpp diff --git a/causalize/sbg_implementation/generate_sbg_input.cpp b/causalize/sbg_implementation/generate_sbg_input.cpp new file mode 100644 index 0000000..caeb7c4 --- /dev/null +++ b/causalize/sbg_implementation/generate_sbg_input.cpp @@ -0,0 +1,377 @@ +/***************************************************************************** + + This file is part of Modelica C Compiler. + + Modelica C Compiler is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Modelica C Compiler is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Modelica C Compiler. If not, see . + +******************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace Modelica; + +namespace Causalize { +GenerateSBGInput::GenerateSBGInput(MMO_Class& mmo_class) : _mmo_class(mmo_class) {} + +std::string GenerateSBGInput::fileName() { return _mmo_class.name() + "_sbg_input.sbg"; } + +Integer GenerateSBGInput::getValue(Expression exp) const +{ + VarSymbolTable symbols = _mmo_class.syms(); + EvalExpression eval_exp(symbols); + return Integer(Apply(eval_exp, exp)); +} + +void GenerateSBGInput::addDef(int node_id, int end, int dim, int step) +{ + std::ostringstream def; + std::ostringstream dim_name; + if (dim >= 0) { + dim_name << "D" << dim; + } + def << "V" << node_id << dim_name.str() << " = " + << "V" << node_id - 1 << dim_name.str() << "+" << end; + _offsets.push_back(def.str()); + def.str(""); + def << "[V" << node_id - 1 << dim_name.str() << "+1:" << step << ":V" << node_id << dim_name.str() << "]"; + _V.push_back(def.str()); +} + +Integer GenerateSBGInput::getSize(const Index& idx) const +{ + OptExp exp = idx.exp(); + if (!exp || !is(exp.get())) { + ERROR("Only Range expressions supported"); + } + Range range = get(exp.get()); + /// @todo Handle step size. + return getValue(range.end()) - getValue(range.start()) + 1; +} + +Integer GenerateSBGInput::getSize(const IndexList& dom) const +{ + Integer ret = 1; + for (const auto& idx : dom) { + ret *= getSize(idx); + } + return ret; +} + +Integer GenerateSBGInput::getMin(const Index& idx) const +{ + OptExp exp = idx.exp(); + if (!exp || !is(exp.get())) { + ERROR("Only Range expressions supported"); + } + Range range = get(exp.get()); + return getValue(range.start()); +} + +void GenerateSBGInput::addIndexRange(IndexList range, const std::string& eq_id, int node_id) +{ + Usage usage; + foreach_(Index idx, range) + { + OptExp exp = idx.exp(); + if (!exp || !is(exp.get())) { + ERROR("Only Range expressions supported"); + } + Range idx_range = get(exp.get()); + Integer lower = getValue(idx_range.start()); + Integer step = 1; + Integer upper = getValue(idx_range.end()); + if (idx_range.step()) { + step = getValue(idx_range.step().get()); + } + addDef(node_id, upper, -1, step); + usage[idx.name()] = lower; + } + _eq_usage[eq_id] = usage; +} + +/// @todo Handle for-for equations in the same way we do in QSS Solver. +void GenerateSBGInput::buildSet(Equation eq, const std::string& eq_id, int node_id, Indexes range) +{ + Usage usage; + if (!range.indexes().empty()) { + if (is(eq)) { + ERROR("Nested for equations not implemented."); + return; + } + addIndexRange(range.indexes(), eq_id, node_id); + } else if (is(eq)) { + ForEq for_eq = get(eq); + addIndexRange(for_eq.range().indexes(), eq_id, node_id); + } else { + addDef(node_id, 1); + } +} + +/// @todo Add dimension padding and multiple dim support. +void GenerateSBGInput::buildSet(const VarInfo& variable, int node_id) +{ + Option dims = variable.indices(); + if (dims) { + foreach_(Expression d, dims.get()) { addDef(node_id, getValue(d)); } + } else { + addDef(node_id, 1); + } +} + +void GenerateSBGInput::addOffset(int edge_id, const std::string& map, int offset, int v_id, int dim) +{ + std::ostringstream def; + std::ostringstream dim_name; + if (dim >= 0) { + dim_name << "D" << dim; + } + std::ostringstream off_def; + if (offset > 0) { + off_def << " + " << offset; + } else if (offset < 0) { + off_def << " - " << offset; + } + def << "off" << map << edge_id << dim_name.str() << " = " + << "r(V" << v_id - 1 << ",1) - r(E" << edge_id - 1 << ",1)" << off_def.str(); + _offsets.push_back(def.str()); +} + +void GenerateSBGInput::addEdgeDef(int edge_id, int end, int dim) +{ + std::ostringstream def; + std::ostringstream dim_name; + if (dim >= 0) { + dim_name << "D" << dim; + } + def << "E" << edge_id << dim_name.str() << " = " + << "E" << edge_id - 1 << dim_name.str() << "+" << end; + _offsets.push_back(def.str()); + def.str(""); + def << "[E" << edge_id - 1 << dim_name.str() << "+1:1:E" << edge_id << dim_name.str() << "]"; + _E.push_back(def.str()); +} + +void GenerateSBGInput::generatePWLMaps(Expression exp, const std::string& eq_id, int edge_id) +{ + assert(is(exp)); + const IndexList& dom = _eq_range[eq_id]; + Integer dom_size = getSize(dom); + VarSymbolTable symbols = _mmo_class.syms(); + + Reference occur = get(exp); + Ref names = occur.ref(); + assert(names.size() > 0); + std::string node_name = get<0>(names[0]); + int node_id = _var_nodes[node_name]; + int eq_node_id = _eq_nodes[eq_id]; + ExpList indexes = get<1>(occur.ref().front()); + addEdgeDef(edge_id, dom_size); + for (Expression idx : indexes) { + ConstantExpression constant_index(symbols); + if (Apply(constant_index, idx)) { + addOffset(edge_id, "M1", 0, node_id); + _m1_slopes.push_back(1); + } else { + PWLMapValues pwl_map_values(symbols); + Apply(pwl_map_values, idx); + assert(pwl_map_values.slope() != 0); + Usage usage = _eq_usage[eq_id]; + int range_init_value = usage[pwl_map_values.variable()]; + int map_first_value = 0; + map_first_value = pwl_map_values.constant() + pwl_map_values.slope() * range_init_value; + addOffset(edge_id, "M1", map_first_value, node_id); + _m1_slopes.push_back(pwl_map_values.slope()); + } + } + if (indexes.empty()) { // Scalar variable. + addOffset(edge_id, "M1", 0, node_id); + _m1_slopes.push_back(1); + } + std::for_each(dom.begin(), dom.end(), [this, edge_id, eq_node_id](auto) { addOffset(edge_id, "M2", 0, eq_node_id); }); + if (dom.empty()) { // Scalar variable. + addOffset(edge_id, "M2", 0, eq_node_id); + } +} + +void GenerateSBGInput::setup() +{ + IdentList variables = _mmo_class.variables(); + VarSymbolTable symbols = _mmo_class.syms(); + + _sbg_input.open(fileName()); + _max_dim = 1; + _node_id = 1; + _edge_id = 1; + + // Get max dim defined in the model. + for (Name var_name : variables) { + VarInfo variable = symbols[var_name].get(); + if (isVariable(var_name, symbols)) { + Option indexes = variable.indices(); + if (indexes && (indexes->size() > _max_dim)) { + _max_dim = indexes->size(); + } + } + } +} + +void GenerateSBGInput::addVariableNodes() +{ + IdentList variables = _mmo_class.variables(); + VarSymbolTable symbols = _mmo_class.syms(); + + _offsets.emplace_back("V0 = 0"); + _offsets.emplace_back("E0 = 0"); + // Build unknown nodes. + foreach_(Name var_name, variables) + { + VarInfo variable = symbols[var_name].get(); + if (!isVariable(var_name, symbols)) { + buildSet(variable, _node_id); + _var_nodes.insert(std::make_pair(var_name, _node_id)); + _node_id++; + } + } +} + +void GenerateSBGInput::addEquationInfo(const std::string& eq_name, Equality eq, IndexList indexes, int node_id) +{ + _eqs.insert(std::make_pair(eq_name, eq)); + _eq_range.insert(std::make_pair(eq_name, indexes)); + _eq_nodes.insert(std::make_pair(eq_name, node_id)); +} + +void GenerateSBGInput::addEquationNodes() +{ + // Build equation nodes. + EquationList eqs = _mmo_class.equations().equations(); + foreach_(Equation eq, eqs) + { + if (is(eq)) { + ForEq for_eq = get(eq); + std::vector for_eqs = for_eq.elements(); + Indexes range = for_eq.range(); + foreach_(Equation for_el, for_eqs) + { + ERROR_UNLESS(is(for_el), "Only causalization of for and equality equations"); + std::string eq_name = "eq_" + std::to_string(_node_id); + buildSet(for_el, eq_name, _node_id, range); + addEquationInfo(eq_name, get(for_el), range.indexes(), _node_id); + _node_id++; + } + } else if (is(eq)) { + std::string eq_name = "eq_" + std::to_string(_node_id); + buildSet(eq, eq_name, _node_id); + addEquationInfo(eq_name, get(eq), IndexList(), _node_id); + _node_id++; + } else { + ERROR("Only causalization of for and equality equations"); + } + } +} + +void GenerateSBGInput::addEdges() +{ + VarSymbolTable symbols = _mmo_class.syms(); + + foreach_(auto eq_desc, _eqs) + { + Equality eq = eq_desc.second; + Expression left = eq.left(); + Expression right = eq.right(); + foreach_(const auto& node, _var_nodes) + { + Name var_name = node.first; + MatchingExps matching_exps(var_name, isState(var_name, symbols)); + Apply(matching_exps, left); + Apply(matching_exps, right); + std::set matched_exps = matching_exps.matchedExps(); + LOG << "Matched exps for: " << var_name << " in " << eq << std::endl; + foreach_(Expression exp, matched_exps) + { + LOG << "Expression: " << exp << std::endl; + generatePWLMaps(exp, eq_desc.first, _edge_id); + _edge_id++; + } + } + } +} + +void GenerateSBGInput::buildFromModel() +{ + setup(); + addVariableNodes(); + addEquationNodes(); + addEdges(); + generateSBGInput(); +} + +void GenerateSBGInput::generateEdgeMap(const std::string& map_name, const std::string& map_idx, bool fixed_slopes) +{ + _sbg_input << map_name << " %= <<"; + unsigned long size = 1; + for (std::string def : _E) { + int slope = fixed_slopes ? 1 : _m1_slopes[size - 1]; + _sbg_input << "{" << def << "} -> " << slope << "*x+off" << map_idx << size << ((size < _E.size()) ? " , " : ""); + size++; + } + _sbg_input << ">>;" << std::endl; +} + +void GenerateSBGInput::generateSBGInput() +{ + for (std::string def : _offsets) { + _sbg_input << def << std::endl; + } + _sbg_input << std::endl; + _sbg_input << "matchSCCTS(" << std::endl; + _sbg_input << "V %= {"; + unsigned long size = 1; + for (std::string def : _V) { + _sbg_input << def << ((size < _V.size()) ? " , " : ""); + size++; + } + _sbg_input << "};" << std::endl; + + _sbg_input << "Vmap %= <<"; + size = 1; + for (std::string def : _V) { + _sbg_input << "{" << def << "} -> 0*x+" << size << ((size < _V.size()) ? " , " : ""); + size++; + } + _sbg_input << ">>;" << std::endl; + generateEdgeMap("map1", "M1"); + const bool FIXED_SLOPES = true; + generateEdgeMap("map2", "M2", FIXED_SLOPES); + _sbg_input << "Emap %= <<"; + size = 1; + for (std::string def : _E) { + _sbg_input << "{" << def << "} -> 0*x+" << size << ((size < _E.size()) ? " , " : ""); + size++; + } + _sbg_input << ">>;" << std::endl; + _sbg_input << ", 1)" << std::endl; + _sbg_input.close(); +} + +} // namespace Causalize diff --git a/causalize/sbg_implementation/generate_sbg_input.h b/causalize/sbg_implementation/generate_sbg_input.h new file mode 100644 index 0000000..44a3c92 --- /dev/null +++ b/causalize/sbg_implementation/generate_sbg_input.h @@ -0,0 +1,75 @@ +/***************************************************************************** + + This file is part of Modelica C Compiler. + + Modelica C Compiler is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Modelica C Compiler is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Modelica C Compiler. If not, see . + +******************************************************************************/ + +#include +#include + +#include + +namespace Causalize { + +class GenerateSBGInput { + public: + explicit GenerateSBGInput(Modelica::MMO_Class& mmo_class); + virtual ~GenerateSBGInput() = default; + virtual void buildFromModel(); + virtual std::string fileName(); + + protected: + void setup(); + void addVariableNodes(); + void addEquationInfo(const std::string& eq_name, Equality eq, IndexList indexes, int node_id); + void addEquationNodes(); + void addEdges(); + void generateSBGInput(); + void buildSet(const VarInfo& variable, int node_id); + void buildSet(Equation eq, const std::string& eq_id, int offset, Indexes range = IndexList()); + Integer getValue(Expression exp) const; + void addDef(int node_id, int end, int dim = -1, int step = 1); + void addOffset(int edge_id, const std::string& map, int constant, int slope, int dim = -1); + void generatePWLMaps(Expression exp, const std::string& eq_id, int edge_id); + void addIndexRange(IndexList range, const std::string& eq_id, int node_id); + Integer getMin(const Index& idx) const; + Integer getSize(const Index& idx) const; + Integer getSize(const IndexList& dom) const; + void addEdgeDef(int edge_id, int end, int dim = -1); + void generateEdgeMap(const std::string& map_name, const std::string& map_idx, bool fixed_slopes = false); + + private: + using Usage = std::map>; + using EqUsage = std::map>; + + Modelica::MMO_Class& _mmo_class; + std::list _V; + std::list _E; + std::map> _eqs; + std::map> _eq_range; + std::map> _var_nodes; + std::map> _eq_nodes; + EqUsage _eq_usage; + std::list _V_map; + std::list _offsets; + std::ofstream _sbg_input; + std::vector _m1_slopes; + unsigned long _max_dim; + int _node_id; + int _edge_id; +}; + +} // namespace Causalize diff --git a/causalize/sbg_implementation/main.cpp b/causalize/sbg_implementation/main.cpp index 7e4173f..fc120f2 100644 --- a/causalize/sbg_implementation/main.cpp +++ b/causalize/sbg_implementation/main.cpp @@ -20,13 +20,12 @@ #include #include +#include #include #include #include #include #include -#include -#include using namespace std; using namespace Modelica; @@ -52,17 +51,15 @@ void version() cout << "There is NO WARRANTY, to the extent permitted by law." << endl; } -int main(int argc, char **argv) +int main(int argc, char** argv) { int opt; extern char* optarg; string output_path = ""; while (true) { - static struct option long_options[] = {{"version", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"output", required_argument, 0, 'o'}, - {0, 0, 0, 0}}; + static struct option long_options[] = { + {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {"output", required_argument, 0, 'o'}, {0, 0, 0, 0}}; int option_index = 0; opt = getopt_long(argc, argv, "vho:", long_options, &option_index); if (opt == EOF) { @@ -89,7 +86,7 @@ int main(int argc, char **argv) StoredDef stored_def; bool status = false; - std::string model_file; + std::string model_file = ""; if (argv[optind] != nullptr) { model_file = argv[optind]; stored_def = Parser::ParseFile(model_file, status); @@ -97,7 +94,7 @@ int main(int argc, char **argv) std::cout << "No input file provided." << std::endl; usage(); exit(-1); - } + } if (!status) { std::cout << "Error parsing file " << model_file << std::endl; @@ -111,9 +108,16 @@ int main(int argc, char **argv) StateVariablesFinder setup_state_var(mmo_class); setup_state_var.findStateVariables(); + Causalize::GenerateSBGInput gen_sbg_input(mmo_class); + + gen_sbg_input.buildFromModel(); + /// Temp hack to test the binaries, hardcoded paths should go on config files. const std::string CAUSALIZE = "../3rd-party/sbg/sb-graph-dev/bin/sbg-eval "; - const std::string ARGS = "-f " + model_file + " > " + model_file + "_causalized.sbg"; + const std::string DEFAULT_CAUSALIZED_JSON = "./output.json"; + const std::string CAUSALIZED_JSON = mmo_class.name() + "_causalized.json"; + std::string ARGS = "-f " + gen_sbg_input.fileName() + " > " + mmo_class.name() + "_causalized.sbg; mv " + DEFAULT_CAUSALIZED_JSON + + " ./" + CAUSALIZED_JSON; const std::string CAUSALIZE_CMD = CAUSALIZE + ARGS; int res = std::system(CAUSALIZE_CMD.c_str()); diff --git a/causalize/sbg_implementation/matching_graph_builder.cpp b/causalize/sbg_implementation/matching_graph_builder.cpp deleted file mode 100644 index 1e0ddc3..0000000 --- a/causalize/sbg_implementation/matching_graph_builder.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/***************************************************************************** - - This file is part of Modelica C Compiler. - - Modelica C Compiler is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Modelica C Compiler is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Modelica C Compiler. If not, see . - -******************************************************************************/ - -#include -#include -#include -#include -#include -#include - -using namespace Modelica; -using namespace SBG; - -namespace Causalize { -MatchingGraphBuilder::MatchingGraphBuilder(MMO_Class &mmo_class) : _mmo_class(mmo_class), _U(), _F(), _eq_usage() {} - -Real MatchingGraphBuilder::getValue(Expression exp) -{ - VarSymbolTable symbols = _mmo_class.syms(); - EvalExpression eval_exp(symbols); - return Apply(eval_exp, exp); -} - -void MatchingGraphBuilder::addDims(size_t max_dim, size_t exp_dim, SBG::MultiInterval& intervals, int offset) -{ - if (max_dim > exp_dim) { - for (size_t i = exp_dim; i < max_dim; i++) { - Interval interval(offset, 1, offset); - intervals.addInter(interval); - } - } -} - -void MatchingGraphBuilder::addDims(size_t max_dim, size_t exp_dim, ORD_REALS& constant, ORD_REALS& slope) -{ - ORD_REALS::iterator constant_it = constant.end(); - ORD_REALS::iterator slope_it = slope.end(); - if (max_dim > exp_dim) { - for (size_t i = exp_dim; i < max_dim; i++) { - constant_it = constant.insert(constant_it, 0); - slope_it = slope.insert(slope_it, 0); - } - } -} - -SBG::Set MatchingGraphBuilder::buildSet(VarInfo variable, int offset, size_t max_dim) -{ - Option dims = variable.indices(); - MultiInterval variable_intervals; - if (dims) { - foreach_(Expression d, dims.get()) { - Real res = getValue(d) - 1; - Interval interval(offset, 1, offset + res); - variable_intervals.addInter(interval); - } - addDims(max_dim, dims->size(), variable_intervals, offset); - } else { - addDims(max_dim, 0, variable_intervals, offset); - } - return createSet(variable_intervals); -} - -SBG::Set MatchingGraphBuilder::buildSet(Equation eq, std::string eq_id, int offset, size_t max_dim) -{ - Usage usage; - MultiInterval equation_intervals; - if (is(eq)) { - ForEq for_eq = get(eq); - IndexList indexes = for_eq.range().indexes(); - foreach_(Index idx, indexes) { - OptExp exp = idx.exp(); - if (!exp || !is(exp.get())) { - ERROR("Only Range expressions supported"); - } - Range range = get(exp.get()); - Real lower = getValue(range.start()); - Real step = 1; - Real upper = getValue(range.end()); - if (range.step()) { - step = getValue(range.step().get()); - } - Real end = offset + upper - lower; - Interval interval(offset, step, end); - equation_intervals.addInter(interval); - usage[idx.name()] = lower; - } - addDims(max_dim, indexes.size(), equation_intervals, offset); - _eq_usage[eq_id] = usage; - } else { - addDims(max_dim, 0, equation_intervals, offset); - } - return createSet(equation_intervals); -} - -/** - * @brief Add the offset to a given equation domain. - * - * @param dom - * @param offset - * @return SBG::Set The new set with all the offsets applied. - */ -SBG::Set MatchingGraphBuilder::generateMapDom(SBG::Set dom, SBG::Set unk_dom, int offset, size_t max_dim) -{ - MultiInterval edge_set_intervals; - SBG::UNORD_MI atom_sets = dom.asets(); - foreach_(MultiInterval dom_intervals, atom_sets) { - foreach_(Interval inter, dom_intervals.inters()) { - Real end = inter.card() + offset - 1; - edge_set_intervals.addInter(Interval(offset, inter.step(), end)); - } - addDims(max_dim, dom_intervals.inters().size(), edge_set_intervals, offset); - } - return createSet(edge_set_intervals); -} - -SetVertexDesc MatchingGraphBuilder::addVertex(std::string vertex_name, SBG::Set set, std::string desc, SBGraph& graph) -{ - SetVertex V(vertex_name, set, desc); - SetVertexDesc v = boost::add_vertex(graph); - graph[v] = V; - return v; -} - -void MatchingGraphBuilder::addEquation(Equation eq, std::string id, SBG::Set set, SBGraph& graph) -{ - std::ostringstream desc; - desc << eq; - - if (!is(eq)) { - ERROR("Only Equality equations supported."); - } - _F.push_back(std::make_pair(addVertex(id, set, desc.str(), graph),get(eq))); -} - -PWLMap MatchingGraphBuilder::buildPWLMap(ORD_REALS constants, ORD_REALS slopes, SBG::Set dom) -{ - LMap lmap(slopes, constants); - - OrdCT doms; - doms.insert(doms.end(), dom); - - OrdCT maps; - maps.insert(maps.end(), lmap); - PWLMap map(doms, maps); - return map; -} - -MatchingGraphBuilder::MatchingMaps MatchingGraphBuilder::generatePWLMaps(Expression exp, SBG::Set dom, SBG::Set unk_dom, int offset, std::string eq_id, size_t max_dim) -{ - assert(is(exp)); - VarSymbolTable symbols = _mmo_class.syms(); - ORD_REALS constant_pwl_map_u; - ORD_REALS::iterator constant_pwl_map_u_it = constant_pwl_map_u.begin(); - ORD_REALS slope_pwl_map_u; - ORD_REALS::iterator slope_pwl_map_u_it = slope_pwl_map_u.begin(); - ORD_REALS constant_pwl_map_f; - ORD_REALS::iterator constant_pwl_map_f_it = constant_pwl_map_f.begin(); - ORD_REALS slope_pwl_map_f; - ORD_REALS::iterator slope_pwl_map_f_it = slope_pwl_map_f.begin(); - - Reference occur = get(exp); - ExpList indexes = get<1>(occur.ref().front()); - SBG::ORD_INTS init_elems = unk_dom.minElem(); - assert(init_elems.size() == indexes.size() || indexes.size() == 0); - SBG::ORD_INTS::iterator min_elem = init_elems.begin(); - SBG::Set map_dom = generateMapDom(dom, unk_dom, offset, max_dim); - int map_offset = offset - 1; - - foreach_(Expression idx, indexes) - { - SBG::INT set_vertex_init = *min_elem -1; - PWLMapValues pwl_map_values(symbols); - Apply(pwl_map_values, idx); - Usage usage = _eq_usage[eq_id]; - int range_init_value = usage[pwl_map_values.variable()]; - int set_vertex_offset = pwl_map_values.slope() * offset; - int map_first_value = pwl_map_values.constant() + pwl_map_values.slope() * range_init_value + set_vertex_init; - constant_pwl_map_u_it = constant_pwl_map_u.insert(constant_pwl_map_u_it, map_first_value - set_vertex_offset); - slope_pwl_map_u_it = slope_pwl_map_u.insert(slope_pwl_map_u_it, pwl_map_values.slope()); - min_elem++; - } - if (indexes.empty()) { // Scalar variable. - SBG::INT set_vertex_init = *min_elem -1; - constant_pwl_map_u_it = constant_pwl_map_u.insert(constant_pwl_map_u_it, - map_offset + set_vertex_init); - slope_pwl_map_u_it = slope_pwl_map_u.insert(slope_pwl_map_u_it, 1); - addDims(max_dim, 1, constant_pwl_map_u, slope_pwl_map_u); - } else { - addDims(max_dim, indexes.size(), constant_pwl_map_u, slope_pwl_map_u); - } - for (SBG::INT init : dom.minElem()) { - SBG::INT set_vertex_init = init -1; - constant_pwl_map_f_it = constant_pwl_map_f.insert(constant_pwl_map_f_it, -map_offset + set_vertex_init); - slope_pwl_map_f_it = slope_pwl_map_f.insert(slope_pwl_map_f_it, 1); - } - addDims(max_dim, dom.minElem().size(), constant_pwl_map_f, slope_pwl_map_f); - return std::make_pair(buildPWLMap(constant_pwl_map_f, slope_pwl_map_f, map_dom), buildPWLMap(constant_pwl_map_u, slope_pwl_map_u, map_dom)); -} - -SBGraph MatchingGraphBuilder::makeGraph() -{ - SBGraph graph; - VarSymbolTable symbols = _mmo_class.syms(); - - IdentList variables = _mmo_class.variables(); - size_t max_dim = 1; - // Get max dim defined in the model. - foreach_(Name var_name, variables) - { - VarInfo variable = symbols[var_name].get(); - if (!isConstant(var_name, symbols) && !isBuiltIn(var_name, symbols) && !isDiscrete(var_name, symbols) && !isParameter(var_name, symbols)) { - Option indexes = variable.indices(); - if (indexes && indexes->size() > max_dim) { - max_dim = indexes->size(); - } - } - } - - int set_vertex_offset = 1; - // Build unknown nodes. - foreach_(Name var_name, variables) - { - VarInfo variable = symbols[var_name].get(); - if (!isConstant(var_name, symbols) && !isBuiltIn(var_name, symbols) && !isDiscrete(var_name, symbols) && !isParameter(var_name, symbols)) { - SBG::Set vertex_dom = buildSet(variable, set_vertex_offset, max_dim); - _U.push_back(addVertex(var_name, vertex_dom, "", graph)); - set_vertex_offset += vertex_dom.card(); - } - } - - // Build equation nodes. - EquationList eqs = _mmo_class.equations().equations(); - int id = 1; - foreach_(Equation eq, eqs) - { - SBG::Set vertex_dom; - if (is(eq)) { - ForEq for_eq = get(eq); - std::vector for_eqs = for_eq.elements(); - foreach_(Equation for_el, for_eqs) - { - std::string eq_name = "eq_" + std::to_string(id++); - vertex_dom = buildSet(eq, eq_name, set_vertex_offset, max_dim); - set_vertex_offset += vertex_dom.card(); - addEquation(for_el, eq_name, vertex_dom, graph); - } - } else if (is(eq)) { - std::string eq_name = "eq_" + std::to_string(id++); - vertex_dom = buildSet(eq, eq_name, set_vertex_offset, max_dim); - set_vertex_offset += vertex_dom.card(); - addEquation(eq, eq_name, vertex_dom, graph); - } else { - ERROR("Only causalization of for and equality equations"); - } - } - - // Build edges. - int set_edge_offset = 1; - unsigned int edge_id = 1; - foreach_(EquationDesc eq_desc, _F) - { - SetVertexDesc eq_vertex_desc = eq_desc.first; - SetVertex eq_vertex = graph[eq_vertex_desc]; - Expression left = eq_desc.second.left(); - Expression right = eq_desc.second.right(); - SBG::Set dom = eq_vertex.range(); - foreach_(SetVertexDesc unknown_vertex_desc, _U) - { - SetVertex unknown_vertex = graph[unknown_vertex_desc]; - SBG::Set unk_dom = unknown_vertex.range(); - MatchingExps matching_exps(unknown_vertex.id(), isState(unknown_vertex.id(), symbols)); - Apply(matching_exps, left); - Apply(matching_exps, right); - std::set matched_exps = matching_exps.matchedExps(); - LOG << "Matched exps for: " << unknown_vertex.id() << " in " << eq_desc.second << std::endl; - LOG << "Equation dom: " << dom << std::endl; - foreach_(Expression exp, matched_exps) - { - LOG << "Expression: " << exp << std::endl; - MatchingMaps maps = generatePWLMaps(exp, dom, unk_dom, set_edge_offset, eq_vertex.id(), max_dim); - set_edge_offset += dom.card(); - std::string edge_name = "E_" + std::to_string(edge_id++); - LOG << "MapF: " << maps.first << std::endl; - LOG << "MapU: " << maps.second << std::endl; - SetEdge edge(edge_name, maps.first, maps.second); - SetEdgeDesc e; - bool b; - boost::tie(e, b) = boost::add_edge(eq_vertex_desc, unknown_vertex_desc, graph); - graph[e] = edge; - } - } - } - return graph; -} - -} // namespace Causalize diff --git a/causalize/sbg_implementation/matching_graph_builder.h b/causalize/sbg_implementation/matching_graph_builder.h deleted file mode 100644 index 0b231b5..0000000 --- a/causalize/sbg_implementation/matching_graph_builder.h +++ /dev/null @@ -1,57 +0,0 @@ -/***************************************************************************** - - This file is part of Modelica C Compiler. - - Modelica C Compiler is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Modelica C Compiler is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Modelica C Compiler. If not, see . - -******************************************************************************/ - -#include -#include - -namespace Causalize { - -class MatchingGraphBuilder { - public: - MatchingGraphBuilder(Modelica::MMO_Class& mmo_class); - ~MatchingGraphBuilder() = default; - virtual SBG::SBGraph makeGraph(); - - protected: - typedef std::pair MatchingMaps; - - SBG::Set buildSet(VarInfo variable, int offset, size_t max_dim); - SBG::Set buildSet(Equation eq, std::string eq_id, int offset, size_t max_dim); - SBG::Set buildSet(SBG::MultiInterval variable); - SBG::SetVertexDesc addVertex(std::string vertex_name, SBG::Set set, std::string desc, SBG::SBGraph& graph); - void addEquation(Equation eq, std::string id, SBG::Set set, SBG::SBGraph& graph); - Real getValue(Expression exp); - SBG::PWLMap buildPWLMap(SBG::ORD_REALS constants, SBG::ORD_REALS slopes, SBG::Set dom); - MatchingMaps generatePWLMaps(Expression exp, SBG::Set dom, SBG::Set unk_dom, int offset, std::string eq_id, size_t max_dim); - SBG::Set generateMapDom(SBG::Set dom, SBG::Set unk_dom, int offset, size_t max_dim); - void addDims(size_t max_dim, size_t exp_dim, SBG::MultiInterval& intervals, int offset); - void addDims(size_t max_dim, size_t exp_dim, SBG::ORD_REALS& constant, SBG::ORD_REALS& slope); - - private: - typedef std::pair EquationDesc; - typedef std::map Usage; - typedef std::map EqUsage; - - Modelica::MMO_Class& _mmo_class; - std::list _U; - std::list _F; - EqUsage _eq_usage; -}; - -} // namespace Causalize diff --git a/causalize/sbg_implementation/test/models_test.cpp b/causalize/sbg_implementation/test/models_test.cpp index 6baffd3..7fb54b7 100644 --- a/causalize/sbg_implementation/test/models_test.cpp +++ b/causalize/sbg_implementation/test/models_test.cpp @@ -35,13 +35,13 @@ TEST_P(ITests, GenerateCode) { const std::string NAME = GetParam(); std::cout << "Testing model: " << NAME << std::endl; - const std::string FLATTER = "../../../bin/causalize "; + const std::string CAUSALIZE = "../../../bin/causalize "; const std::string ARGS = "-o ./test_data/ ../../../test/mccprograms/" + NAME + ".mo"; const std::string RESULT_FILE = "./test_data/" + NAME + ".passed"; const std::string TEST_CMD = "./test_results.sh " + NAME; - const std::string FLATTER_CMD = FLATTER + ARGS; + const std::string CAUSALIZE_CMD = CAUSALIZE + ARGS; - std::system(FLATTER_CMD.c_str()); + std::system(CAUSALIZE_CMD.c_str()); std::system(TEST_CMD.c_str()); std::ifstream result(RESULT_FILE.c_str()); diff --git a/util/ast_visitors/eval_expression.h b/util/ast_visitors/eval_expression.h index fa8d159..54d5ebe 100644 --- a/util/ast_visitors/eval_expression.h +++ b/util/ast_visitors/eval_expression.h @@ -19,16 +19,16 @@ #ifndef AST_VISITOR_EVALEXP #define AST_VISITOR_EVALEXP + #include #include #include namespace Modelica { -using namespace Modelica::AST; -class EvalExpression : public boost::static_visitor{ +class EvalExpression : public boost::static_visitor { public: - EvalExpression(const VarSymbolTable &); + explicit EvalExpression(const VarSymbolTable &); EvalExpression(const VarSymbolTable &, Name, Real); Real operator()(Integer v) const; Real operator()(Boolean v) const; diff --git a/util/ast_visitors/pwl_map_values.cpp b/util/ast_visitors/pwl_map_values.cpp index 9d968a2..770b016 100644 --- a/util/ast_visitors/pwl_map_values.cpp +++ b/util/ast_visitors/pwl_map_values.cpp @@ -24,12 +24,12 @@ namespace Modelica { -PWLMapValues::PWLMapValues(VarSymbolTable symbols) : _constant(0), _slope(1), _symbols(symbols), _variable() {}; +PWLMapValues::PWLMapValues(VarSymbolTable symbols) : _constant(0), _slope(1), _symbols(symbols), _variable(){}; bool PWLMapValues::operator()(Integer v) const -{ - _constant = v; - return false; +{ + _constant = v; + return false; } bool PWLMapValues::operator()(Boolean v) const { return false; } @@ -84,14 +84,15 @@ void PWLMapValues::assign(Expression left, Expression right, bool var_left, bool } else if (var_right) { _constant = sign * Apply(eval_exp, left); } else { - _constant = sign * (Apply(eval_exp, left) + Apply(eval_exp, right)); + _constant = sign * (Apply(eval_exp, left) + Apply(eval_exp, right)); } } bool PWLMapValues::operator()(BinOp v) const { EvalExpression eval_exp(_symbols); - Expression l = v.left(), r = v.right(); + Expression l = v.left(); + Expression r = v.right(); bool var_left = ApplyThis(l); bool var_right = ApplyThis(r); BinOpType type = v.op(); @@ -129,10 +130,10 @@ bool PWLMapValues::operator()(UnaryOp v) const return ret; } -int PWLMapValues::constant() const { return _constant; } +int PWLMapValues::constant() const { return _constant; } -int PWLMapValues::slope() const { return _slope; } +int PWLMapValues::slope() const { return _slope; } -std::string PWLMapValues::variable() const { return _variable; } +std::string PWLMapValues::variable() const { return _variable; } } // namespace Modelica diff --git a/util/ast_visitors/pwl_map_values.h b/util/ast_visitors/pwl_map_values.h index 36797a8..82084a6 100644 --- a/util/ast_visitors/pwl_map_values.h +++ b/util/ast_visitors/pwl_map_values.h @@ -25,10 +25,9 @@ namespace Modelica { -using namespace Modelica::AST; class PWLMapValues : public boost::static_visitor { public: - PWLMapValues(VarSymbolTable symbols); + explicit PWLMapValues(VarSymbolTable symbols); bool operator()(Integer v) const; bool operator()(Boolean v) const; bool operator()(AddAll v) const;