From ad8dd38eec769902f50068a2933150c8269da894 Mon Sep 17 00:00:00 2001 From: Joaquin Date: Mon, 16 Nov 2020 18:08:11 -0300 Subject: [PATCH] [iss-15] Squashed commit of the following: commit ecfe8dd851d0c46f63138e83501c78a2b81cb57c Author: Joaquin Date: Mon Nov 16 18:05:50 2020 -0300 Fixed merge conflicts. commit 15d4e1bdedffde558a1dfe8e12201b8b27ec5031 Author: Joaquin Date: Mon Nov 16 17:57:15 2020 -0300 Merge new files, split vector graph implementation. commit 756b3e42c8d9010b27f2242abba768730f22b37b Author: Joaquin Date: Mon Nov 16 14:56:17 2020 -0300 Vector graph implementation new files. commit e08f986f2e0ea57d7b6880fd353449b3ef1a6067 Author: Joaquin Date: Thu Nov 12 18:58:39 2020 -0300 Change std compile flags. --- Makefile.in | 2 +- causalize/Makefile.include | 2 + .../for_unrolling/for_index_iterator.cpp | 2 +- .../for_unrolling/for_index_iterator.h | 0 .../for_unrolling/process_for_equations.cpp | 0 .../for_unrolling/process_for_equations.h | 0 .../graph_implementation/Makefile.include | 12 +- .../graph_implementation/apply_tarjan.cpp | 7 - causalize/graph_implementation/apply_tarjan.h | 7 - .../causalization_strategy.cpp | 9 +- .../causalization_strategy.h | 7 - .../graph/graph_definition.cpp | 5 - causalize/graph_implementation/main.cpp | 2 +- .../unknowns_collector.cpp | 7 - .../vector/causalization_algorithm.cpp | 2 +- causalize/vg_implementation/Makefile.include | 35 + causalize/vg_implementation/apply_tarjan.cpp | 180 ++++ causalize/vg_implementation/apply_tarjan.h | 37 + .../causalization_strategy.cpp | 374 ++++++++ .../causalization_strategy.h | 49 + .../for_unrolling/process_for_equations.cpp | 216 +++++ .../for_unrolling/process_for_equations.h | 33 + .../graph/graph_definition.cpp | 40 + .../graph/graph_definition.h | 77 ++ .../vg_implementation/graph/graph_printer.h | 263 ++++++ causalize/vg_implementation/main.cpp | 115 +++ .../vg_implementation/unknowns_collector.cpp | 122 +++ .../vg_implementation/unknowns_collector.h | 35 + .../vector/causalization_algorithm.cpp | 715 +++++++++++++++ .../vector/causalization_algorithm.h | 58 ++ .../vector/graph_builder.cpp | 169 ++++ .../vg_implementation/vector/graph_builder.h | 47 + .../vg_implementation/vector/splitfor.cpp | 49 + causalize/vg_implementation/vector/splitfor.h | 33 + .../vector/vector_graph_definition.cpp | 844 ++++++++++++++++++ .../vector/vector_graph_definition.h | 262 ++++++ .../vector/vector_matching.cpp | 325 +++++++ .../vector/vector_matching.h | 77 ++ .../vector/vector_tarjan.cpp | 323 +++++++ .../vg_implementation/vector/vector_tarjan.h | 78 ++ configure.in | 4 +- .../causalize/vector/AdvectionReaction.mo | 22 + .../causalize/vector/AdvectionReaction2D.mo | 28 + .../causalize/vector/AdvectionReaction3D.mo | 56 ++ examples/causalize/vector/AirConditioners.mo | 69 ++ .../causalize/vector/CascadedFirstOrder.mo | 22 + .../vector/CocurrentHeatExchangerEquations.mo | 77 ++ examples/causalize/vector/Generator.mo | 135 +++ .../causalize/vector/HeatingSystemExplicit.mo | 64 ++ examples/causalize/vector/PowerSystem.mo | 169 ++++ examples/causalize/vector/SimpleAdvection.mo | 28 + .../causalize/vector/Sintetic/example1.mo | 10 + .../causalize/vector/Sintetic/example10.mo | 20 + .../causalize/vector/Sintetic/example11.mo | 8 + .../causalize/vector/Sintetic/example12.mo | 12 + .../causalize/vector/Sintetic/example13.mo | 8 + .../causalize/vector/Sintetic/example14.mo | 10 + .../causalize/vector/Sintetic/example15.mo | 0 .../causalize/vector/Sintetic/example2.mo | 9 + .../causalize/vector/Sintetic/example3.mo | 8 + .../causalize/vector/Sintetic/example4.mo | 10 + .../causalize/vector/Sintetic/example5.mo | 10 + .../causalize/vector/Sintetic/example6.mo | 18 + .../causalize/vector/Sintetic/example7.mo | 38 + .../causalize/vector/Sintetic/example8.mo | 17 + .../causalize/vector/Sintetic/example9.mo | 20 + .../vector/TransmissionLineEquations.mo | 34 + test/causalize/ELECTRICALLY_HEATED_ROD.mo | 16 + .../ELECTRICALLY_HEATED_ROD_MULTIDIM.mo | 29 + test/causalize/Makefile.include | 37 +- test/causalize/OneDHeatTransferTI_FD_100.mo | 33 + .../OneDHeatTransferTI_FD_complicated.mo | 33 + .../OneDHeatTransferTI_FD_impossible.mo | 33 + test/causalize/OneDHeatTransferTI_FD_loop.mo | 6 +- test/causalize/adventionReaction2D.mo | 28 + test/causalize/bug1.mo | 9 + test/causalize/bug2.mo | 12 + test/causalize/bugVectorial.mo | 11 + .../causalize/causalization_strategy_test.cpp | 100 ++- test/causalize/ecvec.mo | 9 + test/causalize/ecvec_newton.mo | 9 + test/causalize/ecvec_newton_sol.mo | 17 + test/causalize/ejemploKofman.mo | 21 + test/causalize/kofman.mo | 21 + test/causalize/lazo_newton.mo | 10 + test/causalize/lazo_newton_sol.mo | 17 + test/causalize/redrc.mo | 24 + test/causalize/rlc_circuit.mo | 21 + test/causalize/tarjan1.mo | 9 + test/causalize/tarjan1.mo.mo | 9 + test/causalize/tarjan1b.mo | 7 + test/causalize/tarjan1c.mo | 13 + test/causalize/tarjan1d.mo | 16 + test/causalize/tarjan2.mo | 12 + test/causalize/tarjan2D.mo | 10 + test/causalize/tarjan2b.mo | 13 + test/causalize/tarjan3.mo | 9 + test/causalize/tarjan4.mo | 8 + test/causalize/tarjan4D.mo | 9 + test/causalize/tarjan5.mo | 10 + test/causalize/tarjan6.mo | 9 + test/causalize/test.mo | 11 + test/causalize/test2.mo | 7 + test/causalize/test3.mo | 13 + test/causalize/testDomRan1.mo | 14 + test/causalize/testDomRan2.mo | 12 + test/causalize/testDomRan3.mo | 14 + test/causalize/testDomRan4.mo | 14 + util/ast_visitors/all_expressions.cpp | 147 +++ util/ast_visitors/all_expressions.h | 57 ++ util/ast_visitors/contains_unknown.cpp | 179 ++++ util/ast_visitors/contains_unknown.h | 65 ++ util/ast_visitors/contains_vector.cpp | 285 ++++++ util/ast_visitors/contains_vector.h | 73 ++ util/ast_visitors/ginac_interface.cpp | 193 +++- util/ast_visitors/ginac_interface.h | 14 +- util/ast_visitors/replace_index.cpp | 202 +++++ util/ast_visitors/replace_index.h | 66 ++ util/ast_visitors/state_variables_finder.cpp | 7 - util/ast_visitors/state_variables_finder.h | 7 - util/solve/solve.cpp | 258 ++++-- 121 files changed, 7587 insertions(+), 207 deletions(-) create mode 100644 causalize/Makefile.include rename causalize/{graph_implementation => common}/for_unrolling/for_index_iterator.cpp (96%) rename causalize/{graph_implementation => common}/for_unrolling/for_index_iterator.h (100%) rename causalize/{graph_implementation => common}/for_unrolling/process_for_equations.cpp (100%) rename causalize/{graph_implementation => common}/for_unrolling/process_for_equations.h (100%) create mode 100644 causalize/vg_implementation/Makefile.include create mode 100644 causalize/vg_implementation/apply_tarjan.cpp create mode 100644 causalize/vg_implementation/apply_tarjan.h create mode 100644 causalize/vg_implementation/causalization_strategy.cpp create mode 100644 causalize/vg_implementation/causalization_strategy.h create mode 100644 causalize/vg_implementation/for_unrolling/process_for_equations.cpp create mode 100644 causalize/vg_implementation/for_unrolling/process_for_equations.h create mode 100644 causalize/vg_implementation/graph/graph_definition.cpp create mode 100644 causalize/vg_implementation/graph/graph_definition.h create mode 100644 causalize/vg_implementation/graph/graph_printer.h create mode 100644 causalize/vg_implementation/main.cpp create mode 100644 causalize/vg_implementation/unknowns_collector.cpp create mode 100644 causalize/vg_implementation/unknowns_collector.h create mode 100644 causalize/vg_implementation/vector/causalization_algorithm.cpp create mode 100644 causalize/vg_implementation/vector/causalization_algorithm.h create mode 100644 causalize/vg_implementation/vector/graph_builder.cpp create mode 100644 causalize/vg_implementation/vector/graph_builder.h create mode 100644 causalize/vg_implementation/vector/splitfor.cpp create mode 100644 causalize/vg_implementation/vector/splitfor.h create mode 100644 causalize/vg_implementation/vector/vector_graph_definition.cpp create mode 100644 causalize/vg_implementation/vector/vector_graph_definition.h create mode 100644 causalize/vg_implementation/vector/vector_matching.cpp create mode 100644 causalize/vg_implementation/vector/vector_matching.h create mode 100644 causalize/vg_implementation/vector/vector_tarjan.cpp create mode 100644 causalize/vg_implementation/vector/vector_tarjan.h create mode 100644 examples/causalize/vector/AdvectionReaction.mo create mode 100644 examples/causalize/vector/AdvectionReaction2D.mo create mode 100644 examples/causalize/vector/AdvectionReaction3D.mo create mode 100644 examples/causalize/vector/AirConditioners.mo create mode 100644 examples/causalize/vector/CascadedFirstOrder.mo create mode 100644 examples/causalize/vector/CocurrentHeatExchangerEquations.mo create mode 100644 examples/causalize/vector/Generator.mo create mode 100644 examples/causalize/vector/HeatingSystemExplicit.mo create mode 100644 examples/causalize/vector/PowerSystem.mo create mode 100644 examples/causalize/vector/SimpleAdvection.mo create mode 100644 examples/causalize/vector/Sintetic/example1.mo create mode 100644 examples/causalize/vector/Sintetic/example10.mo create mode 100644 examples/causalize/vector/Sintetic/example11.mo create mode 100644 examples/causalize/vector/Sintetic/example12.mo create mode 100644 examples/causalize/vector/Sintetic/example13.mo create mode 100644 examples/causalize/vector/Sintetic/example14.mo create mode 100644 examples/causalize/vector/Sintetic/example15.mo create mode 100644 examples/causalize/vector/Sintetic/example2.mo create mode 100644 examples/causalize/vector/Sintetic/example3.mo create mode 100644 examples/causalize/vector/Sintetic/example4.mo create mode 100644 examples/causalize/vector/Sintetic/example5.mo create mode 100644 examples/causalize/vector/Sintetic/example6.mo create mode 100644 examples/causalize/vector/Sintetic/example7.mo create mode 100644 examples/causalize/vector/Sintetic/example8.mo create mode 100644 examples/causalize/vector/Sintetic/example9.mo create mode 100644 examples/causalize/vector/TransmissionLineEquations.mo create mode 100644 test/causalize/ELECTRICALLY_HEATED_ROD.mo create mode 100644 test/causalize/ELECTRICALLY_HEATED_ROD_MULTIDIM.mo create mode 100644 test/causalize/OneDHeatTransferTI_FD_100.mo create mode 100644 test/causalize/OneDHeatTransferTI_FD_complicated.mo create mode 100644 test/causalize/OneDHeatTransferTI_FD_impossible.mo create mode 100644 test/causalize/adventionReaction2D.mo create mode 100644 test/causalize/bug1.mo create mode 100644 test/causalize/bug2.mo create mode 100644 test/causalize/bugVectorial.mo create mode 100644 test/causalize/ecvec.mo create mode 100644 test/causalize/ecvec_newton.mo create mode 100644 test/causalize/ecvec_newton_sol.mo create mode 100644 test/causalize/ejemploKofman.mo create mode 100755 test/causalize/kofman.mo create mode 100644 test/causalize/lazo_newton.mo create mode 100644 test/causalize/lazo_newton_sol.mo create mode 100644 test/causalize/redrc.mo create mode 100644 test/causalize/rlc_circuit.mo create mode 100644 test/causalize/tarjan1.mo create mode 100644 test/causalize/tarjan1.mo.mo create mode 100644 test/causalize/tarjan1b.mo create mode 100644 test/causalize/tarjan1c.mo create mode 100644 test/causalize/tarjan1d.mo create mode 100644 test/causalize/tarjan2.mo create mode 100644 test/causalize/tarjan2D.mo create mode 100644 test/causalize/tarjan2b.mo create mode 100644 test/causalize/tarjan3.mo create mode 100644 test/causalize/tarjan4.mo create mode 100644 test/causalize/tarjan4D.mo create mode 100644 test/causalize/tarjan5.mo create mode 100644 test/causalize/tarjan6.mo create mode 100644 test/causalize/test.mo create mode 100644 test/causalize/test2.mo create mode 100644 test/causalize/test3.mo create mode 100644 test/causalize/testDomRan1.mo create mode 100644 test/causalize/testDomRan2.mo create mode 100644 test/causalize/testDomRan3.mo create mode 100644 test/causalize/testDomRan4.mo create mode 100644 util/ast_visitors/all_expressions.cpp create mode 100644 util/ast_visitors/all_expressions.h create mode 100644 util/ast_visitors/contains_unknown.cpp create mode 100644 util/ast_visitors/contains_unknown.h create mode 100644 util/ast_visitors/contains_vector.cpp create mode 100644 util/ast_visitors/contains_vector.h create mode 100644 util/ast_visitors/replace_index.cpp create mode 100644 util/ast_visitors/replace_index.h diff --git a/Makefile.in b/Makefile.in index 0ebdd99..4c39863 100644 --- a/Makefile.in +++ b/Makefile.in @@ -40,7 +40,7 @@ all: lib-gtest $(LIBMODELICA) include antialias/Makefile.include include mmo/Makefile.include include flatter/Makefile.include -include causalize/graph_implementation/Makefile.include +include causalize/Makefile.include include test/causalize/Makefile.include include test/util/Makefile.include diff --git a/causalize/Makefile.include b/causalize/Makefile.include new file mode 100644 index 0000000..5cc26cd --- /dev/null +++ b/causalize/Makefile.include @@ -0,0 +1,2 @@ +include causalize/graph_implementation/Makefile.include +include causalize/vg_implementation/Makefile.include diff --git a/causalize/graph_implementation/for_unrolling/for_index_iterator.cpp b/causalize/common/for_unrolling/for_index_iterator.cpp similarity index 96% rename from causalize/graph_implementation/for_unrolling/for_index_iterator.cpp rename to causalize/common/for_unrolling/for_index_iterator.cpp index 6680dd9..1fd9ea7 100644 --- a/causalize/graph_implementation/for_unrolling/for_index_iterator.cpp +++ b/causalize/common/for_unrolling/for_index_iterator.cpp @@ -17,7 +17,7 @@ ******************************************************************************/ -#include +#include #include #include #include diff --git a/causalize/graph_implementation/for_unrolling/for_index_iterator.h b/causalize/common/for_unrolling/for_index_iterator.h similarity index 100% rename from causalize/graph_implementation/for_unrolling/for_index_iterator.h rename to causalize/common/for_unrolling/for_index_iterator.h diff --git a/causalize/graph_implementation/for_unrolling/process_for_equations.cpp b/causalize/common/for_unrolling/process_for_equations.cpp similarity index 100% rename from causalize/graph_implementation/for_unrolling/process_for_equations.cpp rename to causalize/common/for_unrolling/process_for_equations.cpp diff --git a/causalize/graph_implementation/for_unrolling/process_for_equations.h b/causalize/common/for_unrolling/process_for_equations.h similarity index 100% rename from causalize/graph_implementation/for_unrolling/process_for_equations.h rename to causalize/common/for_unrolling/process_for_equations.h diff --git a/causalize/graph_implementation/Makefile.include b/causalize/graph_implementation/Makefile.include index 72591b9..d4eb341 100644 --- a/causalize/graph_implementation/Makefile.include +++ b/causalize/graph_implementation/Makefile.include @@ -1,7 +1,5 @@ all: bin/grp_causalize -SRC_CAUSALIZE := causalize/graph_implementation/main.cpp \ - causalize/graph_implementation/for_unrolling/for_index_iterator.cpp \ - causalize/graph_implementation/for_unrolling/process_for_equations.cpp \ +SRC_GRP_CAUSALIZE := causalize/graph_implementation/main.cpp \ causalize/graph_implementation/apply_tarjan.cpp \ causalize/graph_implementation/unknowns_collector.cpp \ causalize/graph_implementation/causalization_strategy.cpp \ @@ -10,6 +8,8 @@ SRC_CAUSALIZE := causalize/graph_implementation/main.cpp \ causalize/graph_implementation/vector/causalization_algorithm.cpp \ causalize/graph_implementation/vector/splitfor.cpp \ causalize/graph_implementation/graph/graph_definition.cpp \ + causalize/common/for_unrolling/for_index_iterator.cpp \ + causalize/common/for_unrolling/process_for_equations.cpp \ util/debug.cpp \ util/table.cpp \ util/type.cpp \ @@ -23,9 +23,9 @@ SRC_CAUSALIZE := causalize/graph_implementation/main.cpp \ mmo/mmo_class.cpp -OBJS_CAUSALIZE = $(SRC_CAUSALIZE:.cpp=.o) +OBJS_GRP_CAUSALIZE = $(SRC_GRP_CAUSALIZE:.cpp=.o) -include $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC_CAUSALIZE))) LIB_CAUSALIZE = -L./lib -lmodelica -lginac -bin/grp_causalize: $(OBJS_CAUSALIZE) lib/libmodelica.a - $(CXX) $(CXXFLAGS) -o bin/grp_causalize $(OBJS_CAUSALIZE) $(LIB_CAUSALIZE) +bin/grp_causalize: $(OBJS_GRP_CAUSALIZE) lib/libmodelica.a + $(CXX) $(CXXFLAGS) -o bin/grp_causalize $(OBJS_GRP_CAUSALIZE) $(LIB_CAUSALIZE) diff --git a/causalize/graph_implementation/apply_tarjan.cpp b/causalize/graph_implementation/apply_tarjan.cpp index 2e7df31..01c252b 100644 --- a/causalize/graph_implementation/apply_tarjan.cpp +++ b/causalize/graph_implementation/apply_tarjan.cpp @@ -17,13 +17,6 @@ ******************************************************************************/ -/* - * apply_tarjan.cpp - * - * Created on: 21/12/2014 - * Author: fede - */ - #include #include diff --git a/causalize/graph_implementation/apply_tarjan.h b/causalize/graph_implementation/apply_tarjan.h index 31b4b85..24a1458 100644 --- a/causalize/graph_implementation/apply_tarjan.h +++ b/causalize/graph_implementation/apply_tarjan.h @@ -17,13 +17,6 @@ ******************************************************************************/ -/* - * apply_tarjan.h - * - * Created on: 21/12/2014 - * Author: fede - */ - #ifndef APPLY_TARJAN_H_ #define APPLY_TARJAN_H_ diff --git a/causalize/graph_implementation/causalization_strategy.cpp b/causalize/graph_implementation/causalization_strategy.cpp index 5de45f3..e7c75cd 100644 --- a/causalize/graph_implementation/causalization_strategy.cpp +++ b/causalize/graph_implementation/causalization_strategy.cpp @@ -17,18 +17,11 @@ ******************************************************************************/ -/* - * causalization_strategy.cpp - * - * Created on: 12/05/2013 - * Author: fede - */ - #include #include #include #include -#include +#include #include #include #include diff --git a/causalize/graph_implementation/causalization_strategy.h b/causalize/graph_implementation/causalization_strategy.h index 190dbcc..1e66c9f 100644 --- a/causalize/graph_implementation/causalization_strategy.h +++ b/causalize/graph_implementation/causalization_strategy.h @@ -17,13 +17,6 @@ ******************************************************************************/ -/* - * causalization_strategy.h - * - * Created on: 12/05/2013 - * Author: fede - */ - #include #include diff --git a/causalize/graph_implementation/graph/graph_definition.cpp b/causalize/graph_implementation/graph/graph_definition.cpp index 2ab998c..e6423de 100644 --- a/causalize/graph_implementation/graph/graph_definition.cpp +++ b/causalize/graph_implementation/graph/graph_definition.cpp @@ -17,11 +17,6 @@ ******************************************************************************/ -/* - * Created on: 21 jul. 2016 - * Author: Diego Hollmann - */ - #include #include #include diff --git a/causalize/graph_implementation/main.cpp b/causalize/graph_implementation/main.cpp index 8a6770e..e0d0122 100644 --- a/causalize/graph_implementation/main.cpp +++ b/causalize/graph_implementation/main.cpp @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/causalize/graph_implementation/unknowns_collector.cpp b/causalize/graph_implementation/unknowns_collector.cpp index 46ef501..a76c2ea 100644 --- a/causalize/graph_implementation/unknowns_collector.cpp +++ b/causalize/graph_implementation/unknowns_collector.cpp @@ -17,13 +17,6 @@ ******************************************************************************/ -/* - * collect_unknowns.cpp - * - * Created on: 29/04/2013 - * Author: fede - */ - #include #include #include diff --git a/causalize/graph_implementation/vector/causalization_algorithm.cpp b/causalize/graph_implementation/vector/causalization_algorithm.cpp index 9b8005b..cdcd5cb 100644 --- a/causalize/graph_implementation/vector/causalization_algorithm.cpp +++ b/causalize/graph_implementation/vector/causalization_algorithm.cpp @@ -21,7 +21,7 @@ #include #define HAS_COUNT #include -#include +#include #include #include #include diff --git a/causalize/vg_implementation/Makefile.include b/causalize/vg_implementation/Makefile.include new file mode 100644 index 0000000..745ac29 --- /dev/null +++ b/causalize/vg_implementation/Makefile.include @@ -0,0 +1,35 @@ +all: bin/vg_causalize +SRC_VG_CAUSALIZE := causalize/vg_implementation/main.cpp \ + causalize/vg_implementation/apply_tarjan.cpp \ + causalize/vg_implementation/unknowns_collector.cpp \ + causalize/vg_implementation/causalization_strategy.cpp \ + causalize/vg_implementation/vector/graph_builder.cpp \ + causalize/vg_implementation/vector/causalization_algorithm.cpp \ + causalize/vg_implementation/vector/splitfor.cpp \ + causalize/vg_implementation/vector/vector_graph_definition.cpp \ + causalize/vg_implementation/vector/vector_tarjan.cpp \ + causalize/vg_implementation/vector/vector_matching.cpp \ + causalize/vg_implementation/graph/graph_definition.cpp \ + causalize/vg_implementation/for_unrolling/process_for_equations.cpp \ + causalize/common/for_unrolling/for_index_iterator.cpp \ + util/debug.cpp \ + util/table.cpp \ + util/type.cpp \ + util/solve/solve.cpp \ + util/ast_visitors/contains_unknown.cpp \ + util/ast_visitors/contains_vector.cpp \ + util/ast_visitors/eval_expression.cpp \ + util/ast_visitors/partial_eval_expression.cpp \ + util/ast_visitors/ginac_interface.cpp \ + util/ast_visitors/contains_expression.cpp \ + util/ast_visitors/splitfor_visitor.cpp \ + util/ast_visitors/state_variables_finder.cpp \ + mmo/mmo_class.cpp + + +OBJS_VG_CAUSALIZE = $(SRC_VG_CAUSALIZE:.cpp=.o) +-include $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRC_CAUSALIZE))) +LIB_CAUSALIZE = -L./lib -lmodelica -lginac + +bin/vg_causalize: $(OBJS_VG_CAUSALIZE) lib/libmodelica.a + $(CXX) $(CXXFLAGS) -o bin/vg_causalize $(OBJS_VG_CAUSALIZE) $(LIB_CAUSALIZE) diff --git a/causalize/vg_implementation/apply_tarjan.cpp b/causalize/vg_implementation/apply_tarjan.cpp new file mode 100644 index 0000000..f648e84 --- /dev/null +++ b/causalize/vg_implementation/apply_tarjan.cpp @@ -0,0 +1,180 @@ +/***************************************************************************** + + 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 + +namespace Causalize { +typedef boost::adjacency_list DirectedGraph; +typedef boost::graph_traits::vertex_descriptor DGVertex; +typedef boost::graph_traits::edge_descriptor DGEdge; + +std::map _matching; +std::map _collapsed2original; +using namespace Causalize; + +DGVertex original2collapsed(Vertex value) +{ + std::map::iterator it; + for (it = _collapsed2original.begin(); it != _collapsed2original.end(); it++) { + if ((*it).second == value) { + return (*it).first; + } + } + ERROR("Can't find collapsed vertex from original."); + return (*it).first; +} + +void buildCollapsedGraph(Causalize::CausalizationGraph &graph, DirectedGraph &digraph) +{ + // Create the vertices on the directed graph + Causalize::CausalizationGraph::vertex_iterator vi, vi_end; + for (boost::tie(vi, vi_end) = vertices(graph); vi != vi_end; ++vi) { + if (graph[*vi].type == kVertexEquation) { + DGVertex v = add_vertex(digraph); + _collapsed2original[v] = *vi; + } + } + // Create the edges on the directed graph + DirectedGraph::vertex_iterator vj, vj_end; + for (boost::tie(vj, vj_end) = vertices(digraph); vj != vj_end; ++vj) { + CausalizationGraph::out_edge_iterator ek, ek_end; + Vertex originalEqVertex = _collapsed2original[*vj]; + Vertex uMatchingVertex = _matching[originalEqVertex]; + for (boost::tie(ek, ek_end) = out_edges(uMatchingVertex, graph); ek != ek_end; ++ek) { + Vertex eqAdjacentVertex = target(*ek, graph); + if (eqAdjacentVertex != originalEqVertex) { + boost::add_edge(original2collapsed(eqAdjacentVertex), *vj, digraph); + } + } + } +} + +// void replaceMMOClassEquations(MMO_Class mmoClass, MMO_EquationList causalEqs) { +// MMO_EquationList oldEquations = mmoClass->getEquations(); +// MMO_EquationListIterator iter, auxiliaryIter; +// auxiliaryIter = oldEquations->begin(); +// for(iter = auxiliaryIter; iter != oldEquations->end(); iter = auxiliaryIter) { +// ++auxiliaryIter; +// mmoClass->removeEquation(current_element(iter)); +// } +// foreach(iter, causalEqs) { +// mmoClass->addEquation(current_element(iter)); +// } +//} + +int apply_tarjan(CausalizationGraph &graph, std::map &components) +{ + boost::associative_property_map> matching_map(_matching); + + // Vertex Index Map required for checked_edmonds_maximum_cardinality_matching. + // This is to allow the causalization graph, which is an adjacency list, to + // use as VertexList either vecS or listS. + std::map vertex2index; + CausalizationGraph::vertex_iterator i, iend; + int ic = 0; + for (boost::tie(i, iend) = vertices(graph); i != iend; ++i, ++ic) { + vertex2index[*i] = ic; + } + boost::associative_property_map> index_map(vertex2index); + + DEBUG('c', "Calculating maximum cardinality matching over causalization graph...\n"); + + bool success = checked_edmonds_maximum_cardinality_matching(graph, matching_map, index_map); + if (!success) { + ERROR("Can't find a maximum cardinality matching.\n"); + } + + for (std::map::iterator it = _matching.begin(); it != _matching.end(); ++it) { + char se[10]; + Vertex v1 = it->first; + if (graph[v1].type == kVertexEquation) { + sprintf(se, "E%d", vertex2index[v1]); + } else { + sprintf(se, "U%d", vertex2index[v1]); + } + char su[10]; + Vertex v2 = it->second; + if (graph[v2].type == kVertexEquation) { + sprintf(su, "E%d", vertex2index[v2]); + } else { + sprintf(su, "U%d", vertex2index[v2]); + } + DEBUG('c', "%s matches %s\n", se, su); + } + + DirectedGraph collapsedGraph; + + DEBUG('c', "Collapsing matching vertices...\n"); + + buildCollapsedGraph(graph, collapsedGraph); + + std::map vertex2component; + boost::associative_property_map> component_map(vertex2component); + std::map dg_vertex2index; + DirectedGraph::vertex_iterator j, jend; + int jc = 0; + for (boost::tie(j, jend) = vertices(collapsedGraph); j != jend; ++j, ++jc) { + dg_vertex2index[*j] = jc; + } + boost::associative_property_map> dg_index_map(dg_vertex2index); + + DEBUG('c', "Running tarjan algorithm over collapsed graph...\n"); + + int numComponents = strong_components(collapsedGraph, component_map, boost::vertex_index_map(dg_index_map)); + + DEBUG('c', "%d strong components identifed.\n", numComponents); + + for (std::map::iterator it = vertex2component.begin(); it != vertex2component.end(); ++it) { + DGVertex dgVertex = it->first; + int componentIndex = it->second; + DEBUG('c', "Vertex: %d -- Component: %d\n", dg_vertex2index[dgVertex], componentIndex); + Vertex eqVertex = _collapsed2original[dgVertex]; + Vertex uVertex = _matching[eqVertex]; + std::map::iterator componentsIt = components.find(componentIndex); + if (componentsIt == components.end()) { + Causalize::ComponentPtr component = new Causalize::Component; + std::list *uVertices = new std::list; + uVertices->push_back(uVertex); + component->uVertices = uVertices; + std::list *eqVertices = new std::list; + eqVertices->push_back(eqVertex); + component->eqVertices = eqVertices; + components[componentIndex] = component; + } else { + Causalize::ComponentPtr component = componentsIt->second; + std::list *uVertices = component->uVertices; + uVertices->push_back(uVertex); + std::list *eqVertices = component->eqVertices; + eqVertices->push_back(eqVertex); + } + } + + return components.size(); +} + +} // namespace Causalize diff --git a/causalize/vg_implementation/apply_tarjan.h b/causalize/vg_implementation/apply_tarjan.h new file mode 100644 index 0000000..b39184b --- /dev/null +++ b/causalize/vg_implementation/apply_tarjan.h @@ -0,0 +1,37 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#ifndef APPLY_TARJAN_H_ +#define APPLY_TARJAN_H_ + +#include +#include +#include +#include + +namespace Causalize { +struct Component { + std::list *uVertices; + std::list *eqVertices; +}; +typedef Component *ComponentPtr; +int apply_tarjan(CausalizationGraph &graph, std::map &components); +} // namespace Causalize + +#endif /* APPLY_TARJAN_H_ */ diff --git a/causalize/vg_implementation/causalization_strategy.cpp b/causalize/vg_implementation/causalization_strategy.cpp new file mode 100644 index 0000000..d66a4e2 --- /dev/null +++ b/causalize/vg_implementation/causalization_strategy.cpp @@ -0,0 +1,374 @@ +/***************************************************************************** + + 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 +#include +#include +#include +#include +#include +#include +#include +#include + +extern bool solve; +using namespace Modelica; +using namespace Modelica::AST; + +namespace Causalize { +CausalizationStrategy::CausalizationStrategy(MMO_Class &mmo_class) : _mmo_class(mmo_class) +{ + Causalize::process_for_equations(mmo_class); + + const EquationList &equations = mmo_class.equations_ref().equations_ref(); + + UnknownsCollector collector(mmo_class); + ExpList unknowns = collector.collectUnknowns(); + + if (equations.size() != unknowns.size()) { + ERROR( + "The model being causalized is not balanced.\n" + "There are %d equations and %d variables\n", + equations.size(), unknowns.size()); + } + + int index = 0; + + _all_unknowns = unknowns; + + std::list eqVerts; + std::vector unknownVerts; + + DEBUG('c', "Building causalization graph...\n"); + DEBUG('c', "Equation indexes:\n"); + + // Create equation vertexes + foreach_(Equation e, equations) + { + VertexProperty vp; + Equality &eq = get(e); + PartialEvalExpression eval(_mmo_class.syms_ref(), false); + eq.left_ref() = Apply(eval, eq.left_ref()); + eq.right_ref() = Apply(eval, eq.right_ref()); + vp.equation = e; + vp.type = kVertexEquation; + vp.index = index++; + vp.visited = false; + Vertex v = add_vertex(vp, _graph); + eqVerts.push_back(v); + if (debugIsEnabled('c')) cout << vp.index << ":" << e << endl; + } + + DEBUG('c', "Unknown indexes:\n"); + + // Create unknown vertexes + index = 0; + foreach_(Expression e, unknowns) + { + VertexProperty vp; + vp.unknown = Unknown(e); + vp.type = kVertexUnknown; + vp.index = index++; + vp.visited = false; + Vertex v = add_vertex(vp, _graph); + unknownVerts.push_back(v); + if (debugIsEnabled('c')) cout << vp.index << ":" << e << endl; + } + + DEBUG('c', "Graph edges as (equation_index, uknown_index):\n"); + + // Create edges + std::vector definedUnks; + for (Vertex v : unknownVerts) { + definedUnks.push_back(_graph[v].unknown()); + } + ContainsUnknown occurrs(definedUnks, _mmo_class.syms()); + foreach_(const Vertex &eqVertex, eqVerts) + { + Equation &e = _graph[eqVertex].equation; + ERROR_UNLESS(is(e), "Causalization of non-equality equation is not supported"); + Equality &eq = boost::get(e); + const bool rl = Apply(occurrs, eq.left_ref()); + const bool ll = Apply(occurrs, eq.right_ref()); + if (rl || ll) { + for (int u : occurrs.getUsages()) { + add_edge(eqVertex, unknownVerts[u], _graph); + DEBUG('c', "(%d, %d) ", _graph[eqVertex].index, _graph[unknownVerts[u]].index); + } + } + occurrs.clear(); + } + + DEBUG('c', "\n"); + + _causalEqsEnd.resize(equations.size()); + _causalEqsEndIndex = equations.size() - 1; + + // GraphPrinter gp(_graph); + // gp.printGraph("initial_graph.dot"); +} + +void CausalizationStrategy::Causalize() +{ + DEBUG('p', "Graph size before Simple strategy:%d\n", num_vertices(_graph)); + + SimpleCausalizationStrategy(); + + int graph_size = num_vertices(_graph); + + DEBUG('p', "Graph size after Simple strategy:%d\n", graph_size); + + if (graph_size > 0) { // graph still has vertices + MakeCausalMiddle(); + _causalEqsBegining.insert(_causalEqsBegining.end(), _causalEqsMiddle.begin(), _causalEqsMiddle.end()); + } + + for (size_t i = _causalEqsEndIndex + 1; i < _causalEqsEnd.size(); ++i) { + _causalEqsBegining.insert(_causalEqsBegining.end(), _causalEqsEnd[i]); + } + + _mmo_class.equations_ref().equations_ref() = _causalEqsBegining; + + // Add new functions + foreach_(ClassType ct, _cl) + { + Class c = get(ct); + _mmo_class.types_ref().push_back(c.name()); + MMO_Class *mmo = new MMO_Class(c); + _mmo_class.tyTable_ref().insert(c.name(), Type::Class(c.name(), mmo)); + } + std::stringstream s; + s << _mmo_class.name() << ".c"; + std::fstream fs(s.str().c_str(), std::fstream::out); + fs << "#include \n"; + fs << "#define pre(X) X\n"; + foreach_(std::string s, c_code) fs << s; + fs.close(); +} + +void CausalizationStrategy::CausalizeSimple() +{ + SimpleCausalizationStrategy(); + + for (size_t i = _causalEqsEndIndex + 1; i < _causalEqsEnd.size(); ++i) { + _causalEqsBegining.insert(_causalEqsBegining.end(), _causalEqsEnd[i]); + } + + _mmo_class.equations_ref().equations_ref() = _causalEqsBegining; + + // Add new functions + foreach_(ClassType ct, _cl) + { + Class c = get(ct); + _mmo_class.types_ref().push_back(c.name()); + MMO_Class *mmo = new MMO_Class(c); + _mmo_class.tyTable_ref().insert(c.name(), Type::Class(c.name(), mmo)); + } + std::stringstream s; + s << _mmo_class.name() << ".c"; + std::fstream fs(s.str().c_str(), std::fstream::out); + fs << "#include \n"; + fs << "#define pre(X) X\n"; + foreach_(std::string s, c_code) fs << s; + fs.close(); +} + +void CausalizationStrategy::CausalizeTarjan() +{ + MakeCausalMiddle(); + + _causalEqsBegining.insert(_causalEqsBegining.end(), _causalEqsMiddle.begin(), _causalEqsMiddle.end()); + + _mmo_class.equations_ref().equations_ref() = _causalEqsBegining; + + // Add new functions + foreach_(ClassType ct, _cl) + { + Class c = get(ct); + _mmo_class.types_ref().push_back(c.name()); + MMO_Class *mmo = new MMO_Class(c); + _mmo_class.tyTable_ref().insert(c.name(), Type::Class(c.name(), mmo)); + } + std::stringstream s; + s << _mmo_class.name() << ".c"; + std::fstream fs(s.str().c_str(), std::fstream::out); + fs << "#include \n"; + fs << "#define pre(X) X\n"; + foreach_(std::string s, c_code) fs << s; + fs.close(); +} + +void CausalizationStrategy::SimpleCausalizationStrategy() +{ + std::list eqDegree1Verts; + std::list unknownDegree1Verts; + + CausalizationGraph::vertex_iterator vi, vi_end; + for (boost::tie(vi, vi_end) = vertices(_graph); vi != vi_end; ++vi) { + Vertex v = *vi; + if (out_degree(v, _graph) == 1 && !_graph[v].visited) { + Edge e = GetUniqueEdge(v); + Vertex adjacent = target(e, _graph); + _graph[adjacent].visited = true; + if (_graph[v].type == kVertexEquation) { + eqDegree1Verts.push_back(v); + } else { + unknownDegree1Verts.push_back(v); + } + } + } + + while (!eqDegree1Verts.empty() || !unknownDegree1Verts.empty()) { + std::list::iterator eqIter = eqDegree1Verts.begin(); + if (eqIter != eqDegree1Verts.end()) { + Vertex eq = *eqIter; + Edge e = GetUniqueEdge(eq); + Vertex unknown = target(e, _graph); + MakeCausalBegining(_graph[eq].equation, _graph[unknown].unknown()); + remove_edge(e, _graph); + remove_vertex(eq, _graph); + CollectDegree1Verts(unknown, eqDegree1Verts); + remove_vertex(unknown, _graph); + eqDegree1Verts.erase(eqIter); + } + + std::list::iterator unknownIter = unknownDegree1Verts.begin(); + if (unknownIter != unknownDegree1Verts.end()) { + Vertex unknown = *unknownIter; + Edge e = GetUniqueEdge(unknown); + Vertex eq = target(e, _graph); + MakeCausalEnd(_graph[eq].equation, _graph[unknown].unknown()); + remove_edge(e, _graph); + remove_vertex(unknown, _graph); + CollectDegree1Verts(eq, unknownDegree1Verts); + remove_vertex(eq, _graph); + unknownDegree1Verts.erase(unknownIter); + } + } +} + +Edge CausalizationStrategy::GetUniqueEdge(Vertex v) +{ + CausalizationGraph::out_edge_iterator eqOutEdgeIter, eqOutEdgeIterEnd; + boost::tie(eqOutEdgeIter, eqOutEdgeIterEnd) = out_edges(v, _graph); + return *eqOutEdgeIter; +} + +void CausalizationStrategy::CollectDegree1Verts(Vertex v, std::list °ree1Verts) +{ + CausalizationGraph::out_edge_iterator outEdgeIter, outEdgeIterEnd, next; + boost::tie(outEdgeIter, outEdgeIterEnd) = out_edges(v, _graph); + for (next = outEdgeIter; outEdgeIter != outEdgeIterEnd; outEdgeIter = next) { + next++; + Edge adjEdge = *outEdgeIter; + Vertex adjacent = target(adjEdge, _graph); + remove_edge(adjEdge, _graph); + if (out_degree(adjacent, _graph) == 1 && !_graph[adjacent].visited) { + Edge e = GetUniqueEdge(adjacent); + Vertex adjAdjacent = target(e, _graph); + _graph[adjAdjacent].visited = true; + degree1Verts.push_back(adjacent); + } + } +} + +void CausalizationStrategy::MakeCausalBegining(Equation e, Expression unknown) +{ + if (debugIsEnabled('c')) { + cout << "MakeCausalBegining" << endl; + cout << "Causalizing "; + cout << " " << unknown; + cout << std::endl; + cout << "Using "; + cout << std::endl << e; + cout << std::endl; + } + if (solve) { + std::stringstream s; + s << _mmo_class.name() << ".c"; + Equation causalEq = EquationSolver::Solve(e, unknown, _mmo_class.syms_ref(), c_code, _cl, s.str()); + _causalEqsBegining.push_back(causalEq); + } +} + +void CausalizationStrategy::MakeCausalEnd(Equation e, Expression unknown) +{ + if (debugIsEnabled('c')) { + cout << "MakeCausalEnd" << endl; + cout << "Causalizing"; + cout << " " << unknown; + cout << std::endl; + cout << "Using "; + cout << std::endl << e; + cout << std::endl; + } + + if (solve) { + std::stringstream s; + s << _mmo_class.name() << ".c"; + Equation causalEq = EquationSolver::Solve(e, unknown, _mmo_class.syms_ref(), c_code, _cl, s.str()); + _causalEqsEnd[_causalEqsEndIndex--] = causalEq; + } +} + +/** + * Applies tarjan algorithm + */ +void CausalizationStrategy::MakeCausalMiddle() +{ + std::map components; + + int n_comps = apply_tarjan(_graph, components); + + for (int i = 0; i < n_comps; i++) { + ComponentPtr component = components[i]; + + std::list *uVertices = component->uVertices; + ExpList unknowns; + std::list::iterator uIt; + for (uIt = uVertices->begin(); uIt != uVertices->end(); uIt++) { + Vertex v = *uIt; + Expression unknown = _graph[v].unknown(); + unknowns.push_back(unknown); + } + + std::list *eqVertices = component->eqVertices; + EquationList eqs; + std::list::iterator eqIt; + for (eqIt = eqVertices->begin(); eqIt != eqVertices->end(); eqIt++) { + Vertex v = *eqIt; + Equation eq = _graph[v].equation; + eqs.push_back(eq); + } + + std::stringstream s; + s << _mmo_class.name() << ".c"; + EquationList causalEqs = EquationSolver::Solve(eqs, unknowns, _mmo_class.syms_ref(), c_code, _cl, s.str()); + _causalEqsMiddle.insert(_causalEqsMiddle.end(), causalEqs.begin(), causalEqs.end()); + } +} +} // namespace Causalize diff --git a/causalize/vg_implementation/causalization_strategy.h b/causalize/vg_implementation/causalization_strategy.h new file mode 100644 index 0000000..8d73e28 --- /dev/null +++ b/causalize/vg_implementation/causalization_strategy.h @@ -0,0 +1,49 @@ +/***************************************************************************** + + 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 CausalizationStrategy { + public: + CausalizationStrategy(Modelica::MMO_Class &mmo_class); + void Causalize(); + void CausalizeSimple(); + void CausalizeTarjan(); + + private: + void SimpleCausalizationStrategy(); + Edge GetUniqueEdge(Vertex v); + void CollectDegree1Verts(Vertex v, std::list °ree1Verts); + void MakeCausalBegining(Modelica::AST::Equation eq, Modelica::AST::Expression unknown); + void MakeCausalMiddle(); + void MakeCausalEnd(Modelica::AST::Equation eq, Modelica::AST::Expression unknown); + + CausalizationGraph _graph; + Modelica::MMO_Class &_mmo_class; + Modelica::AST::EquationList _causalEqsBegining; + Modelica::AST::EquationList _causalEqsMiddle; + std::vector _causalEqsEnd; + int _causalEqsEndIndex; + Modelica::AST::ClassList _cl; + Modelica::AST::ExpList _all_unknowns; + std::list c_code; +}; +} // namespace Causalize diff --git a/causalize/vg_implementation/for_unrolling/process_for_equations.cpp b/causalize/vg_implementation/for_unrolling/process_for_equations.cpp new file mode 100644 index 0000000..0089360 --- /dev/null +++ b/causalize/vg_implementation/for_unrolling/process_for_equations.cpp @@ -0,0 +1,216 @@ +/***************************************************************************** + + 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 + +namespace Causalize { + +Equation instantiate_equation(Equation innerEq, std::list variables, std::list indexes, VarSymbolTable &symbolTable) { + VarSymbolTable v=symbolTable; + ERROR_UNLESS(variables.size()==indexes.size(), "Mismatch size of variables and indexes size"); + std::list::iterator varsIter = variables.begin(); + foreach_(int i, indexes) { + VarInfo vinfo = VarInfo(TypePrefixes(1,parameter), "Integer", Option(), Modification(ModEq(Expression(i)))); + v.insert(*varsIter,vinfo); + varsIter++; + } + if (is(innerEq)) { + Equality eqeq = boost::get(innerEq); + Expression l=eqeq.left(), r=eqeq.right(); + //std::cout << "Left= " << l << " right " << r << std::endl; + return Equality(Apply(Modelica::PartialEvalExpression(v),l),Apply(Modelica::PartialEvalExpression(v),r)); + } else { + ERROR("process_for_equations - instantiate_equation:\n" + "Incorrect equation type or not supported yet.\n"); + } + return Equation(); +} + +void process_for_equations(Modelica::MMO_Class &mmo_class) { + EquationList &equations = mmo_class.equations_ref().equations_ref(); + EquationList new_equations; + foreach_ (Equation &e, equations) { + if (is(e)) { + ForEq feq = boost::get(e); + IndexList il = feq.range().indexes(); + ERROR_UNLESS(il.size() <= 3, + "process_for_equations:\n" + "forIndexList with more than 3 forIndex are not supported yet\n"); + EquationList processedEqs; + switch (il.size()) { + case 1: + processedEqs = process_for_eq_1d(feq, mmo_class.syms_ref()); + break; + case 2: + processedEqs = process_for_eq_2d(feq, mmo_class.syms_ref()); + break; + case 3: + processedEqs = process_for_eq_3d(feq, mmo_class.syms_ref()); + break; + } + new_equations.insert(new_equations.end(), processedEqs.begin(), processedEqs.end()); + } else { + // Not a for eq + new_equations.push_back(e); + } + + } + mmo_class.equations_ref().equations_ref()=new_equations; +} + +EquationList process_for_eq_1d(ForEq feq, VarSymbolTable &symbolTable) { + IndexList il = feq.range().indexes(); + Index in = il.front(); + Name variable = in.name(); + OptExp ind = in.exp(); + if (!ind) + ERROR("for-equation's index with implicit range not supported yet\n"); + Expression exp = ind.get(); + ForIndexIterator *forIndexIter = NULL; + if (is(exp)) { + forIndexIter = new RangeIterator(get(exp), symbolTable); + } else if (is(exp)) { + forIndexIter = new BraceIterator(get(exp), symbolTable); + } else { + ERROR("For Iterator not supported"); + } + EquationList processed; + while (forIndexIter->hasNext()) { + Real index_val = forIndexIter->next(); + foreach_ (Equation eq, feq.elements()) + processed.push_back(instantiate_equation(eq, std::list(1,variable), std::list(1,index_val), symbolTable)); + } + delete forIndexIter; + return processed; +} + +EquationList process_for_eq_2d(ForEq feq, VarSymbolTable &symbolTable) { + IndexList il = feq.range().indexes(); + Index in1 = il[0]; + Index in2 = il[1]; + Name variable1 = in1.name(); + Name variable2 = in2.name(); + OptExp ind1 = in1.exp(); + OptExp ind2 = in2.exp(); + if (!ind1||!ind2) + ERROR("for-equation's index with implicit range not supported yet\n"); + Expression exp1 = ind1.get(); + Expression exp2 = ind2.get(); + ForIndexIterator *forIndexIter1 = NULL; + ForIndexIterator *forIndexIter2 = NULL; + if (is(exp1)) { + forIndexIter1 = new RangeIterator(get(exp1), symbolTable); + } else if (is(exp1)) { + forIndexIter1 = new BraceIterator(get(exp1), symbolTable); + } else { + ERROR("For Iterator not supported"); + } + EquationList processed; + while (forIndexIter1->hasNext()) { + int index_val1 = forIndexIter1->next(); + if (is(exp2)) { + forIndexIter2 = new RangeIterator(get(exp2), symbolTable); + } else if (is(exp2)) { + forIndexIter2 = new BraceIterator(get(exp2), symbolTable); + } else { + ERROR("For Iterator not supported"); + } + while (forIndexIter2->hasNext()) { + int index_val2 = forIndexIter2->next(); + foreach_ (Equation eq, feq.elements()) + processed.push_back(instantiate_equation(eq, {variable1, variable2}, {index_val1, index_val2}, symbolTable)); + } + } + delete forIndexIter1; + delete forIndexIter2; + return processed; +} + +EquationList process_for_eq_3d(ForEq feq, VarSymbolTable &symbolTable) { + IndexList il = feq.range().indexes(); + Index in1 = il[0]; + Index in2 = il[1]; + Index in3 = il[2]; + Name variable1 = in1.name(); + Name variable2 = in2.name(); + Name variable3 = in3.name(); + OptExp ind1 = in1.exp(); + OptExp ind2 = in2.exp(); + OptExp ind3 = in3.exp(); + if (!ind1||!ind2||!ind3) + ERROR("for-equation's index with implicit range not supported yet\n"); + Expression exp1 = ind1.get(); + Expression exp2 = ind2.get(); + Expression exp3 = ind3.get(); + ForIndexIterator *forIndexIter1 = NULL; + ForIndexIterator *forIndexIter2 = NULL; + ForIndexIterator *forIndexIter3 = NULL; + if (is(exp1)) { + forIndexIter1 = new RangeIterator(get(exp1), symbolTable); + } else if (is(exp1)) { + forIndexIter1 = new BraceIterator(get(exp1), symbolTable); + } else { + ERROR("For Iterator not supported"); + } + EquationList processed; + while (forIndexIter1->hasNext()) { + int index_val1 = forIndexIter1->next(); + if (is(exp2)) { + forIndexIter2 = new RangeIterator(get(exp2), symbolTable); + } else if (is(exp2)) { + forIndexIter2 = new BraceIterator(get(exp2), symbolTable); + } else { + ERROR("For Iterator not supported"); + } + while (forIndexIter2->hasNext()) { + int index_val2 = forIndexIter2->next(); + if (is(exp3)) { + forIndexIter3 = new RangeIterator(get(exp3), symbolTable); + } else if (is(exp3)) { + forIndexIter3 = new BraceIterator(get(exp3), symbolTable); + } else { + ERROR("For Iterator not supported"); + } + while (forIndexIter3->hasNext()) { + int index_val3 = forIndexIter3->next(); + foreach_ (Equation eq, feq.elements()) + processed.push_back(instantiate_equation(eq, {variable1, variable2, variable3}, {index_val1, index_val2, index_val3}, symbolTable)); + } + } + } + delete forIndexIter1; + delete forIndexIter2; + delete forIndexIter3; + return processed; +} + +} + + + + diff --git a/causalize/vg_implementation/for_unrolling/process_for_equations.h b/causalize/vg_implementation/for_unrolling/process_for_equations.h new file mode 100644 index 0000000..c74d932 --- /dev/null +++ b/causalize/vg_implementation/for_unrolling/process_for_equations.h @@ -0,0 +1,33 @@ +/***************************************************************************** + + 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 + +/** + * Performs a loop unrolling over the for-equations + * decleared on the equation section of the class. + */ + +namespace Causalize { + void process_for_equations(Modelica::MMO_Class &mmo_class); + EquationList process_for_eq_1d(ForEq, VarSymbolTable &); + EquationList process_for_eq_2d(ForEq, VarSymbolTable &); + EquationList process_for_eq_3d(ForEq, VarSymbolTable &); + Equation instantiate_equation(Equation, std::list, std::list, VarSymbolTable &); +} diff --git a/causalize/vg_implementation/graph/graph_definition.cpp b/causalize/vg_implementation/graph/graph_definition.cpp new file mode 100644 index 0000000..0bbe573 --- /dev/null +++ b/causalize/vg_implementation/graph/graph_definition.cpp @@ -0,0 +1,40 @@ +/***************************************************************************** + + 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 + +namespace Causalize { + +Unknown::Unknown() {} + +Unknown::Unknown(Modelica::AST::Expression exp): expression(exp) {} + +Unknown::Unknown(VarInfo varInfo, Modelica::AST::Reference var) { + if (varInfo.state()) { + expression = Modelica::AST::Call("der",Modelica::AST::Reference(var)); + } else { + expression = Modelica::AST::Reference(var); + } +} + +Expression Unknown::operator() () const { + return expression; +} + +} diff --git a/causalize/vg_implementation/graph/graph_definition.h b/causalize/vg_implementation/graph/graph_definition.h new file mode 100644 index 0000000..a107ebb --- /dev/null +++ b/causalize/vg_implementation/graph/graph_definition.h @@ -0,0 +1,77 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#ifndef GRAPH_DEFINITION_ +#define GRAPH_DEFINITION_ + +#include +#include +#include +#include + +#include +#include + +namespace Causalize { + /// @brief Vertex in the incidence graph can be either Equations or Unknowns. This type is used for distinguish between them + enum VertexType {kVertexEquation, kVertexUnknown, kNilVertex}; + + struct Unknown { + Modelica::AST::Expression expression; + Unknown(); + Unknown(Modelica::AST::Expression exp); + Unknown(VarInfo varInfo, Modelica::AST::Reference var); + Expression operator() () const; + }; + + + /// @brief This is the property for a vertex in the incidence graph. Nodes can be of two types: Equation or Unknown. + struct VertexProperty { + VertexType type; + /// @brief This is used for debugging purposes + int index; + + bool visited; + /// @brief This holds the unknown in the case of a Unknown node. + Unknown unknown; + /// @brief This holds the equation in the case of a Equation node. + Modelica::AST::Equation equation; + }; + + /// @brief Empty edge properties for incidence graph + struct EdgeProperty { + friend std::ostream & operator << (std::ostream &os, const EdgeProperty &ep) { + os << ""; + return os; + } + }; + + /// @brief This is the definition of the Incidence graph for the scalar case. + typedef boost::adjacency_list CausalizationGraph; + /// @brief A vertex of the Incidence graph + typedef Causalize::CausalizationGraph::vertex_descriptor Vertex; + /// @brief An equation vertex is the same as a regular vertex + typedef Vertex EquationVertex; + /// @brief An unknown vertex is the same as a regular vertex + typedef Vertex UnknownVertex; + /// @brief This is an edge of the scalar causalization graph + typedef CausalizationGraph::edge_descriptor Edge; + +} +#endif diff --git a/causalize/vg_implementation/graph/graph_printer.h b/causalize/vg_implementation/graph/graph_printer.h new file mode 100644 index 0000000..e64f4ab --- /dev/null +++ b/causalize/vg_implementation/graph/graph_printer.h @@ -0,0 +1,263 @@ +/***************************************************************************** + + 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 + + +using namespace std; +using namespace boost::icl; +#define MAKE_SPACE for(int __i=0; __i + class GraphPrinter{ + + typedef boost::adjacency_list Graph; + typedef typename boost::adjacency_list::vertex_descriptor Vertex; + typedef typename boost::adjacency_list::out_edge_iterator EdgeIterator; + + public: + GraphPrinter(const Graph &g): graph(g) { + typename Graph::vertex_iterator vi, vi_end; + for(tie(vi, vi_end) = vertices(graph); vi!= vi_end; vi++){ + if(graph[*vi].type == kVertexEquation){ + equationDescriptors.push_back(*vi); + }else{ + unknownDescriptors.push_back(*vi); + } + } + }; + + void printGraph(std::string name) { + stringstream stri; + ofstream out(name.c_str()); + int depth = 0; + typedef typename list::iterator Iterator; + + stri << "graph G{" << endl; + INSERT_TAB + MAKE_SPACE + stri << " rankdir=LR" << endl; + stri << " ratio=\"fill\"" << endl; + //~ stri << " edge[style=\"bold\"]" << endl; + stri << " node[shape=\"ellipse\"]" << endl; + INSERT_TAB + MAKE_SPACE + //stringstream colors2; + for(Iterator it=equationDescriptors.begin(); it!=equationDescriptors.end(); it++){ + MAKE_SPACE +#ifdef HAS_COUNT + stri << "eq" << graph[*it].index << " [label=\"Eq. " << graph[*it].index+1 << "\nCount=" << graph[*it].count << "\"];" << endl; +#else + stri << "eq" << graph[*it].index << " [label=\"Eq. " << graph[*it].index+1 << "\"];" << endl; + +#endif + } + //~ stri << colors2.str(); + DELETE_TAB + DELETE_TAB + + + INSERT_TAB + INSERT_TAB + stringstream colors; + for(Iterator it=unknownDescriptors.begin(); it!=unknownDescriptors.end(); it++){ + MAKE_SPACE +#ifdef HAS_COUNT + stri << "var" << graph[*it].index << " [ label = \"" << graph[*it].unknown() << "\nCount=" << graph[*it].count << "\"];" << endl; +#else + stri << "var" << graph[*it].index << " [ label = \"" << graph[*it].unknown() << "\"];" << endl; +#endif + } + DELETE_TAB + MAKE_SPACE + stri << colors.str(); + DELETE_TAB + + INSERT_TAB + MAKE_SPACE + for(Iterator eq_it = equationDescriptors.begin(); eq_it != equationDescriptors.end(); eq_it++){ + EdgeIterator ei, ei_end; + for(tie(ei, ei_end) = out_edges(*eq_it, graph); ei != ei_end; ei++){ + Vertex unknown = target(*ei, graph); + MAKE_SPACE; + string name; + stri << "eq" << graph[*eq_it].index << " -- var" << graph[unknown].index; + EdgeProperty ep = graph[*ei]; + stri << "[label = \"" << ep << "\"];"; + } + } + DELETE_TAB + stri << "}" << endl; + out << stri.str(); + out.close(); +#ifdef __linux__ + size_t lastindex = name.find_last_of("."); + string rawname = name.substr(0, lastindex); + stringstream command; + command << "/usr/bin/dot -T eps " << name << " >" << rawname << ".eps"; + if (system(command.str().c_str())); + command.str(std::string()); + command << "/usr/bin/dot -T jpg " << name << " >" << rawname << ".jpg"; + if (system(command.str().c_str())); +#endif + } + private: + const Graph &graph; + std::list equationDescriptors; + std::list unknownDescriptors; + }; + + template + class GraphPrinterDirected{ + + typedef boost::adjacency_list Graph; + typedef typename boost::adjacency_list::vertex_descriptor Vertex; + typedef typename boost::adjacency_list::out_edge_iterator EdgeIterator; + + public: + GraphPrinterDirected(const Graph &g): graph(g) { + typename Graph::vertex_iterator vi, vi_end; + for(tie(vi, vi_end) = vertices(graph); vi!= vi_end; vi++){ + //~ if(graph[*vi].type == kVertexEquation){ + equationDescriptors.push_back(*vi); + //~ std::cout << graph[*vi].equation << std::endl; + //~ }else{ + //~ unknownDescriptors.push_back(*vi); + //~ } + } + }; + + void printGraph(std::string name) { + stringstream stri; + ofstream out(name.c_str()); + int depth = 0; + typedef typename list::iterator Iterator; + + stri << "digraph D{" << endl; + INSERT_TAB + MAKE_SPACE + stri << " rankdir=LR" << endl; + stri << " ratio=\"fill\"" << endl; + //~ stri << " edge[style=\"bold\"]" << endl; + stri << " node[shape=\"ellipse\"]" << endl; + //~ stri << " subgraph cluster0{" << endl; + //stringstream colors2; + //~ for(Iterator it=equationDescriptors.begin(); it!=equationDescriptors.end(); it++){ + //~ Iterator aux = it; + //~ aux++; + //~ stri << "eq" << graph[*it].index; + //~ if((aux) != equationDescriptors.end()){ + //~ stri << " -- "; + //~ }else{ + //~ stri << ";" << endl; + //~ } + + //~ } + for(Iterator it=equationDescriptors.begin(); it!=equationDescriptors.end(); it++){ + MAKE_SPACE + stri << "eq" << graph[*it].index << " [label=\"Eq. " << graph[*it].number << "\n" << graph[*it].mdi << "\"];" << endl; + + } + //stri << colors2.str(); + //~ DELETE_TAB + //~ MAKE_SPACE + //~ stri << "}" << endl; + DELETE_TAB + + + //~ INSERT_TAB + //~ MAKE_SPACE + //~ stri << "subgraph cluster1{" << endl; + //~ INSERT_TAB + //~ MAKE_SPACE + //~ stri << "label = \"Unknowns\";" << endl; + //~ MAKE_SPACE + //~ stri << "edge [style=invis];" << endl; + //~ MAKE_SPACE + //~ stringstream colors; + //~ for(Iterator it=unknownDescriptors.begin(); it!=unknownDescriptors.end(); it++){ + //~ Iterator aux = it; + //~ aux++; + //~ stri << "var" << graph[*it].index; + //~ if((aux) != unknownDescriptors.end()){ + //~ stri << " -- "; + //~ }else{ + //~ stri << ";" << endl; + //~ } + //~ } + //~ for(Iterator it=unknownDescriptors.begin(); it!=unknownDescriptors.end(); it++){ + //~ MAKE_SPACE +//~ #ifdef HAS_COUNT + //~ stri << "var" << graph[*it].index << " [ label = \"" << graph[*it].unknown() << "\nCount=" << graph[*it].count << "\"];" << endl; +//~ #else + //~ stri << "var" << graph[*it].index << " [ label = \"" << graph[*it].unknown() << "\"];" << endl; +//~ #endif + //~ } + //~ DELETE_TAB + //~ MAKE_SPACE + //~ stri << colors.str(); + //~ stri << "}" << endl; + //~ DELETE_TAB + + INSERT_TAB + MAKE_SPACE + //~ stri << "edge [constraint=false];" << endl; + for(Iterator eq_it = equationDescriptors.begin(); eq_it != equationDescriptors.end(); eq_it++){ + EdgeIterator ei, ei_end; + for(tie(ei, ei_end) = out_edges(*eq_it, graph); ei != ei_end; ei++){ + Vertex e2 = target(*ei, graph); + MAKE_SPACE; + string name; + stri << "eq" << graph[*eq_it].index << " -> eq" << graph[e2].index; + EdgeProperty ep = graph[*ei]; + stri << "[label = \"" << ep << "\"];"; + } + } + DELETE_TAB + stri << "}" << endl; + out << stri.str(); + out.close(); +#ifdef __linux__ + size_t lastindex = name.find_last_of("."); + string rawname = name.substr(0, lastindex); + stringstream command; + command << "/usr/bin/dot -T eps " << name << " >" << rawname << ".eps"; + if (system(command.str().c_str())); + command.str(std::string()); + command << "/usr/bin/dot -T jpg " << name << " >" << rawname << ".jpg"; + if (system(command.str().c_str())); +#endif + } + private: + const Graph &graph; + std::list equationDescriptors; + std::list unknownDescriptors; + }; +} diff --git a/causalize/vg_implementation/main.cpp b/causalize/vg_implementation/main.cpp new file mode 100644 index 0000000..aa445e7 --- /dev/null +++ b/causalize/vg_implementation/main.cpp @@ -0,0 +1,115 @@ + +/***************************************************************************** + + 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 +#include +#include +#include +#include +#include +#include "boost/date_time/posix_time/posix_time.hpp" + +using namespace std; +using namespace Modelica; +using namespace Modelica::AST; +using namespace Causalize; +bool solve = true; +bool tarjan = false; +bool vectorial = false; + +int main(int argc, char ** argv) +{ + + bool r; + int opt; + while ((opt = getopt(argc, argv, "d:vst")) != -1) { + switch (opt) { + case 'd': + if (optarg != NULL && isDebugParam(optarg)) { + debugInit(optarg); + } else { + ERROR("command-line option d has no arguments\n"); + } + break; + case 'v': + vectorial = true; + break; + case 't': + tarjan = true; + vectorial = true; + break; + case 's': + solve = false; + break; + } + } + + StoredDef sd; + if (argv[optind]!=NULL) + sd=Parser::ParseFile(argv[optind],r); + else + sd=Parser::ParseFile("",r); + + if (!r) + return -1; + + Class ast_c = boost::get(sd.classes().front()); + MMO_Class mmo(ast_c); + if (vectorial) { + SplitFor sf(mmo); + sf.splitFor(); + ReducedGraphBuilder gb(mmo); + VectorCausalizationGraph g = gb.makeGraph(); + CausalizationStrategyVector cs(g,mmo); + boost::posix_time::ptime time_start(boost::posix_time::microsec_clock::local_time()); + if(cs.Causalize()){ // Try vectorial causalization first + boost::posix_time::ptime time_end(boost::posix_time::microsec_clock::local_time()); + boost::posix_time::time_duration diff = time_end - time_start; + std::cerr << diff.total_nanoseconds()/1e6 << std::endl; + if(debugIsEnabled('c')){ + cs.PrintCausalizationResult(); + } + cout << mmo << endl; + return 0; + } + return 0; + } + boost::posix_time::ptime time_start(boost::posix_time::microsec_clock::local_time()); + CausalizationStrategy cStrategy(mmo); + cStrategy.Causalize(); + boost::posix_time::ptime time_end(boost::posix_time::microsec_clock::local_time()); + boost::posix_time::time_duration diff = time_end - time_start; + std::cerr << diff.total_nanoseconds()/1e6 << std::endl; + DEBUG('c', "Causalized Equations:\n"); + foreach_(const Equation &e, mmo.equations_ref().equations_ref()) { + if (debugIsEnabled('c')) + cerr << e << std::endl; + } + cout << mmo << endl; + return 0; +} diff --git a/causalize/vg_implementation/unknowns_collector.cpp b/causalize/vg_implementation/unknowns_collector.cpp new file mode 100644 index 0000000..8a6f2ce --- /dev/null +++ b/causalize/vg_implementation/unknowns_collector.cpp @@ -0,0 +1,122 @@ +/***************************************************************************** + + 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 + +UnknownsCollector::UnknownsCollector(MMO_Class &c): _c(c), _finder(c) { + +} + + +ExpList UnknownsCollector::collectUnknowns() { + ExpList _unknowns; + _finder.findStateVariables(); + foreach_(VarSymbolTable::table_type::value_type val, _c.syms_ref()) { + VarInfo varInfo = val.second; + Name name = val.first; + if (!varInfo.builtin() && !isConstant(name,_c.syms_ref()) && !isDiscrete(name, _c.syms_ref()) && !isParameter(name,_c.syms_ref())) { + if (varInfo.modification() && is(varInfo.modification().get())) // if the var has a fixed value over time is not a unknown + continue; + Option opt_type = _c.tyTable_ref()[varInfo.type()]; + ERROR_UNLESS((bool)opt_type, "No %s type found", varInfo.type().c_str()); + Type::Type type = opt_type.get(); + if (is(type)) { + if (varInfo.state()) { + if (!varInfo.indices()) + _unknowns.push_back(Call("der",ExpList(1,Reference(Ref(1,RefTuple(name,ExpList(0))))))); + else if (varInfo.indices().get().size()==1) { + EvalExpression ev(_c.syms_ref()); + Expression lim=varInfo.indices().get().front(); + const int limit=Apply(ev,lim); + for (int i=1;i<=limit;i++) + _unknowns.push_back(Call("der",ExpList(1,Reference(Ref(1,RefTuple(name,ExpList(1,Integer(i)))))))); + } else if (varInfo.indices().get().size()==2) { + EvalExpression ev(_c.syms_ref()); + Expression lim1=varInfo.indices().get()[0]; + Expression lim2=varInfo.indices().get()[1]; + const int limit1=Apply(ev,lim1); + const int limit2=Apply(ev,lim2); + for (int i=1;i<=limit1;i++) + for (int j=1;j<=limit2;j++) + _unknowns.push_back(Call("der",ExpList(1,Reference(Ref(1,RefTuple(name,{i,j})))))); + } else if (varInfo.indices().get().size()==3) { + EvalExpression ev(_c.syms_ref()); + Expression lim1=varInfo.indices().get()[0]; + Expression lim2=varInfo.indices().get()[1]; + Expression lim3=varInfo.indices().get()[2]; + const int limit1=Apply(ev,lim1); + const int limit2=Apply(ev,lim2); + const int limit3=Apply(ev,lim3); + for (int i=1;i<=limit1;i++) + for (int j=1;j<=limit2;j++) + for (int k=1;k<=limit3;k++) + _unknowns.push_back(Call("der",ExpList(1,Reference(Ref(1,RefTuple(name,{i,j,k})))))); + } else { + ERROR("Variables with dimension greater than 3 not supported yet"); + } + } else { + if (!varInfo.indices()) + _unknowns.push_back(Reference(Ref(1,RefTuple(name,ExpList(0))))); + else if (varInfo.indices().get().size()==1) { + EvalExpression ev(_c.syms_ref()); + Expression lim=varInfo.indices().get().front(); + const int limit=Apply(ev,lim); + for (int i=1;i<=limit;i++) + _unknowns.push_back(Reference(Ref(1,RefTuple(name,ExpList(1,Integer(i)))))); + } else if (varInfo.indices().get().size()==2) { + EvalExpression ev(_c.syms_ref()); + Expression lim1=varInfo.indices().get()[0]; + Expression lim2=varInfo.indices().get()[1]; + const int limit1=Apply(ev,lim1); + const int limit2=Apply(ev,lim2); + for (int i=1;i<=limit1;i++) + for (int j=1;j<=limit2;j++) + _unknowns.push_back(Reference(Ref(1,RefTuple(name,{i,j})))); + } else if (varInfo.indices().get().size()==3) { + EvalExpression ev(_c.syms_ref()); + Expression lim1=varInfo.indices().get()[0]; + Expression lim2=varInfo.indices().get()[1]; + Expression lim3=varInfo.indices().get()[2]; + const int limit1=Apply(ev,lim1); + const int limit2=Apply(ev,lim2); + const int limit3=Apply(ev,lim3); + for (int i=1;i<=limit1;i++) + for (int j=1;j<=limit2;j++) + for (int k=1;k<=limit3;k++) + _unknowns.push_back(Reference(Ref(1,RefTuple(name,{i,j,k})))); + } else { + ERROR("Variables with dimension greater than 3 not supported yet"); + } + } + + } else if (is(type)) { + ERROR("No vectorial support yet!"); + } + } + } + return _unknowns; +} + + diff --git a/causalize/vg_implementation/unknowns_collector.h b/causalize/vg_implementation/unknowns_collector.h new file mode 100644 index 0000000..6a436ec --- /dev/null +++ b/causalize/vg_implementation/unknowns_collector.h @@ -0,0 +1,35 @@ +/***************************************************************************** + + 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 + +using namespace std; +using namespace Modelica; +using namespace Modelica::AST; + +class UnknownsCollector { + public: + UnknownsCollector(MMO_Class &c); + ExpList collectUnknowns(); + private: + int getCompRefVal(Reference compRef, VarSymbolTable &symbolTable); + MMO_Class &_c; + StateVariablesFinder _finder; +}; diff --git a/causalize/vg_implementation/vector/causalization_algorithm.cpp b/causalize/vg_implementation/vector/causalization_algorithm.cpp new file mode 100644 index 0000000..66ba995 --- /dev/null +++ b/causalize/vg_implementation/vector/causalization_algorithm.cpp @@ -0,0 +1,715 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#define HAS_COUNT + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#define dprint(v) std::cout << #v"=" << v << std::endl //;) + +#define sz(a) int((a).size()) + +using namespace Modelica; +using namespace std; +using namespace boost::icl; + +extern bool solve; +extern bool tarjan; +extern bool vectorial; + +namespace Causalize { +CausalizationStrategyVector::CausalizationStrategyVector(VectorCausalizationGraph g, MMO_Class &m): mmo(m){ + graph = g; + step = 0; + VectorCausalizationGraph::vertex_iterator vi, vi_end; + equationNumber = unknownNumber = 0; + for(boost::tie(vi, vi_end) = vertices(graph); vi != vi_end; vi++){ + VectorVertex current_element = *vi; + if(graph[current_element].type == kVertexEquation){ + equationNumber += graph[current_element].count; + equationDescriptors.push_back(current_element); + } + else{ + unknownNumber += graph[current_element].count; + unknownDescriptors.push_back(current_element); + } + } + DEBUG('c', "Number of equations %d\n" + "Number of unknowns %d\n", + equationNumber, unknownNumber); + + if(equationNumber != unknownNumber){ + ERROR("The model being causalized is not balanced.\n" + "There are %d equations and %d variables\n", + equationNumber, unknownNumber); + } + + stringstream ss; + ss << "initial_graph.dot"; + GraphPrinter gp(graph); + gp.printGraph(ss.str()); +} + + +void +CausalizationStrategyVector::Causalize1toN(const VectorUnknown unk, const Equation eq, const IndexPairSet ips){ + CausalizedVar c_var; + c_var.unknown = unk; + c_var.equation = eq; + c_var.pairs = ips; + equations1toN.push_back(c_var); +} + +void +CausalizationStrategyVector::CausalizeNto1(const VectorUnknown unk, const Equation eq, const IndexPairSet ips){ + CausalizedVar c_var; + c_var.unknown = unk; + c_var.equation = eq; + c_var.pairs = ips; + equationsNto1.insert(equationsNto1.begin(), c_var); +} + +bool +CausalizationStrategyVector::Causalize() { + while (tarjan){ // El while es para salir si encuentra q no funciona el vectorial + VectorMatching m(graph, equationDescriptors, unknownDescriptors); + m.dfs_matching(); + VectorTarjan t(graph, m.getPairE(), m.getPairU()); + + stringstream ss; + ss << "graph_tarjan_" << step++ << ".dot"; + GraphPrinterDirected gp(t.tgraph); + gp.printGraph(ss.str()); + + std::list scc; + if(!t.GetConnectedComponent(scc)){ + // No se puede resolver con Tarjan Vectorial + std::cout << "No se puede resolver con Tarjan Vectorial, procederemos con el método escalar" << std::endl; + tarjan = false; + vectorial = false; + continue; + } + for (auto cc : scc){ + //~ dprint("New"); + std::vector vars; + for (auto vp:cc){ + CausalizedVar c_var; + c_var.unknown = vp.unknown; + c_var.equation = vp.equation; + c_var.pairs = vp.pairs; + vars.push_back(c_var); + } + tarjan_equations.push_back(vars); + } + if (debugIsEnabled('c')) + PrintCausalizationResult(); + if (solve) // @karupayun: assert(solve())? + SolveEquations2(); + return true; + } + int steps = 0; + bool split = false; + + while(true) { // Old code: When we weren't making tarjan algorithm for vectorial cases. + bool causalize_some=false; + assert(equationNumber == unknownNumber); + if(equationDescriptors.empty() && unknownDescriptors.empty()) { + // Finished causalizing :) + if (debugIsEnabled('c')) + PrintCausalizationResult(); + if (solve) + SolveEquations(); + return true; + } + + + //list::size_type numAcausalEqs = equationDescriptors.size(); + list::iterator iter, auxiliaryIter; + + + //First, we process the equations' side + auxiliaryIter = equationDescriptors.begin(); + for(iter = auxiliaryIter; iter != equationDescriptors.end(); iter = auxiliaryIter){ // Ecuación + stringstream ss; + ss << "graph_" << step++ << ".dot"; + GraphPrinter gp(graph); + gp.printGraph(ss.str()); + // Additional iterator to erase while traversing + auxiliaryIter++; + EquationVertex eq = *iter; + ERROR_UNLESS(out_degree(eq, graph) != 0, "Problem is singular, not supported yet\n"); + // Try to look for a set of indexes to causalize + Option > op = CanCausalize(eq, kVertexEquation, split); // Acá busca causalizar + // If we can causalize something + if (op) { + // We are going to causalize something + causalize_some=true; + split = false; + // This pair holds which edge(the first component) to use for causalization and which indexes(the second component) + std::pair causal_pair = op.get(); + ERROR_UNLESS(causal_pair.second.size()==1, "Causalizing more than a singleton"); + VectorEdge e = causal_pair.first; + // This is the unknown node connecting to the edge + UnknownVertex unk = GetUnknown(e); + equationNumber--; + unknownNumber--; + // Save the result of this step of causalization + Causalize1toN(graph[unk].unknown, graph[eq].equation, causal_pair.second); + // Update the pairs in the edge that is being causalized + if (debugIsEnabled('c')) + std::cerr << "Causalizing from the equation side " << causal_pair.second << std::endl; + graph[e].RemovePairs(causal_pair.second); + // Decrement the number of uncausalized equations/unknowns + graph[eq].count -= causal_pair.second.begin()->Dom().Size(); + graph[unk].count -= causal_pair.second.begin()->Ran().Size(); + // If the edge has no more pairs in it remove it + if (graph[e].IsEmpty()) { + if (debugIsEnabled('c')) { + std::cout << "Removing the edge\n"; + } + remove_edge(e, graph); + } + // Auxiliary list to later remove empty edges + std::list remove; + foreach_(VectorEdge e1, out_edges(unk,graph)) { + // Update the labels from all the edges adjacent to the unknown + if (debugIsEnabled('c')) { + std::cout << "Removing unknowns " << causal_pair.second.begin()->Ran() << " from " << graph[e1]<<"\n"; + } + graph[e1].RemoveUnknowns(causal_pair.second.begin()->Ran()); + if (debugIsEnabled('c')) { + std::cout << "Result: " << graph[e1] << "\n"; + } + // If the edge is now empty schedule it for removal + if (graph[e1].IsEmpty()) { + if (debugIsEnabled('c')) { + std::cout << "Removing the edge\n"; + } + remove.push_back(e1); + } + } + // Now remove all scheduled edges + foreach_(VectorEdge e1, remove) { + WARNING_UNLESS(out_degree(GetEquation(e1),graph)>1, "Disconnecting equation node"); + remove_edge(e1, graph); + } + // If the equation node is now unconnected and with count==0 we can remove it + if (out_degree(eq,graph)==0) { + ERROR_UNLESS(graph[eq].count==0, "Disconnected node with uncausalized equations"); + remove_vertex(eq,graph); + equationDescriptors.erase(iter); + } + // If the unknown node is now unconnected and with count==0 we can remove it + if (out_degree(unk,graph)==0) { + ERROR_UNLESS(graph[unk].count==0, "Disconnected node with uncausalized unknowns"); + remove_vertex(unk,graph); + unknownDescriptors.remove(unk); + } + //~ stringstream ss; + //~ ss << "graph_" << step++ << ".dot"; + //~ GraphPrinter gp(graph); + //~ gp.printGraph(ss.str()); + } + } + + + //Now, we process the unknowns' side + auxiliaryIter = unknownDescriptors.begin(); + for(iter = auxiliaryIter; iter != unknownDescriptors.end(); iter = auxiliaryIter){ + // Additional iterator to erase while traversing + auxiliaryIter++; + UnknownVertex unk = *iter; + ERROR_UNLESS(out_degree(unk, graph) != 0, "Problem is singular, not supported yet\n"); + // Try to look for a set of indexes to causalize + Option > op = CanCausalize(unk, kVertexUnknown, split); + // If we can causalize something + if (op) { + // We are going to causalize something + causalize_some=true; + split = false; + // This pair holds which edge(the first component) to use for causalization and which indexes(the second component) + std::pair causal_pair = op.get(); + VectorEdge e = causal_pair.first; + // This is the equation node connecting to the edge + EquationVertex eq = GetEquation(e); + equationNumber--; + unknownNumber--; + // Save the result of this step of causalization + CausalizeNto1(graph[unk].unknown, graph[eq].equation, causal_pair.second); + // Update the pairs in the edge that is being causalized + if (debugIsEnabled('c')) + std::cerr << "Causalizing from the unknown side " << causal_pair.second << std::endl; + graph[e].RemovePairs(causal_pair.second); + // Decrement the number of uncausalized equations/unknowns + ERROR_UNLESS(causal_pair.second.size()==1, "Causalizing more than a singleton"); + graph[eq].count -= causal_pair.second.begin()->Dom().Size(); + graph[unk].count -= causal_pair.second.begin()->Ran().Size(); + // If the edge has no more pairs in it remove it + if (graph[e].IsEmpty()) { + if (debugIsEnabled('c')) { + std::cout << "Removing the edge\n" << graph[e] << "\n"; + } + remove_edge(e, graph); + } + // Auxiliary list to later remove empty edges + std::list remove; + foreach_(VectorEdge e1, out_edges(eq,graph)) { + // Update the labels from all the edges adjacent to the equation + if (debugIsEnabled('c')) { + std::cout << "Removing equations " << causal_pair.second.begin()->Dom() << " from " << graph[e1]<<"\n"; + } + graph[e1].RemoveEquations(causal_pair.second.begin()->Dom()); + if (debugIsEnabled('c')) { + std::cout << "Result: " << graph[e1] << "\n"; + } + // If the edge is now empty schedule it for removal + if (graph[e1].IsEmpty()) { + if (debugIsEnabled('c')) { + std::cout << "Removing the edge\n" << graph[e1] << "\n"; + } + remove.push_back(e1); + } + } + // Now remove all scheduled edges + foreach_(VectorEdge e1, remove) { + if (e1!=e) + WARNING_UNLESS(out_degree(GetUnknown(e1),graph)>1, "Disconnecting unknown node"); //TODO: Review this condition and error message + remove_edge(e1, graph); + } + // If the equation node is now unconnected and with count==0 we can remove it + if (out_degree(eq,graph)==0) { + ERROR_UNLESS(graph[eq].count==0, "Disconnected node with uncausalized equations"); + remove_vertex(eq,graph); + equationDescriptors.remove(eq); + } + // If the unknown node is now unconnected and with count==0 we can remove it + if (out_degree(unk,graph)==0) { + ERROR_UNLESS(graph[unk].count==0, "Disconnected node with uncausalized unknowns"); + remove_vertex(unk,graph); + unknownDescriptors.erase(iter); + } + /*stringstream ss; + ss << "graph_" << step++ << ".dot"; + GraphPrinter gp(graph); + gp.printGraph(ss.str());*/ + } + } + + if (!causalize_some && !split) { // Try to split ranges + split=true; + continue; + } + if(!causalize_some && split){ + //we have a LOOP or a FOR equation that we don't + //handle at least yet, so we resort to the previous + //algorithm + ERROR("Loop detected! We don't handle loops yet!\n"); + return false; + } + steps++; + ERROR_UNLESS(steps<50, "Maximum number of steps reached"); + } +} + + +Option CausalizationStrategyVector::TestBreak(VectorEquationVertex eq, + VertexType vt, + VectorCausalizationGraph::out_edge_iterator edge, + IndexPairSet::iterator candidate_pair) +{ + VectorCausalizationGraph::out_edge_iterator other, other_end; + MDI mdi = (vt==kVertexEquation ? candidate_pair->Dom() : candidate_pair->Ran()) ; + std::set leftovers = {mdi}; + //std::cerr << "Trying to break " << mdi << std::endl; + for(boost::tie(other,other_end) = out_edges(eq,graph); other != other_end; ++other) { + const IndexPairSet &ips = graph[*other].Pairs(); + IndexPairSet::iterator test; + // First find on candidate_edge a possible set of pairs + for (test = ips.begin(); test!=ips.end(); test++) { + if (test == candidate_pair && other == edge) + continue; // Skip the same pair in the same edge + MDI toRemove = (vt==kVertexEquation ? test->Dom() : test->Ran()); + std::set new_leftovers; + //std::cerr << "Removing " << toRemove << std::endl; + for(MDI m : leftovers) { + std::list diff = m - toRemove; + new_leftovers.insert(diff.begin(), diff.end()); + } + if (new_leftovers.size()==0) // If the difference is empty we are done + return Option(); + leftovers = new_leftovers; + /*std::cerr << "Left={ "; + for(MDI m : leftovers) + std::cerr << m; + std::cerr << "}\n"; + */ + } + } + mdi = *leftovers.begin(); + if (vt==kVertexEquation) { + // Here we are only taking the first of the remaining parts. We could choose anyone so we are taking the first + return IndexPair(mdi, + mdi.ApplyUsage(candidate_pair->GetUsage(),candidate_pair->Ran()).ApplyOffset(candidate_pair->GetOffset()), + candidate_pair->GetOffset(), + candidate_pair->GetUsage()); + } else { + + return IndexPair(mdi.RevertUsage(candidate_pair->GetUsage(),candidate_pair->Dom()).ApplyOffset(candidate_pair->GetOffset()), + mdi, + candidate_pair->GetOffset(), + candidate_pair->GetUsage()); + } +} + +Option > CausalizationStrategyVector::CanCausalizeBreak(VectorEquationVertex eq, VertexType vt) { + VectorCausalizationGraph::out_edge_iterator vi, vi_end, other, other_end; + VectorEdge candidate_edge; + IndexPairSet::iterator candidate_pair, test; + IndexPairSet resultingIPS; + for(boost::tie(vi,vi_end) = out_edges(eq,graph); vi != vi_end; ++vi) { + // Try to find a pair in candidate_edge + candidate_edge = *vi; + const IndexPairSet &ips = graph[*vi].Pairs(); + // First find on candidate_edge a possible set of pairs + for (candidate_pair = ips.begin(); candidate_pair!=ips.end(); candidate_pair++) { + if (candidate_pair->Dom().Size()!=candidate_pair->Ran().Size()) // If they are different size cannot causalize + continue; + if (Option ip = TestBreak(eq,vt, vi, candidate_pair)) { // We found something we can break + return make_pair(candidate_edge,IndexPairSet({ip.get()})); + } + } + } + return Option >(); // First find on candidate_edge a possible set of pairs +} + +Option > CausalizationStrategyVector::CanCausalize(VectorEquationVertex eq, VertexType vt, bool split) { + VectorCausalizationGraph::out_edge_iterator vi, vi_end, other, other_end; + VectorEdge candidate_edge; + IndexPairSet::iterator candidate_pair, test; + IndexPairSet resultingIPS; + for(boost::tie(vi,vi_end) = out_edges(eq,graph); vi != vi_end; ++vi) { + // Try to find a pair in candidate_edge + candidate_edge = *vi; + const IndexPairSet &ips = graph[*vi].Pairs(); + // First find on candidate_edge a possible set of pairs + for (candidate_pair = ips.begin(); candidate_pair!=ips.end(); candidate_pair++) { + IndexPair candidate_ip = *candidate_pair; + // A N-to-1 or 1-to-N can not be causalized + if (candidate_ip.Dom().Size()!=candidate_ip.Ran().Size()) + continue; + + if (TestPairInCandidateEdge(candidate_pair, candidate_edge, vt)) { + //We found a candidate pair in the candidate edge + //Check if this pair is allowed for other edges + bool collision = false; + for (boost::tie(other,other_end) = out_edges(eq,graph); other != other_end; ++other) { + // Skip the candidate_edge + if (candidate_edge==*other) { + continue; + } + if (CollisionPairInEdge(*candidate_pair, *other, vt)) { + collision=true; + break; + } + } + //If there is no collision add the candidate_pair S + if (!collision) { + resultingIPS.insert(*candidate_pair); + return make_pair(candidate_edge, resultingIPS); + } + } + } + //If we found a suitable set of pairs, return this result + } + //At this point we couldn't find any causalizable pair in any edge + if (split) + return CanCausalizeBreak(eq,vt); + return Option >(); // First find on candidate_edge a possible set of pairs +} + + +bool CausalizationStrategyVector::TestPairInCandidateEdge(IndexPairSet::iterator ip, VectorEdge edge, VertexType vt) { + IndexPairSet::iterator test; + //Test the candidate pair in the edge + for (test = graph[edge].Pairs().begin(); test !=graph[edge].Pairs().end(); test++) { + // Skip the same pair in the same edge + if (ip==test) { + continue; + } + IndexPair candidate = *ip; + IndexPair test_pair = *test; + if (vt==kVertexEquation) { + if (candidate.Dom() & test_pair.Dom()) { + return false; + } + } else { + if (candidate.Ran() & test_pair.Ran()) { + return false; + } + + } + } + //The pair works in this edge with the current S + return true; +} + + +bool CausalizationStrategyVector::CollisionPairInEdge(IndexPair ip, VectorEdge edge, VertexType vt) { + for (IndexPairSet::iterator test = graph[edge].Pairs().begin(); test !=graph[edge].Pairs().end(); test++) { + if (vt==kVertexEquation) { + if (ip.Dom() & test->Dom()) { + //There is a collision, return true + return true; + } + } else if (vt==kVertexUnknown) { + if (ip.Ran() & test->Ran() ) { + //There is a collision, return true + return true; + } + }else { + ERROR("Wrong vertex type"); + } + } + //There is no collision, return false + return false; +} + + + +void CausalizationStrategyVector::SolveEquations2() { + EquationList all; + std::list c_code; + + VarSymbolTable syms = mmo.syms_ref(); + foreach_(vector cvv, tarjan_equations){ + EquationList eql; + ExpList epl; + foreach_(CausalizedVar cv, cvv) { + Equation equation = cv.equation; + if(is(equation)) { + ERROR_UNLESS(cv.pairs.size() == 1, "Solving scalar equation with more than one index pair"); + IndexPair ip = *cv.pairs.begin(); + MDI dom = ip.Dom(), ran = ip.Ran(); + //ERROR_UNLESS(ip.GetOffset().isZeros(), "Solving with offset not implemented"); + ERROR_UNLESS(dom.Size() == ran.Size(), "Solving with ranges of different size"); + ForEq feq = get(equation); + int index = 0; + for(Index & i : feq.range_ref().indexes_ref()) { + VarInfo vinfo = VarInfo(TypePrefixes(), "Integer", Option(), Modification()); + syms.insert(i.name(),vinfo); + i.exp_ref() = Expression(Range(dom.Intervals().at(index).lower(),dom.Intervals().at(index).upper())); + index++; + } + ExpList el; + index = 0; + Usage us = ip.GetUsage(); + Offset offset = ip.GetOffset(); + for (Interval i: ran.Intervals()) { + if (boost::icl::size(i)==1 && us[index]==-1) { // The unknown is used in a unitary range + el.push_back(i.lower()); + } else {// The unknown index is using a iterator + ERROR_UNLESS(indexRan(); + for(Interval i : mdi.Intervals()) { + ERROR_UNLESS(boost::icl::size(i)==1, "Interval of size>1 used for solving a scalar equation"); + varIndexes.push_back(Expression(i.lower())); + } + } + cv.unknown.SetIndex(varIndexes); + eql.push_back(equation); + epl.push_back(cv.unknown()); + if (debugIsEnabled('c')) { + std::cout << "Solving\n" << equation << "\nfor variable " << cv.unknown() << "\n"; + } + } + + + } + auto cc_eqs = (EquationSolver::Solve(eql, epl, syms, c_code, _cl, mmo.name() + ".c")); + all.insert(all.end(), cc_eqs.begin(), cc_eqs.end()); + } + foreach_(ClassType ct, _cl) { + Class c = get(ct); + mmo.types_ref().push_back(c.name()); + MMO_Class *mmo2 = new MMO_Class(c); + mmo.tyTable_ref().insert(c.name(), Type::Class(c.name(),mmo2)); + } + std::stringstream s; + s << mmo.name() << ".c"; + std::fstream fs (s.str().c_str(), std::fstream::out); + fs << "#include \n"; + fs << "#define pre(X) X\n"; + foreach_(std::string s, c_code) + fs << s; + fs.close(); + mmo.equations_ref().equations_ref()=all; +} + + + +void CausalizationStrategyVector::SolveEquations() { + EquationList all; + std::list c_code; + + vector sorted_vars = equations1toN; + sorted_vars.insert(sorted_vars.end(),equationsNto1.begin(), equationsNto1.end()); + foreach_(CausalizedVar cv, sorted_vars) { + Equation equation = cv.equation; + if(is(equation)) { + ERROR_UNLESS(cv.pairs.size() == 1, "Solving scalar equation with more than one index pair"); + IndexPair ip = *cv.pairs.begin(); + MDI dom = ip.Dom(), ran = ip.Ran(); + //ERROR_UNLESS(ip.GetOffset().isZeros(), "Solving with offset not implemented"); + ERROR_UNLESS(dom.Size() == ran.Size(), "Solving with ranges of different size"); + ForEq feq = get(equation); + VarSymbolTable syms = mmo.syms_ref(); + int index = 0; + for(Index & i : feq.range_ref().indexes_ref()) { + VarInfo vinfo = VarInfo(TypePrefixes(), "Integer", Option(), Modification()); + syms.insert(i.name(),vinfo); + i.exp_ref() = Expression(Range(dom.Intervals().at(index).lower(),dom.Intervals().at(index).upper())); + index++; + } + ExpList el; + index = 0; + Usage us = ip.GetUsage(); + Offset offset = ip.GetOffset(); + for (Interval i: ran.Intervals()) { + if (boost::icl::size(i)==1 && us[index]==-1) { // The unknown is used in a unitary range + el.push_back(i.lower()); + } else {// The unknown index is using a iterator + ERROR_UNLESS(indexRan(); + for(Interval i : mdi.Intervals()) { + ERROR_UNLESS(boost::icl::size(i)==1, "Interval of size>1 used for solving a scalar equation"); + varIndexes.push_back(Expression(i.lower())); + } + } + cv.unknown.SetIndex(varIndexes); + + if (debugIsEnabled('c')) { + std::cout << "Solving\n" << equation << "\nfor variable " << cv.unknown() << "\n"; + } + all.push_back(EquationSolver::Solve(equation, cv.unknown(), mmo.syms_ref(),c_code, _cl, mmo.name() + ".c")); + } + } + foreach_(ClassType ct, _cl) { + Class c = get(ct); + mmo.types_ref().push_back(c.name()); + MMO_Class *mmo2 = new MMO_Class(c); + mmo.tyTable_ref().insert(c.name(), Type::Class(c.name(),mmo2)); + } + std::stringstream s; + s << mmo.name() << ".c"; + std::fstream fs (s.str().c_str(), std::fstream::out); + fs << "#include \n"; + fs << "#define pre(X) X\n"; + foreach_(std::string s, c_code) + fs << s; + fs.close(); + mmo.equations_ref().equations_ref()=all; +} + +Vertex CausalizationStrategyVector::GetEquation(Edge e) { + return ((graph[(source(e,graph))].type==kVertexEquation))?source(e,graph):target(e,graph); +} + + +Vertex CausalizationStrategyVector::GetUnknown(Edge e) { + return ((graph[(target(e,graph))].type==kVertexUnknown))?target(e,graph):source(e,graph); +} + + +void +CausalizationStrategyVector::PrintCausalizationResult(){ + vector sorted_vars = equations1toN; + sorted_vars.insert(sorted_vars.end(),equationsNto1.begin(), equationsNto1.end()); + cout << "Result of causalization: \n"; + foreach_(CausalizedVar cv, sorted_vars) { + cout << "With equation \n"; + cout << cv.equation; + cout << "\n solve variable " << cv.unknown(); + cout << " in range " << cv.pairs << "\n"; + } + cout << "Causalization steps: " << sorted_vars.size() << "\n"; +} +} diff --git a/causalize/vg_implementation/vector/causalization_algorithm.h b/causalize/vg_implementation/vector/causalization_algorithm.h new file mode 100644 index 0000000..c5ba89b --- /dev/null +++ b/causalize/vg_implementation/vector/causalization_algorithm.h @@ -0,0 +1,58 @@ +/***************************************************************************** + + 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 CausalizationStrategyVector{ + public: + CausalizationStrategyVector(Causalize::VectorCausalizationGraph g, Modelica::MMO_Class &m); + bool Causalize(); + void PrintCausalizationResult(); + private: + void SolveEquations(); + void SolveEquations2(); + void Causalize1toN(const VectorUnknown unknown, const Equation equation, const IndexPairSet ips); + void CausalizeNto1(const VectorUnknown unknown, const Equation equation, const IndexPairSet ips); + Vertex GetEquation(Edge e); + Vertex GetUnknown(Edge e); + Option > CanCausalizeBreak(VectorEquationVertex eq, VertexType vt); + Option > CanCausalize(VectorEquationVertex eq, VertexType vt, bool split=false); + bool TestPairInCandidateEdge(IndexPairSet::iterator ip, VectorEdge edge, VertexType vt); + Option TestBreak(VectorEquationVertex eq, + VertexType vt, + VectorCausalizationGraph::out_edge_iterator edge, + IndexPairSet::iterator candidate_pair); + bool CollisionPairInEdge(IndexPair ip, VectorEdge edge, VertexType vt); + + EquationList rta; + int step; + int equationNumber; + int unknownNumber; + Causalize::VectorCausalizationGraph graph; + std::list equationDescriptors, unknownDescriptors; + std::vector equations1toN; + std::vector equationsNto1; + std::vector > tarjan_equations; + Modelica::MMO_Class &mmo; + Modelica::AST::ClassList _cl; +}; +} diff --git a/causalize/vg_implementation/vector/graph_builder.cpp b/causalize/vg_implementation/vector/graph_builder.cpp new file mode 100644 index 0000000..9c2f7a6 --- /dev/null +++ b/causalize/vg_implementation/vector/graph_builder.cpp @@ -0,0 +1,169 @@ +/***************************************************************************** + + 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 + +//#ifdef ENABLE_DEBUG_MSG +//#define DEBUG_MSG(str) do {std::cout << str << std::endl;} while( false ) +//#else +//#define DEBUG_MSG(str) do {} while( false ) +//#endif +#define DEBUG_MSG(str) do {std::cout << str << std::endl;} while( false ) + +using namespace std; +using namespace boost::icl; +using namespace Modelica; +using namespace Modelica::AST; + +namespace Causalize { +ReducedGraphBuilder::ReducedGraphBuilder(MMO_Class &mmo_cl): mmo_class(mmo_cl), state_finder(mmo_cl) { +} + +VectorCausalizationGraph ReducedGraphBuilder::makeGraph() { + /* Create nodes for the Equations*/ + foreach_ (Equation e, mmo_class.equations().equations()) { + static int index = 0; + VectorVertexProperty vp; + vp.type = kVertexEquation; + vp.equation = e; + if (is(e)) { + vp.count=getForRangeSize(get(e)); + } else if (is(e)) { + vp.count=1; + } else { + ERROR("Only causalization of for and equality equations"); + } + vp.index=index++; + equationDescriptorList.push_back(add_vertex(vp,graph)); + } + /* Create nodes for the unknowns: We iterate through the VarSymbolTable + * and create one vertex per unknown */ + state_finder.findStateVariables(); + foreach_ (Name var, mmo_class.variables()) { + static int index = 0; + const VarSymbolTable &syms = mmo_class.syms_ref(); + VarInfo varInfo = syms[var].get(); + if (!isConstant(var,syms) && !isBuiltIn(var,syms) && !isDiscrete(var,syms) && !isParameter(var,syms)) { + if (varInfo.modification() && is(varInfo.modification().get())) // if the var has a fixed value over time is not a unknown + continue; + VectorVertexProperty vp; + vp.type=kVertexUnknown; + vp.index=index++; + vp.unknown = VectorUnknown(varInfo, var); + if ("Real"==varInfo.type()) { + int totalUnknowns = 1; + if (!varInfo.indices()) { //Is a scalar unknown + vp.count=totalUnknowns; + } else { //Is a vector unknown + ExpList indexes = varInfo.indices_.get(); + EvalExpression ev(mmo_class.syms_ref()); + foreach_(Expression i, indexes) { + int indexSize = Apply(ev,i); + totalUnknowns *= indexSize; + vp.unknown.dimensionList.push_back(indexSize); + } + vp.count = totalUnknowns; + } + } else + ERROR("Unknown type: %s", varInfo.type().c_str()); + unknownDescriptorList.push_back(add_vertex(vp, graph)); + } + } + if(debugIsEnabled('c')){ + DEBUG_MSG("Equations"); + foreach_ (VectorEquationVertex eq, equationDescriptorList){ + DEBUG_MSG(graph[eq].index << ": " << graph[eq].equation) ; + } + DEBUG_MSG("Unknowns"); + foreach_(VectorUnknownVertex un, unknownDescriptorList){ + DEBUG_MSG(graph[un].index << ": " << graph[un].unknown()) ; + } + } + + + foreach_ (VectorEquationVertex eq, equationDescriptorList){ + foreach_(VectorUnknownVertex un, unknownDescriptorList){ + Expression unknown = graph[un].unknown(); + VarSymbolTable syms = mmo_class.syms_ref(); + Equation e = graph[eq].equation; + if (is(e)) { + Causalize::ContainsVector occurrs(unknown, graph[un], syms); + Equality eqq = boost::get(e); + const bool rl = Apply(occurrs,eqq.left_ref()); + const bool rr = Apply(occurrs,eqq.right_ref()); + if(rl || rr) { + Label ep(occurrs.GetOccurrenceIndexes()); + add_edge(eq, un, ep, graph); + } + } else if (is(e)) { + ForEq feq = get(e); + ERROR_UNLESS(feq.elements().size()==1, "For equation with more than one equation not supported"); + Equation inside = feq.elements().front(); + ERROR_UNLESS(is(inside), "Only equality equation inside for loops supported"); + Equality eqq = boost::get(inside); + IndexList ind = feq.range().indexes(); + VarSymbolTable syms_for = mmo_class.syms_ref(); + Causalize::ContainsVector occurrs_for(graph[un], syms_for, ind); + const bool rl = Apply(occurrs_for,eqq.left_ref()); + const bool rr = Apply(occurrs_for,eqq.right_ref()); + if(rl || rr) { + Label ep(occurrs_for.GetOccurrenceIndexes()); + add_edge(eq, un, ep, graph); + } + } else + ERROR_UNLESS(is(e), "Only causalization of equality and for equation is supported"); + } + } + DEBUG('c', "\n"); + return graph; +} + + +int ReducedGraphBuilder::getForRangeSize(ForEq feq) { + IndexList ind = feq.range().indexes(); + Index i = ind.front(); + int equations = 1; + foreach_(Index i, ind) { + if (!i.exp()) + ERROR("graph_builder:\n No expression on for equation"); + Expression exp = i.exp().get(); + if (is(exp)) { + equations *= get(exp).args().size(); + } else if (is(exp)) { + Range range = get(exp); + ERROR_UNLESS(!range.step(), "graph_builder: FOR ranges with leaps not supported yet"); + EvalExpression ev(mmo_class.syms_ref()); + equations *= Apply(ev,range.end_ref())-Apply(ev,range.start_ref())+1; + } else { + ERROR("Expression in FOR Index not supported\n"); + } + } + return equations; +} +} diff --git a/causalize/vg_implementation/vector/graph_builder.h b/causalize/vg_implementation/vector/graph_builder.h new file mode 100644 index 0000000..f41c8ed --- /dev/null +++ b/causalize/vg_implementation/vector/graph_builder.h @@ -0,0 +1,47 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +/* +* This class provides the interface to build the causalization +* graph which is then going to be processed by the causalization +* algorithm. Since there may be more than one way of building it +* we'll have a base abstract class and (maybe) several concrete +* implementations. +*/ +#include +#include +#include + + +namespace Causalize { +class ReducedGraphBuilder { +public: + ReducedGraphBuilder(MMO_Class &mmo_cl); + ~ReducedGraphBuilder(){}; + virtual VectorCausalizationGraph makeGraph(); +private: + int getForRangeSize(Modelica::AST::ForEq); + list equationDescriptorList; + list unknownDescriptorList; + StateVariablesFinder state_finder; + MMO_Class &mmo_class; + Causalize::VectorCausalizationGraph graph; +}; + +} diff --git a/causalize/vg_implementation/vector/splitfor.cpp b/causalize/vg_implementation/vector/splitfor.cpp new file mode 100644 index 0000000..74327df --- /dev/null +++ b/causalize/vg_implementation/vector/splitfor.cpp @@ -0,0 +1,49 @@ +/***************************************************************************** + + 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 + + +namespace Modelica { + + SplitFor::SplitFor(MMO_Class &c): _c(c) { + } + + void SplitFor::splitFor() { + EquationList &el = _c.equations_ref().equations_ref(); + SplitForVisitor efv; + EquationList el_new; + foreach_(Equation e1, el) { + EquationList eql = Apply(efv, e1); + foreach_(Equation e2, eql) { + el_new.push_back(e2); + } + } + el=el_new; + } + +}; + diff --git a/causalize/vg_implementation/vector/splitfor.h b/causalize/vg_implementation/vector/splitfor.h new file mode 100644 index 0000000..c27721d --- /dev/null +++ b/causalize/vg_implementation/vector/splitfor.h @@ -0,0 +1,33 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#ifndef SPLIT_FOR_H +#define SPLIT_FOR_H +#include + +namespace Modelica { + class SplitFor { + MMO_Class &_c; + public: + SplitFor(MMO_Class &c); + void splitFor(); + }; +} + +#endif diff --git a/causalize/vg_implementation/vector/vector_graph_definition.cpp b/causalize/vg_implementation/vector/vector_graph_definition.cpp new file mode 100644 index 0000000..01b4713 --- /dev/null +++ b/causalize/vg_implementation/vector/vector_graph_definition.cpp @@ -0,0 +1,844 @@ +/***************************************************************************** + + 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 + + +namespace Causalize { + + VectorUnknown::VectorUnknown(VarInfo varInfo, Modelica::AST::Reference var): Unknown(varInfo, var) { + if (!varInfo.indices()) { + dimension = 0; + } else { + dimension = varInfo.indices().get().size(); + } + } + + void VectorUnknown::SetIndex(Modelica::AST::ExpList index) { + ERROR_UNLESS((int)index.size()==dimension, "Indexes size different than unknown dimension"); + if (dimension!=0) { + if (Modelica::AST::is(expression)) { + get(get(expression).args_.front()).ref_.front().get<1>() = index; + } else if (Modelica::AST::is(expression)) { + get(expression).ref_.front().get<1>() = index; + } else { + ERROR("Wrong unknown expression type"); + } + } + } + + std::ostream& operator<<(std::ostream &os, const IndexPairSet &ips) { + std::list ipsStList; + foreach_(IndexPair ip, ips){ + std::ostringstream ipSt; + ipSt << ip; + ipsStList.push_back(ipSt.str()); + } + std::string ipsSt = "{" + boost::algorithm::join(ipsStList, ",") + "}"; + os << ipsSt; + return os; + } + + + /***************************************************************************** + **** Offset **** + *****************************************************************************/ + Offset Offset::operator-() const { + std::vector ret(offset.size()); + for(int i = 0; i<(int)offset.size(); i++) { + ret[i] = -offset[i]; + } + return ret; + }; + /***************************************************************************** + ****************************************************************************/ + + + + /***************************************************************************** + **** MDI **** + *****************************************************************************/ + MDI::MDI(int d, ...) { + intervals.resize(d); + va_list vl; + va_start(vl,d); + for (int i=0;iintervals)<(other.intervals); + } + + std::list MDI::Partition(Interval iA, Interval iB) { + std::list ret; + int a = iA.lower(); + int b = iA.upper(); + int c = iB.lower(); + int d = iB.upper(); + if ((a MDI::PutHead(Interval i, std::list mdiList) { + std::list mdiListRet; + for(MDI xs: mdiList) { + IntervalList ys=IntervalList(xs.intervals.begin(), xs.intervals.end()); + ys.push_front(i); + mdiListRet.push_back(ys); + } + return mdiListRet; + } + + std::list MDI::PutLists(MDI mdi, std::list mdiList) { + std::list mdiListRet; + for(Interval i: mdi.intervals) { + std::list zss = PutHead(i, mdiList); + for(MDI zs: zss) { + mdiListRet.push_back(zs); + } + } + return mdiListRet; + } + + std::ostream& operator<<(std::ostream &os, const MDI mdi) { + std::list xsStList; + for(Interval x: mdi.intervals) { + std::stringstream ss; + if ( x.lower()== x.upper()) + ss << "[" << x.lower() << "]"; + else + ss << "["<< x.lower() << ":" << x.upper() << "]"; + xsStList.push_back(ss.str()); + } + os << "<" << boost::algorithm::join(xsStList, ",") << ">"; + return os; + } + + std::list MDI::CartProd(std::list xss) { + std::list yss; + if (xss.size()==0) return yss; + else if (xss.size()==1) { + IntervalVector xs = xss.front().intervals; + for(Interval i: xs) { + IntervalList ys; + ys.push_back(i); + yss.push_back(ys); + } + return yss; + } else { + std::list zss = xss; + zss.pop_front(); + return PutLists(xss.front(), CartProd(zss)); + } + } + + std::list MDI::Filter(std::list mdiList, MDI mdi) { + std::list mdiListRet; + for(MDI m: mdiList) { + ERROR_UNLESS(m.Dimension()==mdi.Dimension(), "Dimension error #1"); + if (m.Dimension()!=mdi.Dimension()) { + std::cout << "Dimension error #2\n"; + abort(); + } + MDI::iterator iterXS = m.begin(); + MDI::iterator iterYS = mdi.begin(); + bool hasInter = true; + for(int i=0; i<(int)m.Dimension(); i++) { + hasInter&= intersects(*iterXS,*iterYS); + iterXS++; + iterYS++; + } + if (!hasInter) { + mdiListRet.push_back(m); + } + } + return mdiListRet; + } + + MDI MDI::ApplyOffset(Offset offset) const { + //TODO: It is mandatory to "Apply" or "Revert" usage before applying this method +// ERROR_UNLESS((int)offset.Size()==this->Dimension(),"Dimension error applying offset"); //TODO: Review this error + if (this->Dimension()==0 || offset.Size()==0) { + //nothing to apply + return *this; + } + IntervalVector copyIntervals = intervals; + for(int i=0; i<(int)copyIntervals.size(); i++) { + copyIntervals[i] = CreateInterval(copyIntervals[i].lower()+offset[i],copyIntervals[i].upper()+offset[i]); + } + return MDI(copyIntervals); + } + + MDI MDI::ApplyUsage(Usage usage, MDI ran) const { + if (usage.Size()==0 || usage.isUnused() || ran.Dimension()==0) { + return ran; + } + IntervalVector newIntervals(usage.Size()); + for(int i=0; i<(int)usage.Size(); i++) { + if (usage[i]>=0) { + newIntervals[i] = intervals[usage[i]]; + } + else { + ERROR_UNLESS(ran.Dimension()>=i, "Range argument size error"); + newIntervals[i] = ran.intervals[i]; + } + } + return MDI(newIntervals); + } + + MDI MDI::RevertUsage(Usage usage, MDI dom) const { +// ERROR_UNLESS(usage.Size()==dom.Dimension(), "Dimension error reverting usage"); + if (usage.Size()==0 || usage.isUnused() || dom.Dimension()==0) { + return dom; + } + else { + IntervalVector newIntervals(usage.Size()); + int usages = 0; + for (int i=0; i=0) { + newIntervals[usage[i]] = this->intervals[i]; + usages++; + } + } + newIntervals.resize(usages); + return MDI(newIntervals); + } + } + + MDI MDI::DomToRan(IndexPair ip) const { + MDI rta = this->ApplyUsage(ip.GetUsage(), ip.Ran()); + rta = rta.ApplyOffset(ip.GetOffset()); + return rta; + } + + + MDI MDI::RanToDom(IndexPair ip) const { + MDI rta = this->RevertUsage(ip.GetUsage(), ip.Dom()); + rta = rta.ApplyOffset(-ip.GetOffset()); + return rta; + } + + std::list MDI::operator-(const MDI &other) { + if (this->Dimension()!=other.Dimension()) { + ERROR("Dimension error #3\n"); + } + std::list ret; + MDI::iterator iterA = this->begin(); + MDI::const_iterator iterB = other.begin(); + std::list prod; + for(int i=0; iDimension(); i++) { + prod.push_back(Partition(*iterA,*iterB)); // particiona en cada eje por posibles subconjuntos + iterA++; + iterB++; + } + ret = CartProd(prod); // Genera todos + return Filter(ret, other); // Filtra los que intersecan + } + + + Option MDI::operator&(const MDI &other) const { + if (this->Dimension() != other.Dimension()) { //TODO: Is this condition OK? + std::cout << *this << " " << other << std::endl; + std::cout << this->Dimension() << " " << other.Dimension() << std::endl; + ERROR("Dimension error #5\n"); + } + IntervalList intersection; + for(int i=0; iDimension(); i++) { + //If i-th interval does not intersect with its corresponding interval in the other MDI: return an empty MDI + if (!intersects(this->intervals[i],other.intervals[i])) return Option(); + else intersection.push_back((this->intervals[i])&(other.intervals[i])); + } + //All intervals intersect with its corresponding interval in the other MDI: return the resulting intersection MDI + return MDI(intersection); + } + + bool MDI::Contains(const MDI &other) const { + if (this->Dimension()!=other.Dimension()) + return false; // @karupayun: Is this ok?? And for example a line inside a square? + else { + for (int i=0; i<(int)this->intervals.size(); i++){ + if (!boost::icl::contains(this->intervals[i],other.intervals[i])) + return false; + } + //If each interval of "this" contains its corresponding interval of "other" return true + return true; + } + return false; + } + /***************************************************************************** + ****************************************************************************/ + int sum_size (std::list &mdis){ + int rta = 0; + for (auto mdi : mdis){ + rta += mdi.Size(); + } + return rta; + } + + /***************************************************************************** + **** INDEX PAIR **** + *****************************************************************************/ + std::list IndexPair::operator-(const IndexPair& other) const { + ERROR_UNLESS((this->Dom().Dimension()==other.Dom().Dimension()), "Domain dimension error in IndexPair subtraction"); + ERROR_UNLESS((this->Ran().Dimension()==other.Ran().Dimension()), "Range dimension error in IndexPair subtraction"); + std::list ret; + switch (this->Type()) { + case _N_N: + switch (other.Type()) { + case _N_N: + if (this->offset != other.offset) { + //Nothing to subtract + return std::list{*this}; + } else { + std::list remainingDom = this->Dom()-other.Dom(); + std::list remainingRan = this->Ran()-other.Ran(); + ERROR_UNLESS(remainingDom.size()==remainingRan.size(), "Size error in remaining domains and ranges"); + std::list::iterator domIter = remainingDom.begin(); + std::list::iterator ranIter = remainingRan.begin(); + std::list ret; + while (domIter!=remainingDom.end()) { + ret.push_back(IndexPair(*domIter,*ranIter,this->offset, this->usage)); + domIter++; + ranIter++; + } + return ret; + } + case _N_1: + if (!this->Ran().Contains(other.Ran())) { + //Nothing to subtract + return std::list{*this}; + } else { + MDI domToRemove = (other.Ran().RevertUsage(usage, this->Dom())).ApplyOffset(-offset); + ERROR_UNLESS(domToRemove.Size()==1, "Domain of removing a pair N-1 from a N-N must have size 1"); + if(!this->Dom().Contains(domToRemove)) { + //Nothing to subtract + return std::list{*this}; + } else { + std::list remainingDom = this->Dom()-domToRemove; + std::list remainingRan = this->Ran()-other.Ran(); + ERROR_UNLESS(remainingDom.size()==remainingRan.size(), "Size error in remaining domains and ranges"); + std::list::iterator domIter = remainingDom.begin(); + std::list::iterator ranIter = remainingRan.begin(); + std::list ret; + while (domIter!=remainingDom.end()) { + ret.push_back(IndexPair(*domIter,*ranIter,this->offset, this->usage)); + domIter++; + ranIter++; + } + return ret; + } + } + case _1_N: + if (!this->Dom().Contains(other.Dom())) { + //Nothing to subtract + return std::list{*this}; + } else { + MDI ranToRemove = (other.Dom().ApplyUsage(usage, this->Ran())).ApplyOffset(offset); + ERROR_UNLESS(ranToRemove.Size()==1, "Range of removing a pair N-1 from a N-N pair must have size 1"); + std::list remainingDom = this->Dom()-other.Dom(); + std::list remainingRan = this->Ran()-ranToRemove; + ERROR_UNLESS(remainingDom.size()==remainingRan.size(), "Size error in remaining domains and ranges"); + std::list::iterator domIter = remainingDom.begin(); + std::list::iterator ranIter = remainingRan.begin(); + std::list ret; + while (domIter!=remainingDom.end()) { + ret.push_back(IndexPair(*domIter,*ranIter,this->offset, this->usage)); + domIter++; + ranIter++; + } + return ret; + } + } + case _N_1: + switch (other.Type()) { + case _N_N: + if (!other.Ran().Contains(this->Ran())) { + //Nothing to subtract + return std::list{*this}; + } else { + MDI domToRemove = (other.Ran().RevertUsage(other.usage, other.Dom())).ApplyOffset(-other.offset); + ERROR_UNLESS(domToRemove.Size()==1, "Domain of removing a pair N-N from a N-1 pair must have size 1"); + if(!this->Dom().Contains(domToRemove)) { + //Nothing to subtract + return std::list{*this}; + } else { + std::list remainingDom = this->Dom()-domToRemove; + std::list ret; + for (MDI dom: remainingDom) { + ret.push_back(IndexPair(dom, this->Ran(), this->offset, this->usage)); + } + return ret; + } + } + case _N_1: + if (this->Ran()!=other.Ran()) { + //Nothing to subtract + return std::list{*this}; + } else { + std::list remainingDom = this->Dom()-other.Dom(); + std::list ret; + for (MDI dom: remainingDom) { + ret.push_back(IndexPair(dom, this->Ran(), this->offset, this->usage)); + } + return ret; + } + case _1_N: + if (!other.Ran().Contains(this->Ran()) || !this->Dom().Contains(other.Ran())) { + //Nothing to subtract + return std::list{*this}; + } else { + std::list remainingDom = this->Dom()-other.Dom(); + std::list ret; + for (MDI dom: remainingDom) { + ret.push_back(IndexPair(dom, this->Ran(), this->offset, this->usage)); + } + return ret; + } + } + case _1_N: + switch (other.Type()) { + case _N_N: + if (!other.Dom().Contains(this->Dom())) { + //Nothing to subtract + return std::list{*this}; + } else { + MDI ranToRemove = (this->Dom().ApplyUsage(other.usage, other.Ran())).ApplyOffset(-other.offset); + ERROR_UNLESS(ranToRemove.Size()==1, "Domain of removing a pair N-N from a 1-N pair must have size 1"); + if(!this->Ran().Contains(ranToRemove)) { + //Nothing to subtract + return std::list{*this}; + } else { + std::list remainingRan = this->Ran()-ranToRemove; + std::list ret; + for (MDI ran: remainingRan) { + ret.push_back(IndexPair(this->Dom(), ran, this->offset, this->usage)); + } + return ret; + } + } + case _N_1: + if (!this->Ran().Contains(other.Ran()) || !other.Dom().Contains(this->Dom())) { + //Nothing to subtract + return std::list{*this}; + } else { + std::list remainingRan = this->Ran()-other.Ran(); + std::list ret; + for (MDI ran: remainingRan) { + ret.push_back(IndexPair(this->Dom(), ran, this->offset, this->usage)); + } + return ret; + } + case _1_N: + if (!this->Ran().Contains(other.Ran())) { + //Nothing to subtract + return std::list{*this}; + } else { + std::list remainingRan = this->Ran()-other.Ran(); + std::list ret; + for (MDI ran: remainingRan) { + ret.push_back(IndexPair(this->Dom(), ran, this->offset, this->usage)); + } + return ret; + } + } + default: + ERROR("This case should not occur"); + abort(); + } + } + + IndexPairSet IndexPair::RemoveUnknowns(MDI unk2remove) { + ERROR_UNLESS(this->Ran().Dimension()==unk2remove.Dimension(), "Removing unknowns of different dimension"); + switch (this->Type()) { + case _N_N: + if (Option intersection = unk2remove & this->Ran()) { + MDI ranToRemove = intersection.get(); + MDI domToRemove = (ranToRemove.RevertUsage(usage, this->Dom())).ApplyOffset(-offset); + std::list remainsDom = this->Dom()-domToRemove; + std::list remainsRan = this->Ran()-ranToRemove; + ERROR_UNLESS(remainsDom.size()==remainsRan.size(), "Size error of remaining pairs"); + std::list::iterator domIter = remainsDom.begin(); + std::list::iterator ranIter = remainsRan.begin(); + IndexPairSet ret; + while (domIter!=remainsDom.end()) { + ret.insert(IndexPair(*domIter,*ranIter,this->offset, this->usage)); + domIter++; + ranIter++; + } + return ret; + } else { + return {*this}; + } + case _N_1: + if (this->Ran()==unk2remove) { + //Remove all: + return {}; + } + else { + //Nothing to remove_ + return {*this}; + } + case _1_N: + if (Option intersection = unk2remove & this->Ran()) { + MDI ranToRemove = intersection.get(); + IndexPairSet ret; + std::list remainsRan = this->Ran()-ranToRemove; + for (MDI r: remainsRan) { + ret.insert(IndexPair(this->Dom(), r ,this->offset, this->usage)); + } + return ret; + } else { + return {*this}; + } + default: + ERROR("This case should not occur"); + abort(); + } + } + + IndexPairSet IndexPair::RemoveEquations(MDI eqs2remove) { + ERROR_UNLESS(this->Dom().Dimension()==eqs2remove.Dimension(), "Removing equations of different dimension"); + switch (this->Type()) { + case _N_N: + if (Option intersection = eqs2remove & this->Dom()) { + MDI domToRemove = intersection.get(); + MDI ranToRemove = (domToRemove.ApplyUsage(usage, this->Ran())).ApplyOffset(offset); + std::list remainsDom = this->Dom()-domToRemove; + std::list remainsRan = this->Ran()-ranToRemove; + ERROR_UNLESS(remainsDom.size()==remainsRan.size(), "Size error of remaining pairs"); + std::list::iterator domIter = remainsDom.begin(); + std::list::iterator ranIter = remainsRan.begin(); + IndexPairSet ret; + while (domIter!=remainsDom.end()) { + ret.insert(IndexPair(*domIter,*ranIter,this->offset, this->usage)); + domIter++; + ranIter++; + } + return ret; + } else { + return {*this}; + } + case _N_1: + if (Option intersection = eqs2remove & this->Dom()) { + MDI domToRemove = intersection.get(); + IndexPairSet ret; + std::list remainsDom = this->Dom()-domToRemove; + for (MDI dom: remainsDom) { + ret.insert(IndexPair(dom,this->Ran(),this->offset, this->usage)); + } + return ret; + } else { + return {*this}; + } + case _1_N: + if (this->Dom()==eqs2remove) { + //Remove all: + return {}; + } + else { + //Nothing to remove_ + return {*this}; + } + default: + ERROR("This case should not occur"); + abort(); + } + } + + bool IndexPair::operator<(const IndexPair& other) const { + return this->Dom() < other.Dom() || this->Ran() < other.Ran() || this->GetOffset() < other.GetOffset(); + } + + std::ostream& operator<<(std::ostream &os, const IndexPair &ip) { + os << "(" << ip.Dom() << ", " << ip.Ran() << ")"; + /*if (ip.OS().Size()) { + os << "Offset = {"; + for (int i: ip.OS()) + os << i << " "; + os << "}"; + } + if (ip.GetUsage().Size()) { + os << "Usage = {"; + for (int i: ip.GetUsage()) + os << i << " "; + os << "}"; + } */ + return os; + } + + bool IndexPair::Contains(const IndexPair& other) const { + if (this->offset!=other.offset || this->usage!=other.usage) + return false; + if (this->dom.Size()ran.Size()dom.Contains(other.dom) & this->ran.Contains(other.ran)) + return true; + else + return false; + } + + Option IndexPair::operator&(const IndexPair& other) const { + //TODO: + return Option(); + } + + IndexPairType IndexPair::Type() const { + //TODO: Check if there is MtoN or NtoM with N,M > 1 + if (dom.Size()==ran.Size()) + return _N_N; + else if (dom.Size()>ran.Size()) + return _N_1; + else return _1_N; + } + + /***************************************************************************** + ****************************************************************************/ + + + + /***************************************************************************** + **** LABEL **** + *****************************************************************************/ + Label::Label(IndexPairSet ips): ips(ips) { + this->RemoveDuplicates(); + } + + + void Label::RemovePairs(IndexPairSet ipsToRemove) { + IndexPairSet newIps; + foreach_(IndexPair ipRemove, ipsToRemove) { + foreach_(IndexPair ip, this->ips) { +// newIps.erase(ip); + foreach_(IndexPair ipRemaining, (ip-ipRemove)) { + newIps.insert(ipRemaining); + } + } + } + this->ips = newIps; + } + + void Label::RemoveUnknowns(MDI const mdi) { + IndexPairSet newIps; + for(IndexPair ip: this->ips) { + IndexPairSet afterRemove = ip.RemoveUnknowns(mdi); + newIps.insert(afterRemove.begin(), afterRemove.end()); + } +// std::cout << "\nLabel::RemoveUnknowns result:\n" << newIps << "\n"; + this->ips=newIps; + } + + void Label::RemoveEquations(MDI const mdi) { + IndexPairSet newIps; + for(IndexPair ipOld: this->ips) { + for(IndexPair ipNew: ipOld.RemoveEquations(mdi)) { + newIps.insert(ipNew); + } + } +// std::cout << "\nLabel::RemoveEquations result:\n" << newIps << "\n"; + this->ips=newIps; + } + + + std::ostream& operator<<(std::ostream &os, const Label &label) { + os << label.ips; + return os; + } + + void Label::RemoveDuplicates() { + bool removeSomething = true; + IndexPairSet newIPS = ips; + while (removeSomething) { + for (IndexPairSet::iterator checkingIP=ips.begin(); checkingIP!=ips.end(); checkingIP++) { + //Ignore pairs 1-1 => should not be equal pairs in a set + if (checkingIP->Dom().Size()==1 && checkingIP->Ran().Size()==1) + continue; + for (IndexPairSet::iterator otherIP=ips.begin(); otherIP!=ips.end(); otherIP++) { + //Ignore the same pair + if (checkingIP == otherIP) + continue; + switch (checkingIP->Type()) { + case _N_N: + switch (otherIP->Type()) { + case _N_N: + if (checkingIP->GetUsage()==otherIP->GetUsage()) { + if (checkingIP->GetOffset()==otherIP->GetOffset()) { // Same usage same offset => are equals: SHOULD NOT OCCUR + ERROR("This case should not occur since should not be equal pairs in a set"); + abort(); + } else { // Same usage different offset => there is no intersection, nothing to remove + removeSomething = false; + continue; + } + } else { //Different usage => ERROR: Not supported yet + ERROR("Multiple usages of a same vector with different index usages in a same for equation not supported"); + abort(); + } + case _N_1: + if (checkingIP->Ran().Contains(otherIP->Ran())) { //There is intersection => remove it from the N-1 Index Pair + newIPS.erase(*otherIP); + MDI domToRemove = otherIP->Ran().RevertUsage(checkingIP->GetUsage(), checkingIP->Dom()).ApplyOffset(checkingIP->GetOffset()); + for (MDI remainingDom: otherIP->Dom()-domToRemove) { + newIPS.insert(IndexPair(remainingDom, otherIP->Ran(), otherIP->GetOffset(), otherIP->GetUsage())); + } + removeSomething = true; + continue; + } + else { //No intersection => nothing to remove + removeSomething = false; + continue; + } + case _1_N: + if (checkingIP->Dom().Contains(otherIP->Dom())) { //There is intersection => remove the N-N Index Pair, since it must be a 1-1 pair. + newIPS.erase(*checkingIP); + removeSomething = true; + continue; + } + } + case _N_1: + switch (otherIP->Type()) { + case _N_N: + if (otherIP->Ran().Contains(checkingIP->Ran())) { //There is intersection => remove it from the N-1 Index Pair + newIPS.erase(*checkingIP); + MDI domToRemove = checkingIP->Ran().RevertUsage(otherIP->GetUsage(), otherIP->Dom()).ApplyOffset(otherIP->GetOffset()); + for (MDI remainingDom: checkingIP->Dom()-domToRemove) { + newIPS.insert(IndexPair(remainingDom, checkingIP->Ran(), checkingIP->GetOffset(), checkingIP->GetUsage())); + } + removeSomething = true; + continue; + } + else { //No intersection => nothing to remove + removeSomething = false; + continue; + } + case _N_1: + if (checkingIP->Ran()==otherIP->Ran()) { // Same range => are equals: SHOULD NOT OCCUR + ERROR("This case should not occur since should not be equal pairs in a set"); + abort(); + } + else { //No intersection => nothing to remove + removeSomething = false; + continue; + } + case _1_N: + //This case should not occur + ERROR("This case should not occur since should could not be N-1 and 1-N pairs in a same label"); + abort(); + } + case _1_N: + switch (otherIP->Type()) { + case _N_N: + if (otherIP->Dom().Contains(checkingIP->Dom())) { //There is intersection => remove the N-N Index Pair, since it must be a 1-1 pair. + newIPS.erase(*otherIP); + removeSomething = true; + continue; + } + case _N_1: + //This case should not occur + ERROR("This case should not occur since should could not be N-1 and 1-N pairs in a same label"); + abort(); + case _1_N: + if (checkingIP->Dom()==otherIP->Dom()) { // Same range => are equals: SHOULD NOT OCCUR + ERROR("This case should not occur since should not be equal pairs in a set"); + abort(); + } + else { //No intersection => nothing to remove + removeSomething = false; + continue; + } + } + } + } + } + removeSomething = false; + } + ips = newIPS; + } + /***************************************************************************** + ****************************************************************************/ + + + std::ostream& operator<<(std::ostream &os, const std::list &mdiList) { + std::list mdiStList; + for(MDI mdi: mdiList) { + std::stringstream ss; + ss << mdi; + mdiStList.push_back(ss.str()); + } + os << "{" << boost::algorithm::join(mdiStList, ",") << "}"; + return os; + } + + std::ostream& operator<<(std::ostream &os, const std::list &ipList) { + std::list ipsStList; + foreach_(IndexPair ip, ipList){ + std::ostringstream ipSt; + ipSt << ip; + ipsStList.push_back(ipSt.str()); + } + std::string ipsSt = "{" + boost::algorithm::join(ipsStList, ",") + "}"; + os << ipsSt; + return os; + } + + + unsigned long int EdgeCount(IndexPairSet labels) { + unsigned long int count = 0; + /*foreach_(IndexPair ip, labels) { + unsigned long int eq_count = IntervalCount(get<0>(ip).first); + unsigned long int unk_count = IntervalCount(get<1>(ip).first); + count += (eq_count > unk_count ? eq_count : unk_count); + //unsigned long int eq_ount = + + }*/ + return count; + } + + +} diff --git a/causalize/vg_implementation/vector/vector_graph_definition.h b/causalize/vg_implementation/vector/vector_graph_definition.h new file mode 100644 index 0000000..05a2c23 --- /dev/null +++ b/causalize/vg_implementation/vector/vector_graph_definition.h @@ -0,0 +1,262 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#ifndef VECTOR_GRAPH_DEFINITION_ +#define VECTOR_GRAPH_DEFINITION_ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +namespace ICL = boost::icl; +namespace Causalize { + /// @brief This is the property for a vertex in the incidence graph. Nodes can be of two types: Equation or Unknow. + class IndexPair; + struct VectorUnknown: Unknown { + int dimension; + std::vector dimensionList; + VectorUnknown(){}; + VectorUnknown(VarInfo varInfo, Modelica::AST::Reference var); + void SetIndex(Modelica::AST::ExpList index); + }; + + struct VectorVertexProperty: VertexProperty { + /// @brief The number of equations or unknowns left to causalize in this node + int count; + VectorUnknown unknown; + }; + + /// @brief A pair representing a usage of a variable in an equation + typedef ICL::discrete_interval Interval; + inline Interval CreateInterval(int a, int b) { + return ICL::discrete_interval(a,b, ICL::interval_bounds::closed()); + } + typedef std::list IntervalList; + typedef std::vector IntervalVector; + + + /***************************************************************************** + **** Usage **** + *****************************************************************************/ + class Usage { + public: + inline Usage():usage() { }; + inline Usage(int size):usage(std::vector(size)) { } + inline Usage(int size, int value):usage(std::vector(size, value)) { } + inline int& operator[](int index) { return usage[index]; } + inline const int& operator[](int index) const { return usage[index]; } + inline void push_back(const int i) { usage.push_back(i); } + inline bool operator==(const Usage& other) const { return this->usage == other.usage; }; + inline bool operator!=(const Usage& other) const { return this->usage != other.usage; }; + inline int Size() { return usage.size(); } + inline bool isUnused() { + for(int i: usage) { + if (i!=-1) return false; + } + return true; + } + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + inline const_iterator begin() const { return usage.begin(); } + inline iterator begin() { return usage.begin(); } + inline iterator end() { return usage.end(); } + private: + std::vector usage; + }; + /***************************************************************************** + ****************************************************************************/ + + + + /***************************************************************************** + **** Offset **** + *****************************************************************************/ + class Offset { + public: + inline Offset(std::vector offset): offset(offset) { }; + inline Offset(): offset() { }; + inline bool operator<(const Offset& other) const { return this->offset < other.offset; }; + inline bool operator==(const Offset& other) const { return this->offset == other.offset; }; + inline bool operator!=(const Offset& other) const { return this->offset != other.offset; }; + inline int operator[](const int& index) const { return offset[index]; }; + inline bool isZeros() { + for(int i: offset) { + if (i!=0) return false; + } + return true; + } + Offset operator-() const; + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + inline const_iterator begin() const { return offset.begin(); } + inline iterator begin() { return offset.begin(); } + inline iterator end() { return offset.end(); } + inline unsigned int Size () const { return offset.size(); } +private: + std::vector offset; + }; + /***************************************************************************** + ****************************************************************************/ + + + /***************************************************************************** + **** MDI **** + *****************************************************************************/ + class MDI { //Multi-Dimensional Interval + + public: + MDI(int d, ... ); + MDI(IntervalList intervalList); + inline MDI() { intervals.resize(0); } + inline MDI(IntervalVector intervals): intervals(intervals) { }; + inline int Dimension() const {return intervals.size(); } + int Size () const; + std::list operator-(const MDI& other); + std::list Difference(const MDI& other) { return (*this)-other;} ; + MDI ApplyOffset(Offset) const; + MDI ApplyUsage(Usage, MDI ran = MDI({})) const; + MDI RevertUsage(Usage usage, MDI dom = MDI({})) const; + // karupayun - Para moverse usando la info de la conexion entre Dom y Ran + MDI DomToRan(IndexPair ip) const; + MDI RanToDom(IndexPair ip) const; + bool operator<(const MDI& other) const; + Option operator&(const MDI& other) const; + Option Intersection (MDI& other) { return other & (*this) ;} + friend std::ostream& operator<<(std::ostream& os, const MDI mdi); + inline const IntervalVector & Intervals() const { return intervals; } + bool Contains(const MDI& other) const; + inline bool operator==(const MDI& other) const { return this->intervals==other.intervals; }; + inline bool operator!=(const MDI& other) const { return !((*this)==other); }; + + private: + IntervalVector intervals; + typedef IntervalVector::iterator iterator; + typedef IntervalVector::const_iterator const_iterator; + inline const_iterator begin() const { return intervals.begin(); } + inline iterator begin() { return intervals.begin(); } + inline iterator end() { return intervals.end(); } + + IntervalList Partition(Interval iA, Interval iB); + //MDI ApplyOffset(Offset offset); + std::list PutHead(Interval i, std::list mdiList); + std::list Filter(std::list mdiList, MDI mdi); + std::list CartProd(std::list mdiList); + std::list PutLists(MDI mdi, std::list mdiList); + }; + /***************************************************************************** + ****************************************************************************/ + typedef std::list MDIL; // //Multi-Dimensional Interval List + int sum_size (std::list &mdis); // Sumas de los tamaños de los MDI's de la lista + + std::ostream& operator<<(std::ostream &os, const std::list &mdiList); + enum IndexPairType{ + _N_N, _N_1, _1_N + }; + + /***************************************************************************** + **** INDEX PAIR **** + *****************************************************************************/ + class IndexPair { + public: + inline IndexPair() { }; + inline IndexPair(MDI dom_, MDI ran_, Offset os, Usage us): dom(dom_), ran(ran_), offset(os), usage(us) { }; + inline MDI Dom() const { return dom; } + inline MDI Ran() const { return ran; } + inline Offset GetOffset() const { return offset; } + inline Usage GetUsage() const { return usage; } + std::list operator-(const IndexPair& other) const; + std::list Difference(const IndexPair& other) { return (*this) - other; } + std::set RemoveUnknowns(MDI unk2remove); + std::set RemoveEquations(MDI eqs2remove); + bool operator<(const IndexPair& other) const; + Option operator&(const IndexPair& other) const; + friend std::ostream& operator<<(std::ostream& os, const IndexPair& ip); + bool Contains(const IndexPair& other) const; + IndexPairType Type() const; + private: + MDI dom, ran; + Offset offset; + Usage usage; + }; + /***************************************************************************** + ****************************************************************************/ + + + std::ostream& operator<<(std::ostream &os, const std::list &ipList); + + + typedef std::set IndexPairSet; + std::ostream& operator<<(std::ostream& os, const IndexPairSet& ips); + + /***************************************************************************** + **** LABEL **** + *****************************************************************************/ + class Label { + public: + inline Label() {}; + Label(IndexPairSet ips); + void RemovePairs(IndexPairSet ips); + void RemoveUnknowns(MDI const unk2remove); + void RemoveEquations(MDI const mdi); + unsigned long int EdgeCount(); + inline bool IsEmpty() { return ips.size()==0; } + inline const IndexPairSet & Pairs() const { return ips; } + friend std::ostream& operator<<(std::ostream& os, const Label& label); + private: + IndexPairSet ips; + void RemoveDuplicates(); + }; + /***************************************************************************** + ****************************************************************************/ + + + + unsigned long int EdgeCount(IndexPairSet); + + + /// @brief This is the definition of the Incidence graph for the vector case. + typedef boost::adjacency_list VectorCausalizationGraph; + /// @brief This a node from the vectorized incidence graph + typedef Causalize::VectorCausalizationGraph::vertex_descriptor VectorVertex; + /// @brief An equation vertex is the same as a regular vertex + typedef VectorVertex VectorEquationVertex; + /// @brief An unknown vertex is the same as a regular vertex + typedef VectorVertex VectorUnknownVertex; + /// @brief This is an edge of the vectorized causalization graph + typedef VectorCausalizationGraph::edge_descriptor VectorEdge; + /// @brief This struct represents a set of causalized vars for the vector algorithm + + struct CausalizedVar{ + VectorUnknown unknown; + Equation equation; + IndexPairSet pairs; + }; +} +#endif diff --git a/causalize/vg_implementation/vector/vector_matching.cpp b/causalize/vg_implementation/vector/vector_matching.cpp new file mode 100644 index 0000000..9fd6ad1 --- /dev/null +++ b/causalize/vg_implementation/vector/vector_matching.cpp @@ -0,0 +1,325 @@ +/***************************************************************************** + + 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 + +namespace Causalize{ + typedef std::map MapMDI; +//---------------------------------- Funciones Auxiliares ----------------------------------/ + void VectorMatching::check(VectorVertex ev, IndexPair ip){ + if (ip.Dom() == ip.Ran().RanToDom(ip) && ip.Ran() == ip.Dom().DomToRan(ip)) return; + std::cout << "EQ " << graph[ev].equation << std::endl; + std::cout << "IP.DOM() " << ip.Dom() << std::endl; + std::cout << "IP.RAN() " << ip.Ran() << std::endl; + std::cout << "IP.OFF() "; + for (auto it : ip.GetOffset()) std::cout << it << " "; + std::cout << std::endl; + std::cout << "IP.USA() "; + for (auto it : ip.GetUsage()) std::cout << it << " "; + std::cout << std::endl; + std::cout << "IP.DomToRan() " << ip.Dom().DomToRan(ip) << std::endl; + std::cout << "IP.RanToDom() " << ip.Ran().RanToDom(ip) << std::endl; + } + + bool differents (VectorEdge e1, VectorEdge e2, IndexPair ip1, IndexPair ip2){ + return e1 != e2 || ip1.Dom() != ip2.Dom() || ip1.Ran() != ip2.Ran(); + } +//---------------------------------- ------------------------------------------------------/ + + bool VectorMatching::isNil (VectorVertex v){ + return graph[v].type == kNilVertex; + } + + // Filtra los no-visitados para el dfs + std::list VectorMatching::filter_not_visited (VectorVertex v, MDI mdi){ + std::list rta (1,mdi); + for (auto vis : Visitados[v]){ + std::list new_list; + for (auto act_mdi : rta){ + new_list.splice(new_list.end(), act_mdi-vis); + } + rta = new_list; + } + return rta; + } + + // Busca solo los MDI que no estén matcheados + std::list VectorMatching::buscar_NIL (MapMDI lv){ + std::list rta; + for (auto par : lv){ + VectorVertex v = par.second.v; + if (isNil(v)){ + rta.push_back (par.first); + } + } + return rta; + } + + MapMDI VectorMatching::get_match_mdis (MapMDI map_unk, MDI unk_mdi){ + MapMDI rta; + Option aux; + for (auto par : map_unk){ + if (aux = par.first & unk_mdi){ + rta[aux.get()] = par.second; + } + } + return rta; + } + + // dado V y MDI, matcheo V-MDI con el V_match usando la arista e + void VectorMatching::set_mdi_e (VectorVertex v, MDI mdi, IndexPair ip, VectorVertex v_match, VectorEdge e = VectorEdge()){ + MapMDI rta; + for (auto par : Pair_E[v]){ + MDI aux = par.first; + for (auto dif : aux-mdi){ + rta[dif] = par.second; + } + } + rta[mdi] = Match (ip, v_match, e); + Pair_E[v] = rta; + } + + void VectorMatching::set_mdi_u (VectorVertex v, MDI mdi, IndexPair ip, VectorVertex v_match, VectorEdge e = VectorEdge()){ + MapMDI rta; + for (auto par : Pair_U[v]){ + MDI aux = par.first; + for (auto dif : aux-mdi) + rta[dif] = par.second; + } + rta[mdi] = Match (ip, v_match, e); + Pair_U[v] = rta; + } + + + +// --------------------------------------------- Heurística Inicial --------------------------------------------------// + // Usado en la heurística, matcheamos la arista si tiene alguna parte del dominio que nadie más tiene + bool VectorMatching::is_dom_unique (VectorVertex ev, VectorEdge e1, IndexPair ip1, MDI mdi){ + std::list resto; + std::list aux; + resto.push_back (mdi); + foreach_(VectorEdge edge, out_edges(ev,graph)) { + IndexPairSet ips = graph[edge].Pairs(); + for (auto ip : ips){ + if (differents(e1, edge, ip1, ip)){ + for (auto r : resto){ + std::list toAdd = r - ip.Dom(); + for (auto add : toAdd) + aux.push_back(add); + } + resto = aux; + aux.clear(); + } + } + } + return sum_size(resto); + } + + bool VectorMatching::is_ran_unique (VectorVertex uv, VectorEdge e1, IndexPair ip1, MDI mdi){ + std::list resto; + std::list aux; + resto.push_back (mdi); + foreach_(VectorEdge edge, out_edges(uv,graph)) { + IndexPairSet ips = graph[edge].Pairs(); + for (auto ip : ips){ + if (differents(e1, edge, ip1, ip)){ + for (auto r : resto){ + std::list toAdd = r - ip.Ran(); + for (auto add : toAdd) + aux.push_back(add); + } + resto = aux; + aux.clear(); + } + } + } + return sum_size(resto); + } + + // Usado en la heurística, matchea aristas en su totalidad, por lo que si una parte ya está usada no se usa. + bool VectorMatching::is_dom_matched (VectorVertex ev, MDI mdi){ + std::list nil_mdi = buscar_NIL (Pair_E[ev]); + int tamano = mdi.Size(); + for (auto it : nil_mdi){ + if(auto aux = it & mdi) + tamano -= aux.get().Size(); + } + return tamano != 0; + } + + bool VectorMatching::is_ran_matched (VectorVertex uv, MDI mdi){ + std::list nil_mdi = buscar_NIL (Pair_U[uv]); + int tamano = mdi.Size(); + for (auto it : nil_mdi){ + if(auto aux = it & mdi) + tamano -= aux.get().Size(); + } + return tamano != 0; + } + + // Elije el matching inicial de una forma heurística para ahorrarse casos complicados + int VectorMatching::heuristica_inicial(){ + for (auto &ev : eqDescriptors){ + foreach_(VectorEdge edge, out_edges(ev,graph)) { + for (auto ip : graph[edge].Pairs()){ + VectorVertex uv = target (edge,graph); + if (ip.Ran().Size() < ip.Dom().Size()) continue; //Quiero matchear eq completas + if (is_dom_matched(ev, ip.Dom())) continue; + if (is_ran_matched(uv, ip.Ran())) continue; + if (is_dom_unique(ev, edge, ip, ip.Dom()) || is_ran_unique(uv, edge, ip, ip.Ran())) { + set_mdi_e(ev, ip.Dom(), ip, uv, edge); + set_mdi_u(uv, ip.Ran(), ip, ev, edge); + return ip.Dom().Size(); + } + } + } + } + return 0; + } +// ------------------------------------------------------------------------------------------------------------------ // + + bool VectorMatching::isOK (int matching, bool print_message = false){ + + VectorCausalizationGraph::vertex_iterator vi, vi_end; + int equationNumber = 0, unknownNumber = 0; + for(boost::tie(vi, vi_end) = vertices(graph); vi != vi_end; vi++){ + VectorVertex current_element = *vi; + if(graph[current_element].type == kVertexEquation){ + equationNumber += graph[current_element].count; + } + else{ + unknownNumber += graph[current_element].count; + } + } + if(equationNumber != matching){ + //~ if (print_message) + //~ printf("The model being causalized is not full-matched.\n" + //~ "There are %d equations and the matching is %d\n", + //~ equationNumber, matching); + return false; + } + return true; + } + + Option VectorMatching::DFS (VectorVertex v, MDI mdi){ // visit, not_visited, inv_offset + if (isNil(v)) return mdi; // Si es Nil retorno el MDI + std::list nv_mdis = filter_not_visited(v, mdi); // Para que sea un dfs filtro por no visitados + visit(v, mdi); + for (auto nv_mdi : nv_mdis){ + foreach_(VectorEdge edge, out_edges(v,graph)) { // Busco todas las aristas + VectorVertex u = target(edge,graph); // Calculo la incognita de la arista + for (auto ip : graph[edge].Pairs()){ + Option inter_mdi = nv_mdi & ip.Dom(); + if (!inter_mdi) continue; + MDI unk_mdi = inter_mdi.get().DomToRan(ip); + MapMDI match_mdis = get_match_mdis (Pair_U[u], unk_mdi); // Toda la información de los matcheos de U, que se los paso a E + for (auto match_mdi : match_mdis){ + MDI dfs_mdi_e = match_mdi.first.RanToDom(match_mdi.second.ip); + Option opt_dfs_matcheado_e = DFS (match_mdi.second.v, dfs_mdi_e); + if (opt_dfs_matcheado_e){ + MDI dfs_matcheado_e = opt_dfs_matcheado_e.get(); + MDI matcheado_u = dfs_matcheado_e.DomToRan(match_mdi.second.ip); + MDI mdi_e = matcheado_u.RanToDom(ip); + if (unk_mdi.Size()<= 1){ // Parche para que funcione en casos borde (for i + dfs_matcheado_e = inter_mdi.get(); + mdi_e = dfs_matcheado_e; + } + if (unk_mdi.Size() < dfs_matcheado_e.Size()) continue; // Sino no tiene sentido intentar matchear + IndexPair ip2(mdi_e, matcheado_u, ip.GetOffset(), ip.GetUsage()); + set_mdi_e(v, mdi_e, ip2, u, edge); + set_mdi_u(u, matcheado_u, ip2, v, edge); + return mdi_e; + } + } + } + } + } + return Option (); // Return false + } + + int VectorMatching::dfs_matching (){ + VectorVertexProperty NIL; + NIL.type = kNilVertex; + VectorVertex NIL_VERTEX = add_vertex(NIL, graph); + for (auto &ev : eqDescriptors){ + foreach_(VectorEdge e1, out_edges(ev,graph)) { + for (auto ip : graph[e1].Pairs()){ + check(ev, ip); + set_mdi_e (ev, ip.Dom(), ip, NIL_VERTEX); + } + } + } + for (auto &uv : uDescriptors){ + foreach_(VectorEdge e1, out_edges(uv,graph)) { + for (auto ip : graph[e1].Pairs()){ + set_mdi_u (uv, ip.Ran(), ip, NIL_VERTEX); + } + } + } + + int matching = 0; + while (true){ // Matchea con la heurística inicial suponiendo que las aristas van completan. + int new_matching = heuristica_inicial(); + if (!new_matching) break; + matching += new_matching; + } + bool founded = !isOK(matching, true); + while (founded){ + founded = false; + inicializar_dfs(); + for (auto &ev : eqDescriptors){ + if (founded) break; + std::list eps = buscar_NIL (Pair_E[ev]); // Acá tiene que usarse buscar uno! + for (auto ep : eps){ + if (Option aux_mdi = DFS (ev, ep)){ + matching += aux_mdi.get().Size(); + founded = true; + break; + } + } + } + } + //~ for (auto &uv : uDescriptors){ + //~ for (auto mmdi : Pair_U[uv]){ + //~ std::cout << "\nMatcheamos la Incognita: " << graph[uv].unknown() << " en el rango: " << mmdi.first << " con la ecuación:\n" << graph[mmdi.second.v].equation << " en el rango " << mmdi.first.RanToDom(mmdi.second.ip) << std::endl << std::endl; + //~ } + + //~ } + if (debugIsEnabled('c')) { + for (auto &ev : eqDescriptors){ + for (auto mmdi : Pair_E[ev]){ + std::cout << "\nMatcheamos la Ecuación: " << graph[ev].equation << " en el rango: " << mmdi.first << " con la incognita:\n" << graph[mmdi.second.v].unknown() << " en el rango " << mmdi.first.DomToRan(mmdi.second.ip) << std::endl << std::endl; + } + + } + } + if (!isOK (matching, true)) assert(false); + return matching; + } + + +} // Causalize + diff --git a/causalize/vg_implementation/vector/vector_matching.h b/causalize/vg_implementation/vector/vector_matching.h new file mode 100644 index 0000000..ccbcc09 --- /dev/null +++ b/causalize/vg_implementation/vector/vector_matching.h @@ -0,0 +1,77 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#ifndef VECTOR_MATCHING_ +#define VECTOR_MATCHING_ + +#include + +namespace Causalize { + + class Match{ + + public: + Match(){ }; + Match(IndexPair ip, VectorVertex v, VectorEdge e): ip(ip), v(v), e(e){} + + IndexPair ip; + VectorVertex v; // Vertice Matcheado + VectorEdge e; + }; + + typedef std::map MapMDI; + + class VectorMatching{ + + public: + VectorMatching(){ }; + VectorMatching(VectorCausalizationGraph graph, std::list &eqDescriptors, std::list &uDescriptors) + :graph(graph), eqDescriptors(eqDescriptors), uDescriptors(uDescriptors){}; + int dfs_matching(); + Option DFS (VectorVertex v, MDI mdi); + std::map getPairE () {return Pair_E;} + std::map getPairU () {return Pair_U;} + + private: + void inicializar_dfs(){ Visitados.clear(); } + void visit (VectorVertex v, MDI mdi){ Visitados[v].push_back(mdi); } + std::list filter_not_visited (VectorVertex v, MDI mdi); + std::list buscar_NIL (MapMDI lv); + MapMDI get_match_mdis (MapMDI map_unk, MDI unk_mdi); + void set_mdi_e (VectorVertex v, MDI mdi, IndexPair ip, VectorVertex v_match, VectorEdge e); + void set_mdi_u (VectorVertex v, MDI mdi, IndexPair ip, VectorVertex v_match, VectorEdge e); + bool is_dom_unique (VectorVertex ev, VectorEdge e1, IndexPair ip1, MDI mdi); + bool is_ran_unique (VectorVertex uv, VectorEdge e1, IndexPair ip1, MDI mdi); + bool is_dom_matched (VectorVertex ev, MDI mdi); + bool is_ran_matched (VectorVertex uv, MDI mdi); + int heuristica_inicial(); + bool isOK (int matching, bool print_message); + bool isNil (VectorVertex v); + void check(VectorVertex ev, IndexPair ip); + + VectorCausalizationGraph graph; + std::list eqDescriptors; + std::list uDescriptors; + + std::map Pair_E; // Con quien se aparean las ecuaciones + std::map Pair_U; // Con quien se aparean las incognitas + std::map > Visitados; // Para el DFS + }; +}; // Causalize +#endif diff --git a/causalize/vg_implementation/vector/vector_tarjan.cpp b/causalize/vg_implementation/vector/vector_tarjan.cpp new file mode 100644 index 0000000..8fa5ffd --- /dev/null +++ b/causalize/vg_implementation/vector/vector_tarjan.cpp @@ -0,0 +1,323 @@ +/***************************************************************************** + + 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 + +#define dprint(v) std::cout << #v"=" << v << std::endl //;) + + + +namespace Causalize{ + + MDIL inter1a1 (MDIL l1, MDIL l2){ + MDIL rta; + assert (l1.size() == l2.size()); + auto pm2 = l2.begin(); + for (auto m1 : l1){ + if (m1 & *pm2) + rta.push_back ((m1 & *pm2).get()); + } + return rta; + } + + MDIL DomToRanList (IndexPair ip, MDIL doml, MDIL raml){ + MDIL rta; + auto pram = raml.begin(); + for (auto m : doml){ + ip.Ran() = *pram; + rta.push_back(m.DomToRan(ip)); + pram++; + } + return rta; + } + + MDIL RanToDomList (IndexPair ip, MDIL raml, MDIL doml){ + MDIL rta; + auto pdom = doml.begin(); + for (auto m : raml){ + ip.Dom() = *pdom; + rta.push_back(m.DomToRan(ip)); + pdom++; + } + return rta; + } + + + std::list resta (std::list lmdi, MDI mdi){ + std::list rta; + for (auto r : lmdi){ + std::list toAdd = r - mdi; + for (auto add : toAdd) + rta.push_back(add); + } + return rta; + } + + std::list DomToRanList (IndexPair ip, std::list doms){ + std::list rta; + for(auto dom : doms){ + rta.push_back (dom.DomToRan(ip)); + } + return rta; + } + + VectorTarjan::VectorTarjan(VectorCausalizationGraph graph, std::map Pair_E, std::map Pair_U) : graph(graph){ + int counter = 1, counter2 = 1; + for (auto p : Pair_E){ + VectorVertex v = p.first; + for (auto mm : p.second){ + //~ dprint(graph[v].equation); + TarjanVertex tv = add_vertex (tgraph); + tgraph[tv].equation = graph[v].equation; + tgraph[tv].index = counter++; + tgraph[tv].count = mm.first.Size(); + tgraph[tv].unknown = graph[mm.second.v].unknown; + tgraph[tv].ip = IndexPair (mm.first, mm.first.DomToRan (mm.second.ip), mm.second.ip.GetOffset(), mm.second.ip.GetUsage()); + tgraph[tv].mdi = mm.first; + tgraph[tv].number = counter2; + tgraph[tv].edge = mm.second.e; + } + counter2++; + } + + VectorCausalizationGraph::edge_iterator ei, ei_end; + TarjanGraph::vertex_iterator v1, v1_end, v2, v2_end; + //~ for(boost::tie(v1, v1_end) = vertices(tgraph); v1 != v1_end; v1++){ + //~ dprint('\n'); + //~ dprint(tgraph[*v1].number); + //~ dprint(tgraph[*v1].equation); + //~ dprint(tgraph[*v1].unknown()); + //~ dprint(tgraph[*v1].ip.Dom()); + //~ dprint(tgraph[*v1].ip.Ran()); + //~ } + foreach_(VectorEdge ei, edges(graph)) { + for (auto ip : graph[ei].Pairs()){ + + std::list dom; dom.push_back(ip.Dom()); + std::list ran; ran.push_back(ip.Ran()); + + for(boost::tie(v1, v1_end) = vertices(tgraph); v1 != v1_end; v1++){ + if (tgraph[*v1].edge == ei){ // Borrar la parte del matching + dom = resta (dom, tgraph[*v1].ip.Dom()); + ran = resta (ran, tgraph[*v1].ip.Ran()); + } + } + //~ dprint(size(ran)); + //~ dprint(size(dom)); + if ((ran.size()) != (dom.size())) { // Parche en el caso de 1 con todos + if ((ran.size()) == 0){ + for (auto _ : dom){ + ran.push_back(ip.Ran()); + } + } + else if ((dom.size()) == 0){ + for (auto _ : ran){ + ran.push_back(ip.Dom()); + } + } + else assert(false); + } + + if (sum_size(dom) == 0) continue; // Si es 0 no queda nada + if (sum_size(ran) == 0) continue; // Si es 0 no queda nada + auto mran = ran.begin(); + for (auto mdom : dom){ + for(boost::tie(v1, v1_end) = vertices(tgraph); v1 != v1_end; v1++){ + if (graph[source(ei, graph)].equation == tgraph[*v1].equation){ + for(boost::tie(v2, v2_end) = vertices(tgraph); v2 != v2_end; v2++){ + if (graph[target(ei, graph)].unknown() == tgraph[*v2].unknown()){ + // Intersección dominios arista con v1 + if (!(tgraph[*v1].ip.Dom() & mdom)) continue; + MDI new_dom = (tgraph[*v1].ip.Dom() & mdom).get(); + + // Intersección rangos arista con v2 + if (!(tgraph[*v2].ip.Ran() & *mran)) continue; + MDI new_ran = (tgraph[*v2].ip.Ran() & *mran).get(); + + // Interseco ambos rangos para ver las verdaderas dependencias + if (!(new_dom.DomToRan(ip) & new_ran)) continue; + if (!(new_ran.RanToDom(ip) & new_dom)) continue; + new_ran = (new_ran & new_dom.DomToRan(ip)).get(); + new_dom = (new_dom & new_ran.RanToDom(ip)).get(); + + // Solo vamos a guardar una arista de Dom a Dom + new_ran = new_ran.RanToDom(tgraph[*v2].ip); + + if ((v1 == v2) && (new_dom == new_ran)) continue; // No have sense this kind of edges + IndexPair new_ip (new_dom, new_ran, ip.GetOffset(), ip.GetUsage()); + IndexPairSet ips; + ips.insert(new_ip); + Label lab (ips); + add_edge (*v1, *v2, lab, tgraph).first; + + //~ tgraph[te].dom = new_dom; + //~ tgraph[te].ran = new_ran; + //~ tgraph[te].Label = ips; + //~ tgraph[te].ip = new_ip; + + //~ dprint(tgraph[*v1].number); + //~ dprint(tgraph[*v2].number); + //~ dprint('\n'); + //~ dprint(tgraph[te].dom); + //~ dprint(tgraph[te].ran); + } + } + } + } + mran++; + } + } + } + }; + + // Busca el conjunto de nodos que representa el mdi y ese vértice. + // Devuelve un conjunto disjunto de partes. El booleano representa si solo buscamos elementos no visitados anteriormente. + MDIL VectorTarjan::find (TarjanVertex tv, MDI mdi, bool onlyNV){ + MDIL rta; + for (auto pair : data){ + MDI mdi2 = pair.first.second; + auto tv2 = pair.first.first; + auto td = pair.second; + if ((tv == tv2) && (mdi & mdi2)){ + if (mdi2.Contains(mdi) && (td.id != -1) && (!td.onStack)) // Si ya fue visitado y seleccionada su componente conexa, lo ignoramos en el dfs. + return rta; + if (mdi != mdi2){ // Debo quebrar + if (td.id != -1){ // Visitado con otro MDI no disjunto, caso no resuelto todavía. + dprint(td.id); + dprint(mdi); + dprint(mdi2); + dprint(tgraph[tv].number); + isOk = false; + } + data.erase(pair.first); + VertexPart vp; + for (auto m : mdi2 - mdi){ + vp = std::make_pair(tv2, m); + data[vp] = td; + } + vp = std::make_pair(tv2, (mdi&mdi2).get()); + data[vp] = td; + rta.push_back((mdi&mdi2).get()); + } + if (td.id == -1 || !onlyNV) + rta.push_back(mdi); + } + } + return rta; + } + + void VectorTarjan::DFS(TarjanVertex tv, MDI mdi){ + MDIL mdil = find (tv, mdi); // Función que se encarga de trabajar con los distintos conjuntos + //~ for (auto mdi : mdil){ // Marco como visitado + //~ VertexPart at = (std::make_pair (tv, mdi)); + + //~ } + + for (auto mdi : mdil){ // DFS + VertexPart at = (std::make_pair (tv, mdi)); + data[at].id = data[at].low = id; + data[at].onStack = true; + stack.push(at); + id++; + foreach_(TarjanEdge edge, out_edges(tv,tgraph)) { + TarjanVertex tv2 = target(edge, tgraph); + // Pasar pasar de Dom1 a Dom2, paso de Dom1 a Ran2 y de Ran2 a Dom2 + MDI mdi2 = mdi.DomToRan(*tgraph[edge].Pairs().begin()).RanToDom(tgraph[tv2].ip); + // -------------------------------------------- + if (!(tgraph[tv2].mdi & mdi2)) continue; // TODO(karupayun): Falta analizar que hacer si estamos cayendo a un MDI que no figuraba anteriormente. Esta línea deberíamos borrarla. + MDIL mdil2 = find (tv2, (tgraph[tv2].mdi & mdi2).get(), false); + for (auto m : mdil2){ + VertexPart to = std::make_pair(tv2,m); + if (data[to].id == -1) DFS (to.first, to.second); // Si no está visitado, lo visitamos + if (data[to].onStack) { + data[at].low = std::min (data[at].low, data[to].low); // Si está en stack actualizamos el mínimo + } + } + } + if (data[at].id == data[at].low){ + ConnectedComponent scc; + while (1){ + VertexPart node = stack.top(); + stack.pop(); // TODO(karupayun): Si cambió el conjunto esto no sería así. Pensar que hacer para trabajar ese caso difícil. + data[node].onStack = false; + data[node].low = data[at].id; + scc.push_back(node); + if (node == at) { + strongly_connected_component.push_back(scc); + break; + } + } + } + } + } + + bool VectorTarjan::GetConnectedComponent(std::list &scc){ + isOk = true; + id = 0; + + TarjanGraph::vertex_iterator vi, vi_end; + for(boost::tie(vi, vi_end) = vertices(tgraph); vi != vi_end; vi++){ + TarjanData td; + td.id = -1; + td.low = 0; + td.onStack = false; + + VertexPart vp = std::make_pair (*vi, tgraph[*vi].mdi); + data[vp] = td; + } + + for (auto pair : data){ + if (pair.second.id == -1) + DFS(pair.first.first, pair.first.second); + } + + /* Si volvemos a un mismo vértice con otro rango del que salimos, lo vamos a consider como un caso no resuelto todavía. Si volvemos con el mismo, es trivial: + * Hay N ciclos. + * */ + for (auto cc : strongly_connected_component){ + //~ dprint("New"); + CausalizeEquations ces; + for (auto vp:cc){ // vp = std::pair + MDI dom = vp.second; + MDI ran = dom.DomToRan (tgraph[vp.first].ip); + IndexPair ip (dom, ran, tgraph[vp.first].ip.GetOffset(), tgraph[vp.first].ip.GetUsage()); + IndexPairSet ips = {ip}; + //~ dprint(tgraph[vp.first].number); + //~ dprint(tgraph[vp.first].unknown()); + //~ dprint(vp.second); + CausalizedVar ce; + ce.pairs = ips; + ce.equation = tgraph[vp.first].equation; + ce.unknown = tgraph[vp.first].unknown; + ces.push_back(ce); + } + scc.push_back(ces); + } + + return isOk; + } +} // Causalize + diff --git a/causalize/vg_implementation/vector/vector_tarjan.h b/causalize/vg_implementation/vector/vector_tarjan.h new file mode 100644 index 0000000..12e7955 --- /dev/null +++ b/causalize/vg_implementation/vector/vector_tarjan.h @@ -0,0 +1,78 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#ifndef VECTOR_TARJAN_ +#define VECTOR_TARJAN_ + +#include +#include +#include + +namespace Causalize { + struct TarjanVertexProperty: VectorVertexProperty { + /// @brief Represent the conexion into a Unknown and a Equation + IndexPair ip; // La forma de conexión + MDI mdi; // Equation + int number; + VectorEdge edge; + }; + struct TarjanEdgeProperty: Label { + MDI dom; + MDI ran; + IndexPair ip; + }; + + /// @brief This is the definition of the Incidence graph for the vector case. + typedef boost::adjacency_list TarjanGraph; + /// @brief This a node from the vectorized incidence graph + typedef Causalize::TarjanGraph::vertex_descriptor TarjanVertex; + /// @brief This a node from the vectorized incidence graph + typedef Causalize::TarjanGraph::edge_descriptor TarjanEdge; + struct TarjanData{ + int id; + int low; + bool onStack; + }; + + typedef std::list CausalizeEquations; + typedef std::pair VertexPart; + typedef std::list < VertexPart > ConnectedComponent; + typedef std::map MapMDI; + + + class VectorTarjan{ + public: + VectorTarjan(){ }; + VectorTarjan(VectorCausalizationGraph graph, std::map Pair_E, std::map Pair_U); + bool GetConnectedComponent(std::list &scc); + TarjanGraph tgraph; + + private: + void DFS(TarjanVertex tv, MDI mdi); + int id; + MDIL find (TarjanVertex tv, MDI mdi, bool onlyNV = true); + + bool isOk; + std::stack stack; + std::list strongly_connected_component; + std::map data; + VectorCausalizationGraph graph; + }; +}; // Causalize +#endif diff --git a/configure.in b/configure.in index 8c9de89..66464d8 100644 --- a/configure.in +++ b/configure.in @@ -11,8 +11,8 @@ m4_include([macros/ax_cxx_compile_stdcxx.m4]) # Checks for programs. AC_PROG_CXX AC_PROG_CC -AX_CXX_COMPILE_STDCXX(11,noext,optional) -AX_CXX_COMPILE_STDCXX(14,noext,optional) +AX_CXX_COMPILE_STDCXX(11,noext,mandatory) +AX_CXX_COMPILE_STDCXX(14,noext,mandatory) # Checks for libraries. AC_LANG([C++]) diff --git a/examples/causalize/vector/AdvectionReaction.mo b/examples/causalize/vector/AdvectionReaction.mo new file mode 100644 index 0000000..d58b319 --- /dev/null +++ b/examples/causalize/vector/AdvectionReaction.mo @@ -0,0 +1,22 @@ +model AdvectionReaction + "Model of an advection process with chemical reaction" + parameter Integer N = 10 "Number of volumes"; + parameter Real mu = 1000 "Kinetic coefficient of the reaction"; + constant Real alpha = 0.5 "Parameter of the reaction model"; + Real u_in = 1 "Inlet concentration"; + Real u[N](each start = 0, each fixed = true) + "Concentration at each volume outlet"; +equation + der(u[1]) = ((-u[1]) + 1)*N - mu*u[1]*(u[1] - alpha)*(u[1] - 1); + for j in 2:N loop + der(u[j]) = ((-u[j]) + u[j-1])*N - mu*u[j]*(u[j] - alpha)*(u[j] - 1); + end for; + annotation (Documentation(info=" +

This models solves the problem represented by the following PDE by means of the finite volume method, on a spatial domain of unit length and assuming unit velocity v.

+

+

If μ = 0, the model represent the transport of a certain chemical species in a fluid, similar to SimpleAdvection. If mu is increased, a chemical reaction is added with two stable equilibria, one at u = 0 and one at u = 1, with an unstable equilibrium at u = α.

+

The chemical reaction sharpens the concentration wave front, which would be otherwise be smoothed out by the numerical diffusion effect of the finite volume method.

+

The boundary condition u_in at the inlet, i.e., u(0,t), is specified by suitable binding equations.

+")); +end AdvectionReaction; + diff --git a/examples/causalize/vector/AdvectionReaction2D.mo b/examples/causalize/vector/AdvectionReaction2D.mo new file mode 100644 index 0000000..bc7591a --- /dev/null +++ b/examples/causalize/vector/AdvectionReaction2D.mo @@ -0,0 +1,28 @@ +model AdvectionReaction2D +import file; + parameter Real dT=1e-3; + parameter Real ax=1,ay=1,r=1000; + constant Integer N = 10, M=10; + parameter Real dx=10/N; + parameter Real dy=10/M; + Real u[N,M](each fixed=false); + Real reaction[N,M](each fixed=false); +initial equation + for i in 1:5 loop + u[1,i]=1; + end for; +equation + der(u[1,1])=(-u[1,1]*ax/dx)+(-u[1,1]*ay/dy) + reaction[1,1]; + for i in 2:N loop + der(u[i,1])=(-u[i,1]*ax/dx)+(-u[i,1]+u[i-1,1])*ay/dy + reaction[i,1]; + end for; + for i in 2:M loop + der(u[1,i])=(-u[1,i]+u[1,i-1])*ax/dx+(-u[1,i]*ay/dy) + reaction[1,i]; + end for; + for i in 2:N, j in 2:M loop + der(u[i,j])=(-u[i,j]+u[i,j-1])*ax/dx+(-u[i,j]+u[i-1,j])*ay/dy + reaction[i,j]; + end for; + for i in 1:N, j in 1:M loop + reaction[i,j] = r*u[i,j]^2*(1-u[i,j]); + end for; +end AdvectionReaction2D; diff --git a/examples/causalize/vector/AdvectionReaction3D.mo b/examples/causalize/vector/AdvectionReaction3D.mo new file mode 100644 index 0000000..7c93119 --- /dev/null +++ b/examples/causalize/vector/AdvectionReaction3D.mo @@ -0,0 +1,56 @@ +model AdvectionReaction3D +import file; + parameter Real dT=1e-3; + parameter Real ax=1,ay=1,az=1, r=1000; + constant Integer N = 10, M=10, O = 10; + parameter Real dx=10/N; + parameter Real dy=10/M; + parameter Real dz=10/O; + Real u[N,M,O](each fixed=false); + Real reaction[N,M,O](each fixed=false); +initial equation + for i in 1:5 loop + u[1,i,1]=1; + end for; +equation + // First volume + der(u[1,1,1]) = (-u[1,1,1]*ax/dx) + (-u[1,1,1]*ay/dy) + (-u[1,1,1]*az/dz) + reaction[1,1,1]; + + // X axis row + for i in 2:N loop + der(u[i,1,1]) = ((-u[i,1,1] + u[i-1,1,1])*ax/dx) + (-u[i,1,1])*ay/dy + (-u[i,1,1]*az/dz) + reaction[i,1,1]; + end for; + + // Y axis row + for j in 2:M loop + der(u[1,j,1]) = (-u[1,j,1]*ax/dz) + (-u[1,j,1] + u[1,j-1,1])*ay/dy + (-u[1,j,1]*az/dz) + reaction[1,j,1]; + end for; + + // Z axis row + for k in 2:O loop + der(u[1,1,k]) = (-u[1,1,k]*ax/dx) + (-u[1,1,k]*ay/dy) + ((-u[1,1,k] + u[1,1,k-1]) *az/dz) + reaction[1,1,k]; + end for; + + // XY plane + for i in 2:N, j in 2:M loop + der(u[i,j,1]) = ((-u[i,j,1] + u[i-1,j,1]) *ax/dx) + (-u[i,j,1] + u[i,j-1,1])*ay/dy + (-u[i,j,1]*az/dz) + reaction[i,j,1]; + end for; + + // XZ plane + for i in 2:N, k in 2:O loop + der(u[i,1,k]) = ((-u[i,1,k] + u[i-1,1,k]) *ax/dx) + (-u[i,1,k])*ay/dy + ((-u[i,1,k] + u[i,1,k-1])*az/dz) + reaction[i,1,k]; + end for; + + // YZ plane + for j in 2:M, k in 2:O loop + der(u[1,j,k]) = (-u[1,j,k]*ax/dx) + ((-u[1,j,k]+u[1,j-1,k]))*ay/dy + ((-u[1,j,k] + u[1,j,k-1])*az/dz) + reaction[1,j,k]; + end for; + + // The common volumes + for i in 2:N, j in 2:M, k in 2:O loop + der(u[i,j,k]) = ((-u[i,j,k]+u[i-1,j,k])*ax/dx) + ((-u[i,j,k]+u[i,j-1,k]))*ay/dy + ((-u[i,j,k] + u[i,j,k-1])*az/dz) + reaction[i,j,k]; + end for; + for i in 1:N, j in 1:M, k in 1:O loop + reaction[i,j,k] = r*u[i,j,k]^2*(1-u[i,j,k]); + end for; +end AdvectionReaction3D; diff --git a/examples/causalize/vector/AirConditioners.mo b/examples/causalize/vector/AirConditioners.mo new file mode 100644 index 0000000..8c97eb8 --- /dev/null +++ b/examples/causalize/vector/AirConditioners.mo @@ -0,0 +1,69 @@ +model AirConditioners + import math; + constant Integer N = 20; + parameter Real CAP[N], RES[N], POT[N], THA = 32,pmax=0,Kp=1,Ki=1,tref=20; + Real th[N]; + Real ierr; + discrete Real ptotal,ptotals; + discrete Real on[N]; + discrete Real dtref,pref(start=0.5); + discrete Real nextSample(start=1); + discrete Real noise(start=rand(2)-1); + + + initial algorithm + for i in 1:N loop + th[i] := rand(4)+ 18; + CAP[i] := rand(100)+ 550; + RES[i] := rand(0.4)+ 1.8; + POT[i] := rand(0.2)+ 13; + pmax:=pmax+POT[i]; + end for; + + for i in 1:N loop + if th[i] - tref - 0.5> 0 then + on[i] := 1; + ptotal := ptotal + POT[i]; + end if; + end for; + + equation + for i in 1:N loop + der(th[i]) = (THA/RES[i]-POT[i]*on[i]-th[i]/RES[i]+noise/RES[i])/CAP[i]; + end for; + der(ierr) = pref-ptotals/pmax; + + algorithm + for i in 1:N loop + when th[i] - tref -dtref + on[i] - 0.5 > 0 then + on[i] := 1; + ptotal := ptotal + POT[i]; + elsewhen th[i] - tref -dtref + on[i] - 0.5 < 0 then + on[i] := 0; + ptotal := ptotal - POT[i]; + end when; + end for; + when time > 1000 then + pref := 0.4; + end when; + when time > 2000 then + pref := 0.5; + end when; + when time > nextSample then + nextSample := nextSample+1; + noise := rand(2)-1; + ptotals := ptotal; + dtref := Kp*(ptotals/pmax-pref)-Ki*ierr; + end when; + annotation( + experiment( + + MMO_Description="Control of the power consumption of a large populaion of air conditioners.", + MMO_Solver=DOPRI, + MMO_Output={ptotal}, + StartTime=0, + StopTime=3000, + Tolerance={1e-4}, + AbsTolerance={1e-4} + )); +end AirConditioners; diff --git a/examples/causalize/vector/CascadedFirstOrder.mo b/examples/causalize/vector/CascadedFirstOrder.mo new file mode 100644 index 0000000..123f788 --- /dev/null +++ b/examples/causalize/vector/CascadedFirstOrder.mo @@ -0,0 +1,22 @@ +model CascadedFirstOrder + "N cascaded first order systems, approximating a pure delay" + parameter Integer N = 10 "Order of the system"; + parameter Real T = 1 "System delay"; + final parameter Real tau = T/N "Individual time constant"; + Real x[N] (each start = 0, each fixed = true); +equation + tau*der(x[1]) = 1 - x[1]; + for i in 2:N loop + tau*der(x[i]) = x[i-1] - x[i]; + end for; +annotation( + experiment(StopTime = 2,Tolerance = 1e-6), + Documentation(info = "

This model is meant to try out the tool + performance with ODE systems of possibly very large size, with high + sparsity degree.

+

The model is a cascaded connection of first order linear systems, + approximating a pure delay of T seconds as N approaches + infinity. It contains exactly N state variables and N + differential equations.

")); +end CascadedFirstOrder; + diff --git a/examples/causalize/vector/CocurrentHeatExchangerEquations.mo b/examples/causalize/vector/CocurrentHeatExchangerEquations.mo new file mode 100644 index 0000000..ae62bcc --- /dev/null +++ b/examples/causalize/vector/CocurrentHeatExchangerEquations.mo @@ -0,0 +1,77 @@ +model CocurrentHeatExchangerEquations + "cocurrent heat exchanger implemented by equations" + import Modelica.SIunits; + parameter Real L=10 "length of the channels"; + constant Integer N=20 "number of nodes"; + parameter Real wB=1 "mass flow rate of fluid B"; + parameter Real areaA=5e-5 "cross sectional area of channel A"; + parameter Real areaB=5e-5 "cross sectional area of channel B"; + parameter Real rhoA=1000 "density of fluid A"; + parameter Real rhoB=1000 "density of fluid B"; + parameter SIunits.SpecificHeatCapacity cpA=4200 + "specific heat capacity of fluid A"; + parameter SIunits.SpecificHeatCapacity cpB=4200 + "specific heat capacity of fluid B"; + parameter SIunits.SpecificHeatCapacity cpW=2000 + "specific heat capacity of the wall"; + parameter SIunits.CoefficientOfHeatTransfer gammaA=4000 + "heat transfer coefficient of fluid A"; + parameter SIunits.CoefficientOfHeatTransfer gammaB=10000 + "heat transfer coefficient of fluid B"; + parameter Real omega=0.1 "perimeter"; + final parameter Real l = L / (N - 1) + "length of the each wall segment"; + discrete Real wA(start=1) "mass flow rate of fluid A"; + Real QA[N - 1] + "heat flow rate of fluid A in the segments"; + Real QB[N - 1] + "heat flow rate of fluid B in the segments"; +// Real TA_1 "temperature nodes on channel A"; +// Real TB_1 "temperature nodes on channel B"; + Real TA[N - 1] "temperature nodes on channel A"; + Real TB[N - 1] "temperature nodes on channel B"; + Real TW[N - 1] "temperatures on the wall segments"; + Real QtotA "total heat flow rate of fluid A"; + Real QtotB "total heat flow rate of fluid B"; + + discrete Real TA_1(start=300); + Real TB_1; +initial equation + for i in 1:N-1 loop + TA[i] = 300; + TB[i] = 300; + TW[i] = 300; + end for; +equation + //TA_1 = if time < 8 then 300 else 301; + TB_1 = 310; + //wA = if time < 15 then 1 else 1.1; + + + rhoA * l * cpA * areaA * der(TA[1]) = wA * cpA * TA_1 - wA * cpA * TA[1] + QA[1]; + rhoB * l * cpB * areaB * der(TB[1]) = wB * cpB * TB_1 - wB * cpB * TB[1] - QB[1]; + QA[1] = (TW[1] - (TA_1 + TA[1]) / 2) * gammaA * omega * l; + QB[1] = ((TB_1 + TB[1]) / 2 - TW[1]) * gammaB * omega * l; + cpW / (N - 1) * der(TW[1]) = (-QA[1]) + QB[1]; + + + for i in 2:N-1 loop + rhoA * l * cpA * areaA * der(TA[i ]) = wA * cpA * TA[i-1] - wA * cpA * TA[i ] + QA[i]; + rhoB * l * cpB * areaB * der(TB[i ]) = wB * cpB * TB[i-1] - wB * cpB * TB[i ] - QB[i]; + QA[i] = (TW[i] - (TA[i-1] + TA[i ]) / 2) * gammaA * omega * l; + QB[i] = ((TB[i-1] + TB[i ]) / 2 - TW[i]) * gammaB * omega * l; + cpW / (N - 1) * der(TW[i]) = (-QA[i]) + QB[i]; + end for; + QtotA = sum(QA); + QtotB = sum(QB); +algorithm + when time > 8 then + TA_1 := 301; + end when; + when time > 15 then + wA := 1.1; + //wA = if time < 15 then 1 else 1.1; + end when; + annotation(experiment(StopTime = 20, Tolerance = 1e-6)); +end CocurrentHeatExchangerEquations; + diff --git a/examples/causalize/vector/Generator.mo b/examples/causalize/vector/Generator.mo new file mode 100644 index 0000000..a87967d --- /dev/null +++ b/examples/causalize/vector/Generator.mo @@ -0,0 +1,135 @@ +model Generator + parameter Integer N = 10 + "Number of finite volumes for the superheater model"; + constant Real pi = 3.1416; + parameter Real P_nom = 500e6 "Nominal power of the generator"; + parameter Real f_ref = 50 "Reference network frequency"; + parameter Real T_a = 5 "Characteristic time of the generator"; + parameter Real alpha = 0.3 + "Fraction of turbine power provided by the high-pressure turbine"; + parameter Real T_source = 1.5 + "Normalized temperature of heat source for the superheater"; + parameter Real NTU = 2 "Number of thermal units in the superheater"; + parameter Real tau_b = 200 + "Characteristic time of energy storage in the boiler"; + parameter Real tau_t = 8 + "Characteristic response time of the low pressure turbine"; + parameter Real tau_q = 3 + "Characteristic time of thermal generation process"; + parameter Real tau_sh = 100 + "Characteristic time of the superheater thermal response"; + parameter Real tau_y = 0.3 "Characteristic time of turbine governor"; + parameter Real droop = 0.1 "Primary frequency control droop"; + parameter Real Kp_p = 10 "Proportional gain of pressure controller"; + parameter Real Ti_p = 70 "Integral time of pressure controller"; + parameter Real Kp_t = 2 "Proportional gain of power controller"; + parameter Real Ti_t = 0.3 "Integral time of power controller"; + final parameter Real omega_ref = 2*pi*f_ref; + final parameter Real J = P_nom*T_a/(omega_ref^2); + Real P_a = P_nom + "Active electrical power produced by the synchronous generator - replace the default binding"; + Real P_t_0 = P_nom + "Active power set point - replace the default binding"; + Real P_sfc = 0 + "Additional power request for secondary frequency control - replace the default binding"; + Real P_t(nominal = 1e9) "Mechanical power generated by the turbine [W]"; + Real theta + "Rotor angle relative to reference rotating at nominal speed"; + Real omega "Turbine angular speed"; + Real f "Generator frequency"; + Real delta_f "Normalized frequency error"; + Real p "Boiler pressure in p.u."; + Real p_0 = 1 "Boiler pressure set point in p.u."; + Real w_s "Steam flow rate in p.u."; + Real q_ev "Thermal power to the boiler in p.u."; + Real q_ev_0 "Thermal power set point in p.u."; + Real y_t "Turbine admittance in p.u"; + Real y_t_0 "Turbine admittance set point in p.u."; + Real p_t "Turbine power in p.u."; + Real p_t_0 "Turbine power set point in p.u."; + Real p_t_0_fc + "Turbine power set point in p.u. with frequency control corrections"; + Real p_t_lp "Low-pressure turbine power in p.u."; + + Real T_s[N] + "Normalized temperature states for the superheater model"; + Real T_s_b[N+1] + "Normalized temperature at the boundaries of the superheater volumes"; + + Real err_p_t "Power controller error in p.u."; + Real err_p_t_int "Integral of power controller error"; + + Real err_p "Pressure controller error in p.u."; + Real err_p_int "Pressure controller integral error"; + +equation + // Rotor phase angle equation (relative to reference rotating at reference speed) + der(theta) = omega - omega_ref; + + // Energy balance on the turbine-generator axis + J/2*der(omega) = P_t - P_a; + + // Non-dimensional boiler model + tau_b*der(p) = q_ev - w_s; + + // Non-dimensional turbine model + w_s = y_t*p "steam flow"; + tau_t*der(p_t_lp) + p_t_lp = (1-alpha)*w_s "LP turbine power"; + p_t = alpha *w_s + p_t_lp "Total turbine power"; + + // Non-dimensional steam temperature model + T_s_b[1] = p "Boundary condion at inlet"; + for i in 2:N+1 loop + T_s_b[i] = T_s[i-1] "Upwind discretization scheme"; + end for; + + for i in 1:N loop + tau_sh/N * der(T_s[i]) = w_s*(T_s_b[i] - T_s_b[i+1]) + NTU/N*(T_source - T_s_b[i+1]); + end for; + + // Actuation + tau_y*der(y_t) = y_t_0 - y_t; + tau_q*der(q_ev) = q_ev_0 - q_ev; + + // Normalization equations + P_t = p_t*P_nom; + P_t_0 = p_t_0*P_nom; + + // Boiler follows control strategy with primary and secondary frequency control + f = omega/(2*pi); + delta_f = (f - f_ref)/f_ref; + p_t_0_fc = p_t_0 - 1/droop*delta_f + P_sfc/P_nom; + + err_p_t = p_t_0_fc - p_t; + der(err_p_t_int) = err_p_t; + + err_p = p_0 - p; + der(err_p_int) = err_p; + + q_ev_0 = p_t_0_fc + Kp_p*(err_p + 1/Ti_p * err_p_int); + y_t_0 = p_t_0_fc + Kp_t*(err_p_t + 1/Ti_t *err_p_t_int); + +initial equation + theta = 0; + omega = omega_ref; + p = 1; + p_t_lp = (1-alpha); + y_t = 1; + q_ev = 1; + err_p_t_int = 0; + err_p_int = 0; + T_s[1] = (p + NTU/N*T_source)/(1 + NTU/N); + for i in 2:N loop + T_s[i] = (T_s[i-1] + NTU/N*T_source)/(1 + NTU/N); + end for; + + annotation (Documentation(info=" +

The Generator model is a conceptual model of a thermal power plant with a synchronous electrical generator. The goal is not to reproduce the dynamics of any real power plant accurately, but rather to replicate the mathematical structure and the type of dynamic behaviour that is to be found in real-life power plant models.

+

In particular, the goal is to represent the slow thermal dynamics and the fast electro-mechanical dynamics at the same time. This is a particularly interesting benchmark for multi-rate integration algorithms, that can exploit these dynamic feature by only refining the integration grid for the electro-mechanical states.

+

The thermal part comprises a simplified boiler - turbine model and a thermal model of the superheated steam temperature, assuming uniform thermal source temperature for simplicity. The model is written using normalized variables for simplicity.

+

The generator model is described by the classical swing equation, assuming ideal voltage control and neglecting reactive power flows. The actual power flows between generators and loads are computed by the PowerSystem

+

The model is completed by classical boiler-follows control strategy with primary and secondary frequency control. The primary frequency control input is computed locally and is proportional to the frequency deviation, while the secondary control input is determined by the the PowerSystem model and passed via a modifier to the individual generator models. For simplicity, the superheated steam temperature is not controlled and fluctuates depending on the steam flow.

+

The initial equations initialize the generator at steady-state, assuming that a load with the nominal power of the plant is consuming the entire production locally.

+")); +end Generator; + diff --git a/examples/causalize/vector/HeatingSystemExplicit.mo b/examples/causalize/vector/HeatingSystemExplicit.mo new file mode 100644 index 0000000..44327d9 --- /dev/null +++ b/examples/causalize/vector/HeatingSystemExplicit.mo @@ -0,0 +1,64 @@ +model HeatingSystemExplicit "Explicit ODE model of a heating system - continuous-time dynamics" + function hist + "Cubic function to implement the bifurcation-based temperature controller" + input Real x; + input Real p; + input Real e = 1; + output Real y; + algorithm + y:=-(x+0.5)*(x-0.5)*x*1/(0.0474)*e+p; + end hist; + function sat "Smooth saturation of input x between xmin and xmax" + input Real x; + input Real xmin; + input Real xmax; + output Real y; + algorithm + y := Modelica.Math.tanh(2*(x-xmin)/(xmax-xmin)-1)*(xmax-xmin)/2 + (xmax+xmin)/2; + end sat; + + + constant Real pi = 3.1416; + parameter Integer N = 10 "Number of heated units"; + parameter Real Cu[N] = (ones(N)+ linspace(0,1.348,N))*1e7 + "Heat capacity of heated units"; + parameter Real Cd = 2e6*N + "Heat capacity of distribution circuit"; + parameter Real Gh = 200 + "Thermal conductance of heating elements"; + parameter Real Gu = 150 + "Thermal conductance of heated units to the atmosphere"; + parameter Real Qmax = N*3000 + "Maximum power output of heat generation unit"; + parameter Real Teps = 0.5 + "Threshold of heated unit temperature controllers"; + parameter Real Td0 = 343.15 + "Set point of distribution circuit temperature"; + parameter Real Tu0 = 293.15 "Heated unit temperature set point"; + parameter Real Kp = Qmax/4 + "Proportional gain of heat generation unit temperature controller"; + parameter Real a = 50 "Gain of the histeresis function"; + parameter Real b = 15 "Slope of the saturation function at the origin"; + + // State variables + Real Td(start = Td0, fixed = true) + "Temperature of the fluid in the distribution system"; + Real Tu[N](each start = Tu0, each fixed = true) + "Temperature of individual heated units"; + Real x[N](each start = -0.5, each fixed = true) + "States of heated units temperature controllers"; + Real s[N]; +equation + for i in 1:N loop + s[i]=Gh*(Td - Tu[i])*(sat(b*x[i], -0.5, 0.5)+0.5); + end for; + der(Td) = (sat(Kp*(Td0-Td),0, Qmax) - sum(s))/Cd; + for i in 1:N loop + der(Tu[i]) = (Gh*(Td - Tu[i])*(sat(b*x[i], -0.5, 0.5)+0.5) - Gu*(Tu[i] - (278.15 + 8*sin(2*pi*time/86400))))/Cu[i]; + end for; + for i in 1:N loop + der(x[i]) = a*hist(x[i], Tu0 - Tu[i], Teps); + end for; + annotation(experiment(StopTime = 864000, Tolerance = 1e-4)); +end HeatingSystemExplicit; + diff --git a/examples/causalize/vector/PowerSystem.mo b/examples/causalize/vector/PowerSystem.mo new file mode 100644 index 0000000..3b8c488 --- /dev/null +++ b/examples/causalize/vector/PowerSystem.mo @@ -0,0 +1,169 @@ +model PowerSystem + constant Real pi = 3.1416; + import SI = Modelica.SIunits; + parameter Integer N = 12 "Number of generators in the network"; + parameter Integer M = 12 "Number of volumes in the superheater models"; + + parameter Real P_load[N](each nominal = 1e9) = ones(N) * P_nom "Active power consumed by loads - replace the default binding"; + parameter Real P_nom = 500e6 "Nominal power of a single generator"; + parameter Real f_ref = 50 "Reference network frequency"; + parameter Real omega_ref = 2 * pi * f_ref; + parameter SI.Time T_sfc = 20 "Time constant of secondary frequency control"; + parameter Real P_d = 0.5 * P_nom / omega_ref "Power dissipation coefficient"; + parameter Real droop = 0.10 "Average network droop"; + +///////////////////////// + parameter Integer generator_NFV = M "Number of finite volumes for the superheater model"; + parameter Real generator_P_nom = 500e6 "Nominal power of the generator"; + parameter Real generator_f_ref = 50 "Reference network frequency"; + parameter SI.Time generator_T_a = 5 "Characteristic time of the generator"; + parameter Real generator_alpha = 0.3 "Fraction of turbine power provided by the high-pressure turbine"; + parameter Real generator_T_source = 1.5 "Normalized temperature of heat source for the superheater"; + parameter Real generator_NTU = 2 "Number of thermal units in the superheater"; + parameter SI.Time generator_tau_b = 200 "Characteristic time of energy storage in the boiler"; + parameter SI.Time generator_tau_t = 8 "Characteristic response time of the low pressure turbine"; + parameter SI.Time generator_tau_q = 3 "Characteristic time of thermal generation process"; + parameter SI.Time generator_tau_sh = 100 "Characteristic time of the superheater thermal response"; + parameter SI.Time generator_tau_y = 0.3 "Characteristic time of turbine governor"; + parameter Real generator_droop = 0.1 "Primary frequency control droop"; + parameter Real generator_Kp_p = 10 "Proportional gain of pressure controller"; + parameter SI.Time generator_Ti_p = 70 "Integral time of pressure controller"; + parameter Real generator_Kp_t = 2 "Proportional gain of power controller"; + parameter SI.Time generator_Ti_t = 0.3 "Integral time of power controller"; + final parameter Real generator_omega_ref = 2*pi*generator_f_ref; + final parameter SI.MomentOfInertia generator_J = generator_P_nom*generator_T_a/(generator_omega_ref^2); + parameter Real generator_P_a(nominal = 1e9) = generator_P_nom "Active electrical power produced by the synchronous generator - replace the default binding"; + parameter Real generator_P_t_0(nominal = 1e9) = generator_P_nom "Active power set point - replace the default binding"; + parameter Real generator_P_sfc(nominal = 1e9) = 0 "Additional power request for secondary frequency control - replace the default binding"; + parameter Real generator_p_0 = 1 "Boiler pressure set point in p.u."; + + Real generator_P_t[N] "Mechanical power generated by the turbine [W]"; + Real generator_theta[N] "Rotor angle relative to reference rotating at nominal speed"; + Real generator_omega[N] "Turbine angular speed"; + Real generator_f[N] "Generator frequency"; + Real generator_delta_f[N] "Normalized frequency error"; + Real generator_p[N] "Boiler pressure in p.u."; + Real generator_w_s[N] "Steam flow rate in p.u."; + Real generator_q_ev[N] "Thermal power to the boiler in p.u."; + Real generator_q_ev_0[N] "Thermal power set point in p.u."; + Real generator_y_t[N] "Turbine admittance in p.u"; + Real generator_y_t_0[N] "Turbine admittance set point in p.u."; + Real generator_p_t[N] "Turbine power in p.u."; + Real generator_p_t_0[N] "Turbine power set point in p.u."; + Real generator_p_t_0_fc[N] "Turbine power set point in p.u. with frequency control corrections"; + Real generator_p_t_lp[N] "Low-pressure turbine power in p.u."; + Real generator_T_s[N,generator_NFV] "Normalized temperature states for the superheater model"; + Real generator_T_s_b[N,generator_NFV+1] "Normalized temperature at the boundaries of the superheater volumes"; + + Real generator_err_p_t[N] "Power controller error in p.u."; + Real generator_err_p_t_int[N] "Integral of power controller error"; + + Real generator_err_p[N] "Pressure controller error in p.u."; + Real generator_err_p_int[N] "Pressure controller integral error"; + +///////////////////////// + + + + Real f "Network frequency measured at node 1 for secondary frequency control"; + + Real P_ex[N, N](each nominal = 1e9) "Power going from generator i to generator j"; + Real P_diss[N, N](each nominal = 1e9) "Power dissipated by the generators i and j"; + Real P_a[N](each nominal = 1e9) "Net active power out of generator i"; + parameter Real P_f(nominal = 1e9) = P_nom "Power factor of a single trunk of transmission line"; + Real P_sfc(nominal = 1e9) "Additional power request for secondary frequency control"; + //Generator generator[N](P_a = P_a, each P_nom = P_nom, each P_sfc = P_sfc / N, each NFV = M); + +equation + // Rotor phase angle equation (relative to reference rotating at reference speed) + for i in 1:N loop + der(generator_theta[i]) = generator_omega[i] - generator_omega_ref; + end for; + + // Energy balance on the turbine-generator axis + for i in 1:N loop +// der(generator_J*generator_omega[i]^2/2) = generator_P_t[i] - generator_P_a; + der(generator_omega[i]) = generator_P_t[i] - generator_P_a; + end for; + + // Non-dimensional boiler model + for i in 1:N loop + generator_tau_b*der(generator_p[i]) = generator_q_ev[i] - generator_w_s[i]; + end for; + + // Non-dimensional turbine model + for i in 1:N loop + generator_w_s[i] = generator_y_t[i]*generator_p[i] "steam flow"; + generator_tau_t*der(generator_p_t_lp[i]) + generator_p_t_lp[i] = (1-generator_alpha)*generator_w_s[i] "LP turbine power"; + generator_p_t[i] = generator_alpha *generator_w_s[i] + generator_p_t_lp[i] "Total turbine power"; + + // Non-dimensional steam temperature model + generator_T_s_b[i,1] = generator_p[i] "Boundary condion at inlet"; + + end for; + for i in 1:N, j in 2:generator_NFV+1 loop + generator_T_s_b[i,j] = generator_T_s[i,j-1] "Upwind discretization scheme"; + end for; + for i in 1:generator_NFV, j in 1:N loop + generator_tau_sh/generator_NFV * der(generator_T_s[j,i]) =/* generator_w_s[j]**/(generator_T_s_b[j,i] - generator_T_s_b[j,i+1]) + generator_NTU/generator_NFV*(generator_T_source - generator_T_s_b[j,i+1]); + end for; + + // Actuation + for j in 1:N loop + generator_tau_y*der(generator_y_t[j]) = generator_y_t_0[j] - generator_y_t[j]; + generator_tau_q*der(generator_q_ev[j]) = generator_q_ev_0[j] - generator_q_ev[j]; + end for; + + // Normalization equations + for j in 1:N loop + generator_P_t[j] = generator_p_t[j]*generator_P_nom; + generator_P_t_0 = generator_p_t_0[j]*generator_P_nom; + end for; + + // Boiler follows control strategy with primary and secondary frequency control + for j in 1:N loop + generator_f[j] = generator_omega[j]/(2*pi); + generator_delta_f[j] = (generator_f[j] - generator_f_ref)/generator_f_ref; + generator_p_t_0_fc[j] = generator_p_t_0[j] - 1/generator_droop*generator_delta_f[j] + generator_P_sfc/generator_P_nom; + generator_err_p_t[j] = generator_p_t_0_fc[j] - generator_p_t[j]; + der(generator_err_p_t_int[j]) = generator_err_p_t[j]; + generator_err_p[j] = generator_p_0 - generator_p[j]; + der(generator_err_p_int[j]) = generator_err_p[j]; + + generator_q_ev_0[j] = generator_p_t_0_fc[j] + generator_Kp_p*(generator_err_p[j] + 1/generator_Ti_p *generator_err_p_int[j]); + generator_y_t_0[j] = generator_p_t_0_fc[j] + generator_Kp_t*(generator_err_p_t[j] + 1/generator_Ti_t *generator_err_p_t_int[j]); + end for; +initial equation + for j in 1:N loop + generator_theta[j] = 0; + generator_omega[j] = generator_omega_ref; + generator_p[j] = 1; + generator_p_t_lp[j] = (1-generator_alpha); + generator_y_t[j] = 1; + generator_q_ev[j] = 1; + generator_err_p_t_int[j] = 0; + generator_err_p_int[j] = 0; + generator_T_s[j,1] = (generator_p[j] + generator_NTU/generator_NFV*generator_T_source)/(1 + generator_NTU/generator_NFV); + end for; + for i in 2:generator_NFV, j in 1:N loop + generator_T_s[j,i] = (generator_T_s[j,i-1] + generator_NTU/generator_NFV*generator_T_source)/(1 + generator_NTU/generator_NFV); + end for; + +equation + for i in 1:N loop + P_a[i] =sum(P_ex[i, :]) + sum(P_diss[i, :]) + P_load[i]; + end for; + for i in 1:N, j in 1:N loop + P_ex[i, j] = if i==j then 0 else P_f / abs(i - j) * sin(generator_theta[i] - generator_theta[j]); + P_diss[i, j] = if i == j then 0 else P_d * (generator_omega[i] - generator_omega[j]); + end for; + + f = generator_f[1]; + T_sfc * der(P_sfc) = (f_ref - f) / f_ref * P_nom * N / droop; +initial equation + P_sfc = 0; + annotation(Documentation(info = " +

This model assembles a power system with a linear topology, obtained by connecting N power generators in a linear network with equal transmission lines, and with a load connected to each generator. For simplicity, the loads are described by prescribed active power consumptions.

+

The power transfer between the different generators is computed by the classical swing equation theory. An integral controllers provides secondary frequency control.

+")); +end PowerSystem; diff --git a/examples/causalize/vector/SimpleAdvection.mo b/examples/causalize/vector/SimpleAdvection.mo new file mode 100644 index 0000000..3abc5f7 --- /dev/null +++ b/examples/causalize/vector/SimpleAdvection.mo @@ -0,0 +1,28 @@ +model SimpleAdvection "Basic thermal advection model with uniform speed" + parameter Integer N = 10 "Number of nodes"; + parameter Real Tstart[N]=ones(N)*300 + "Start value of the temperature distribution"; + parameter Real L = 10 "Pipe length"; + final parameter Real l = L/N "Length of one volume"; + Real u = 1 "Fluid speed"; + Real Tin = 300 "Inlet temperature"; + Real T[N] "Node temperatures"; + Real Ttilde[N-1](start = Tstart[2:N], each fixed = true) "Temperature states"; + Real Tout; +equation + for j in 1:N-1 loop + der(Ttilde[j]) = u/l*(T[j]-T[j+1]); + end for; + T[1] = Tin; + T[N] = Tout; + for i in 1:N-1 loop + Ttilde[i] = T[i+1]; + end for; + annotation (Documentation(info=" +

This models solves the temperature advection problem represented by the following PDEs by means of the finite volume method.

+

+

+

The boundary condition at the inlet Tin and the fluid speed u are specified by suitable binding equations.

+")); +end SimpleAdvection; + diff --git a/examples/causalize/vector/Sintetic/example1.mo b/examples/causalize/vector/Sintetic/example1.mo new file mode 100644 index 0000000..9c73b67 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example1.mo @@ -0,0 +1,10 @@ +model A + Real a,b[10,20]; +equation + b[3,5]=12; + for i in 1:10, j in 1:20 loop + b[i,j]+a=1345; + end for; +end A; + +// Cauzalization working. No solving. diff --git a/examples/causalize/vector/Sintetic/example10.mo b/examples/causalize/vector/Sintetic/example10.mo new file mode 100644 index 0000000..ca1a765 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example10.mo @@ -0,0 +1,20 @@ +model A + Real a[13,11],b,c[10]; +equation + for i in 1:10, j in 2:11 loop + a[j+2,i+1]=b; + end for; + for i in 1:13 loop + a[i,1]=2677; + end for; + for i in 1:3 loop + a[i,2]=17; + end for; + for i in 2:10, j in 5:7 loop + a[j-4,i+1]=1777*b; + end for; + b=123; + for i in 1:10 loop + c[i]=17+a[i,4]; + end for; +end A; diff --git a/examples/causalize/vector/Sintetic/example11.mo b/examples/causalize/vector/Sintetic/example11.mo new file mode 100644 index 0000000..0cdf019 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example11.mo @@ -0,0 +1,8 @@ +model A + Real a[13,11]; +equation + for i in 1:13, j in 1:11 loop + a[i,j]+ 2*a[i,j]=3; + end for; +end A; +// Testing use of the same variable diff --git a/examples/causalize/vector/Sintetic/example12.mo b/examples/causalize/vector/Sintetic/example12.mo new file mode 100644 index 0000000..e1a76db --- /dev/null +++ b/examples/causalize/vector/Sintetic/example12.mo @@ -0,0 +1,12 @@ +model A + Real a[5]; +equation + a[5]+sum(a)=13; + for i in 1:4 loop + a[i]=17; + end for; +end A; + + + + diff --git a/examples/causalize/vector/Sintetic/example13.mo b/examples/causalize/vector/Sintetic/example13.mo new file mode 100644 index 0000000..f54a276 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example13.mo @@ -0,0 +1,8 @@ +model A + Real a[5]; +equation + for i in 1:5 loop + a[i]+a[3]=17; + end for; +end A; +// Remove duplicates: OK diff --git a/examples/causalize/vector/Sintetic/example14.mo b/examples/causalize/vector/Sintetic/example14.mo new file mode 100644 index 0000000..1b55a45 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example14.mo @@ -0,0 +1,10 @@ +model A + Real a[12]; +equation + for i in 1:2 loop + a[i]+a[11]=123; + end for; + for i in 1:10 loop + a[i]+a[12]=0; + end for; +end A; diff --git a/examples/causalize/vector/Sintetic/example15.mo b/examples/causalize/vector/Sintetic/example15.mo new file mode 100644 index 0000000..e69de29 diff --git a/examples/causalize/vector/Sintetic/example2.mo b/examples/causalize/vector/Sintetic/example2.mo new file mode 100644 index 0000000..dedf495 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example2.mo @@ -0,0 +1,9 @@ +model A + Real b[10,20]; +equation + for i in 1:10, j in 1:20 loop + b[i,j] + b[j,i]=1345; + end for; +end A; + +// Multiple usages of a same vector with different index usages in a same for equation not supported diff --git a/examples/causalize/vector/Sintetic/example3.mo b/examples/causalize/vector/Sintetic/example3.mo new file mode 100644 index 0000000..22a7612 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example3.mo @@ -0,0 +1,8 @@ +model A + Real b[10]; +equation + b[10]=345; + for i in 1:9 loop + b[i] + b[i+1] = 123; + end for; +end A; diff --git a/examples/causalize/vector/Sintetic/example4.mo b/examples/causalize/vector/Sintetic/example4.mo new file mode 100644 index 0000000..f227ee0 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example4.mo @@ -0,0 +1,10 @@ +model A + Real b[10]; +equation + b[1]=345; + for i in 1:9 loop + b[i] + b[i+1] = 123; + end for; +end A; + +// Modify cancausalize diff --git a/examples/causalize/vector/Sintetic/example5.mo b/examples/causalize/vector/Sintetic/example5.mo new file mode 100644 index 0000000..727a0b1 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example5.mo @@ -0,0 +1,10 @@ +model A + Real b[10]; +equation + b[3]=345; + for i in 1:9 loop + b[i] + b[i+1] = 123; + end for; +end A; + +// Modify cancausalize diff --git a/examples/causalize/vector/Sintetic/example6.mo b/examples/causalize/vector/Sintetic/example6.mo new file mode 100644 index 0000000..2ea4b03 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example6.mo @@ -0,0 +1,18 @@ +model A + Real b[10],a[10]; +equation + for i in 1:10 loop + a[i]+b[i]=23; + end for; + for i in 1:3 loop + a[i]=234; + end for; + for i in 4:7 loop + b[i]=2; + end for; + for i in 8:10 loop + a[i]=282; + end for; +end A; + +// Modify cancausalize diff --git a/examples/causalize/vector/Sintetic/example7.mo b/examples/causalize/vector/Sintetic/example7.mo new file mode 100644 index 0000000..a05a8d6 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example7.mo @@ -0,0 +1,38 @@ +model A + Real b[10,10],a[10,10]; +equation + for i in 1:10, j in 1:10 loop + a[i,j]+b[i,j]=23; + end for; + for i in 1:4, j in 1:3 loop + a[i,j]=35; + end for; + for i in 5:7, j in 1:3 loop + b[i,j]=5; + end for; + for i in 8:10, j in 1:3 loop + a[i,j]=765; + end for; + for i in 1:4, j in 4:7 loop + a[i,j]=75; + end for; + for i in 5:7, j in 4:7 loop + b[i,j]=76; + end for; + for i in 8:10, j in 4:7 loop + a[i,j]=1; + end for; + for i in 8:10, j in 1:4 loop + b[j,i]=31; + end for; + for i in 5:7, j in 8:10 loop + b[i,j]=371; + end for; + for i in 8:10, j in 8:10 loop + a[i,j]=3141; + end for; +end A; + +// Solve is not working + + diff --git a/examples/causalize/vector/Sintetic/example8.mo b/examples/causalize/vector/Sintetic/example8.mo new file mode 100644 index 0000000..9af7391 --- /dev/null +++ b/examples/causalize/vector/Sintetic/example8.mo @@ -0,0 +1,17 @@ +model A + Real b[10]; +equation + sum(b)=123; + //b[1]+ b[2]+ b[3]+ b[4]+ b[5]+ b[6]+ b[7]+ b[8]+ b[9]+ b[10]=53; + for i in 1:3 loop + b[i]=123; + end for; + for i in 5:10 loop + b[i]=123; + end for; + +end A; + +// Sum is not working + + diff --git a/examples/causalize/vector/Sintetic/example9.mo b/examples/causalize/vector/Sintetic/example9.mo new file mode 100644 index 0000000..70af05d --- /dev/null +++ b/examples/causalize/vector/Sintetic/example9.mo @@ -0,0 +1,20 @@ +model A + Real a[13,11]; +equation + for i in 1:10, j in 2:11 loop + a[j+2,i+1]=234; + end for; + for i in 1:13 loop + a[i,1]=2677; + end for; + for i in 1:3 loop + a[i,2]=17; + end for; + for i in 2:10, j in 5:7 loop + a[j-4,i+1]=1777; + end for; +end A; + +// Sum is not working + + diff --git a/examples/causalize/vector/TransmissionLineEquations.mo b/examples/causalize/vector/TransmissionLineEquations.mo new file mode 100644 index 0000000..8f38610 --- /dev/null +++ b/examples/causalize/vector/TransmissionLineEquations.mo @@ -0,0 +1,34 @@ +model TransmissionLineEquations + "Transmission line circuit - Direct implementation by equations" + parameter Integer N = 100 "number of segments"; + parameter Real L = 100 "length of the transmission line"; + final parameter Real l = L / N "length of the each segment"; + parameter Real res = 4.8e-05 "resistance per meter"; + parameter Real cap = 1.01e-10 "capacitance per meter"; + parameter Real ind = 2.53e-07 "inductance per meter"; + parameter Real RL = (ind / cap) ^ (1 / 2) "load resistance"; + parameter Real w = 5000000.0; + final parameter Real TD = L / v "time delay of the transmission line"; + final parameter Real v = 1 / (ind * cap) ^ (1 / 2) "velocity of the signal"; + Real Vstep = if time > 0 then 1 else 0 "input step voltage"; + Real cur_N (start = 0) "current values at the nodes of the transmission line"; + Real cur[N-1](each start = 0) "current values at the nodes of the transmission line"; + Real vol[N](each start = 0) "voltage values at the nodes of the transmission line"; + Real vvol "derivative of input voltage"; +equation + vvol = der(vol[1]); + Vstep = vol[1] + 2 * (1 / w) * der(vol[1]) + 1 / w ^ 2 * der(vvol); + vol[N] = cur_N * RL; + for i in 1:N - 2 loop + cap * der(vol[i + 1]) = (cur[i] - cur[i + 1]) / l; + ind * der(cur[i]) = (-res * cur[i]) - (vol[i + 1] - vol[i]) / l; + end for; + ind * der(cur[N-1]) = (-res * cur[N-1]) - (vol[N] - vol[N-1]) / l; + cap * der(vol[N]) = (cur[N-1] - cur_N) / l; +initial equation + vol = zeros(N); + cur[1:N-1] = zeros(N-1); + vvol = 0; + annotation(experiment(StopTime = 4e-6, Tolerance = 1e-6)); +end TransmissionLineEquations; + diff --git a/test/causalize/ELECTRICALLY_HEATED_ROD.mo b/test/causalize/ELECTRICALLY_HEATED_ROD.mo new file mode 100644 index 0000000..8731c98 --- /dev/null +++ b/test/causalize/ELECTRICALLY_HEATED_ROD.mo @@ -0,0 +1,16 @@ +model ELECTRICALLY_HEATED_ROD + constant Integer N = 10; + parameter Real delR=1, p_elec=1, deltav=1, r=1, omega=1, k1=1, k2=1, Troom=1; + Real T[N], T0, TL, dTdrR; +equation + der (T[1]) = omega * ((T[2] - 2 * T[1] + T0) / delR + (T[2]-T0) / (r * 2 * delR) + p_elec / deltav); + for i in 2:N-1 loop + der (T[i]) = omega * ((T[i+1] - 2 * T[i] + T[i-1]) / delR + (T[i+1]-T[i-1]) / (r * 2 * delR) + p_elec / deltav); + end for; + der (T[N]) = omega * ((TL - 2 * T[N] + T[N-1]) / delR + (TL-T[N-1]) / (r * 2 * delR) + p_elec / deltav); + T0 = 4 / 3 * T[1] - T[2]; + dTdrR = -k1 * (TL ^ 4 - Troom ^ 4) - k2 * (TL - Troom); + dTdrR = (-3 * TL - 4*T[N] - T[N-1]) / (2*delR); +end ELECTRICALLY_HEATED_ROD; + + diff --git a/test/causalize/ELECTRICALLY_HEATED_ROD_MULTIDIM.mo b/test/causalize/ELECTRICALLY_HEATED_ROD_MULTIDIM.mo new file mode 100644 index 0000000..f21cf0b --- /dev/null +++ b/test/causalize/ELECTRICALLY_HEATED_ROD_MULTIDIM.mo @@ -0,0 +1,29 @@ +model ELECTRICALLY_HEATED_ROD_MULTIDIM + constant Integer N = 5; + constant Integer M = 5; + parameter Real delR=1, delX=1, p_elec=1, deltav=1, r=1, omega=1, k1=1, k2=1, Troom=1; + Real T[N,M], T0[M], TL[M], dTdrR[M]; +equation + der(T[1,1]) = omega * ((T[2,1] - 2 * T[1,1] + T0[1]) / delR + (T[2,1]-T0[1]) / (r * 2 * delR) + (T[1,2] - 2 * T[1,1] + Troom) / delX + p_elec / deltav); + der(T[N,1]) = omega * ((TL[1] - 2 * T[N,1] + T0[1]) / delR + (TL[1]-T[N-1,1]) / (r * 2 * delR) + (T[N,2] - 2 * T[N,1] + Troom) / delX + p_elec / deltav); + der(T[N,M]) = omega * ((TL[M] - 2 * T[N,M] + T0[M]) / delR + (TL[M]-T[N-1,M]) / (r * 2 * delR) + (Troom - 2 * T[N,M] + T[N,M-1]) / delX + p_elec / deltav); + der(T[1,M]) = omega * ((T[2,M] - 2 * T[1,M] + T0[M]) / delR + (T[2,M]-T0[M]) / (r * 2 * delR) + (Troom - 2 * T[1,M] + T[1,M-1]) / delX + p_elec / deltav); + for i in 2:N-1 loop + der (T[i,1]) = omega * ((T[i+1,1] - 2 * T[i,1] + T[i-1,1]) / delR + (T[i+1,1]-T[i-1,1]) / (r * 2 * delR) + (T[i,2] - 2 * T[i,1] + Troom) / delX + p_elec / deltav); + der (T[i,M]) = omega * ((T[i+1,M] - 2 * T[i,M] + T[i-1,M]) / delR + (T[i+1,M]-T[i-1,M]) / (r * 2 * delR) + (Troom - 2 * T[i,M] + T[i,M-1]) / delX + p_elec / deltav); + end for; + for j in 2:M-1 loop + der (T[1,j]) = omega * ((T[2,j] - 2 * T[1,j] + T0[j]) / delR + (T[2,j]-T0[j]) / (r * 2 * delR) + (T[1,j+1] - 2 * T[1,j] + T[1,j-1]) / delX + p_elec / deltav); + der (T[N,j]) = omega * ((TL[j] - 2 * T[N,j] + T[N-1,j]) / delR + (TL[j]-T[N-1,j]) / (r * 2 * delR) + (T[N,j+1] - 2 * T[N,j] + T[N,j-1]) / delX + p_elec / deltav); + end for; + for i in 2:N-1, j in 2:M-1 loop + der (T[i,j]) = omega * ((T[i+1,j] - 2 * T[i,j] + T[i-1,j]) / delR + (T[i+1,j]-T[i-1,j]) / (r * 2 * delR) + (T[i,j+1] - 2 * T[i,j] + T[i,j-1]) / delX + p_elec / deltav); + end for; + for j in 1:M loop + T0[j] = 4 / 3 * T[1,j] - T[2,j]; + dTdrR[j] = -k1 * (TL[j] ^ 4 - Troom ^ 4) - k2 * (TL[j] - Troom); + dTdrR[j] = (-3 * TL[j] - 4*T[N,j] - T[N-1,j]) / (2*delR); + end for; +end ELECTRICALLY_HEATED_ROD_MULTIDIM; + + diff --git a/test/causalize/Makefile.include b/test/causalize/Makefile.include index b65d70e..2db42ac 100644 --- a/test/causalize/Makefile.include +++ b/test/causalize/Makefile.include @@ -1,31 +1,46 @@ -OBJS_TEST_CAUSALIZATION := $(OBJS_COMMON) \ +OBJS_CAUSALIZATION_COMMON := $(OBJS_COMMON) \ util/debug.o \ util/table.o \ util/type.o \ util/solve/solve.o \ - util/ast_visitors/evalexp.o \ - util/ast_visitors/part_evalexp.o \ + util/ast_visitors/eval_expression.o \ + util/ast_visitors/partial_eval_expression.o \ util/ast_visitors/ginac_interface.o \ - util/ast_visitors/contains.o \ + util/ast_visitors/contains_expression.o \ util/ast_visitors/state_variables_finder.o \ - causalize/graph_implementation/for_unrolling/for_index_iterator.o \ - causalize/graph_implementation/for_unrolling/process_for_equations.o \ + mmo/mmo_class.o + +OBJS_TEST_GRP_CAUSALIZATION := \ causalize/graph_implementation/unknowns_collector.o \ causalize/graph_implementation/causalization_strategy.o \ causalize/graph_implementation/vector/contains_vector.o \ causalize/graph_implementation/vector/graph_builder.o \ causalize/graph_implementation/apply_tarjan.o \ - mmo/mmo_class.o - + causalize/common/for_unrolling/for_index_iterator.o \ + causalize/common/for_unrolling/process_for_equations.o \ + +OBJS_TEST_VG_CAUSALIZATION := \ + causalize/vg_implementation/unknowns_collector.o \ + causalize/vg_implementation/causalization_strategy.o \ + causalize/vg_implementation/contains_unknown.o \ + causalize/vg_implementation/vector/contains_vector.o \ + causalize/vg_implementation/vector/vector_graph_definition.o \ + causalize/vg_implementation/graph/graph_definition.o \ + causalize/vg_implementation/vector/graph_builder.o \ + causalize/vg_implementation/apply_tarjan.o \ + OBJS_TEST_TARJAN := util/debug.o \ causalize/graph_implementation/apply_tarjan.o \ test/causalize/apply_tarjan_test.o TEST_LIBS = -lboost_unit_test_framework -L./lib -lmodelica -lginac -test/causalize/causalization_strategy_test: $(OBJS_TEST_CAUSALIZATION) test/causalize/graph_implementation/causalization_strategy_test.o - $(CXX) $(CXXFLAGS) -o test/causalize/graph_implementation/causalization_strategy_test $(OBJS_TEST_CAUSALIZATION) test/causalize/graph_implementation/causalization_strategy_test.o $(TEST_LIBS) - +test/causalize/graph_implementation/causalization_strategy_test: $(OBJS_CAUSALIZATION_COMMON) $(OBJS_TEST_GRP_CAUSALIZATION) test/causalize/graph_implementation/causalization_strategy_test.o + $(CXX) $(CXXFLAGS) -o test/causalize/graph_implementation/causalization_strategy_test $(OBJS_CAUSALIZATION_COMMON) $(OBJS_TEST_GRP_CAUSALIZATION) test/causalize/graph_implementation/causalization_strategy_test.o $(TEST_LIBS) + +test/causalize/vg_implementation/causalization_strategy_test: $(OBJS_CAUSALIZATION_COMMON) $(OBJS_TEST_VG_CAUSALIZATION) test/causalize/vg_implementation/causalization_strategy_test.o + $(CXX) $(CXXFLAGS) -o test/causalize/vg_implementation/causalization_strategy_test $(OBJS_CAUSALIZATION_COMMON) $(OBJS_TEST_VG_CAUSALIZATION) test/causalize/vg_implemetation/causalization_strategy_test.o $(TEST_LIBS) + test/causalize/apply_tarjan_test: $(OBJS_TEST_TARJAN) lib/libmodelica.a $(CXX) $(CXXFLAGS) -o test/causalize/graph_implementation/apply_tarjan_test $(OBJS_TEST_TARJAN) $(TEST_LIBS) diff --git a/test/causalize/OneDHeatTransferTI_FD_100.mo b/test/causalize/OneDHeatTransferTI_FD_100.mo new file mode 100644 index 0000000..0215793 --- /dev/null +++ b/test/causalize/OneDHeatTransferTI_FD_100.mo @@ -0,0 +1,33 @@ +model OneDHeatTransferTI_FD + parameter Real L = 0.2; + constant Integer N = 100; + parameter Real T0 = 273.15; + parameter Real TN = 330; + parameter Real cp = 910 ; + parameter Real lambda = 237 ; + parameter Real rho = 2712 ; + final parameter Real dx = L / (N - 1); + Real T[N] ; +initial algorithm + for i in 1:N - 1 loop + T[i] := T0; + end for; + T[N] := TN; +equation + der(T[N]) = 0; + for i in 2:N - 1 loop + der(T[i]) = lambda * ((T[i + 1] - T[i]) / dx + ((-T[i]) + T[i - 1]) / dx) / cp / rho / dx; + end for; + der(T[1]) = lambda * ((T[2] - T[1]) / dx) / cp / rho / dx; + annotation( + + experiment( + MMO_Description="", + MMO_Solver=DOPRI, + MMO_Output={T[1]}, + StartTime=0.0, + StopTime=1, + Tolerance={1e-6}, + AbsTolerance={1e-6} + )); +end OneDHeatTransferTI_FD; diff --git a/test/causalize/OneDHeatTransferTI_FD_complicated.mo b/test/causalize/OneDHeatTransferTI_FD_complicated.mo new file mode 100644 index 0000000..af2915f --- /dev/null +++ b/test/causalize/OneDHeatTransferTI_FD_complicated.mo @@ -0,0 +1,33 @@ +model OneDHeatTransferTI_FD + parameter Real L = 0.2; + constant Integer N = 100000000; + parameter Real T0 = 273.15; + parameter Real TN = 330; + parameter Real cp = 910 ; + parameter Real lambda = 237 ; + parameter Real rho = 2712 ; + final parameter Real dx = L / (N - 1); + Real T[N] ; +initial algorithm + for i in 1:N - 1 loop + T[i] := T0; + end for; + T[N] := TN; +equation + der(T[1]) = lambda * ((T[2] - T[1]) / dx) / cp / rho / dx; + for i in 2:N - 1 loop + der(T[i]) = der(T[i-1]) + lambda * ((T[i + 1] - T[i]) / dx + ((-T[i]) + T[i - 1]) / dx) / cp / rho / dx; + end for; + der(T[N]) = 0; + annotation( + + experiment( + MMO_Description="", + MMO_Solver=DOPRI, + MMO_Output={T[1]}, + StartTime=0.0, + StopTime=1, + Tolerance={1e-6}, + AbsTolerance={1e-6} + )); +end OneDHeatTransferTI_FD; diff --git a/test/causalize/OneDHeatTransferTI_FD_impossible.mo b/test/causalize/OneDHeatTransferTI_FD_impossible.mo new file mode 100644 index 0000000..a25dbf1 --- /dev/null +++ b/test/causalize/OneDHeatTransferTI_FD_impossible.mo @@ -0,0 +1,33 @@ +model OneDHeatTransferTI_FD + parameter Real L = 0.2; + constant Integer N = 100; + parameter Real T0 = 273.15; + parameter Real TN = 330; + parameter Real cp = 910 ; + parameter Real lambda = 237 ; + parameter Real rho = 2712 ; + final parameter Real dx = L / (N - 1); + Real T[N] ; +initial algorithm + for i in 1:N - 1 loop + T[i] := T0; + end for; + T[N] := TN; +equation + der(T[1]) = lambda * ((T[2] - T[1]) / dx) / cp / rho / dx; + for i in 2:N - 1 loop + der(T[i]) = der(T[i-1]) + der(T[i+1]) + lambda * ((T[i + 1] - T[i]) / dx + ((-T[i]) + T[i - 1]) / dx) / cp / rho / dx; + end for; + der(T[N]) = 0; + annotation( + + experiment( + MMO_Description="", + MMO_Solver=DOPRI, + MMO_Output={T[1]}, + StartTime=0.0, + StopTime=1, + Tolerance={1e-6}, + AbsTolerance={1e-6} + )); +end OneDHeatTransferTI_FD; diff --git a/test/causalize/OneDHeatTransferTI_FD_loop.mo b/test/causalize/OneDHeatTransferTI_FD_loop.mo index 3dc3604..06ffcf7 100644 --- a/test/causalize/OneDHeatTransferTI_FD_loop.mo +++ b/test/causalize/OneDHeatTransferTI_FD_loop.mo @@ -1,6 +1,6 @@ -model OneDHeatTransferTI_FD +model OneDHeatTransferTI_FD_loop parameter Real L = 0.2; - constant Integer N = 100; + constant Integer N = 10; parameter Real T0 = 273.15; parameter Real TN = 330; parameter Real cp = 910 ; @@ -33,4 +33,4 @@ equation Tolerance={1e-6}, AbsTolerance={1e-6} )); -end OneDHeatTransferTI_FD; +end OneDHeatTransferTI_FD_loop; diff --git a/test/causalize/adventionReaction2D.mo b/test/causalize/adventionReaction2D.mo new file mode 100644 index 0000000..bc7591a --- /dev/null +++ b/test/causalize/adventionReaction2D.mo @@ -0,0 +1,28 @@ +model AdvectionReaction2D +import file; + parameter Real dT=1e-3; + parameter Real ax=1,ay=1,r=1000; + constant Integer N = 10, M=10; + parameter Real dx=10/N; + parameter Real dy=10/M; + Real u[N,M](each fixed=false); + Real reaction[N,M](each fixed=false); +initial equation + for i in 1:5 loop + u[1,i]=1; + end for; +equation + der(u[1,1])=(-u[1,1]*ax/dx)+(-u[1,1]*ay/dy) + reaction[1,1]; + for i in 2:N loop + der(u[i,1])=(-u[i,1]*ax/dx)+(-u[i,1]+u[i-1,1])*ay/dy + reaction[i,1]; + end for; + for i in 2:M loop + der(u[1,i])=(-u[1,i]+u[1,i-1])*ax/dx+(-u[1,i]*ay/dy) + reaction[1,i]; + end for; + for i in 2:N, j in 2:M loop + der(u[i,j])=(-u[i,j]+u[i,j-1])*ax/dx+(-u[i,j]+u[i-1,j])*ay/dy + reaction[i,j]; + end for; + for i in 1:N, j in 1:M loop + reaction[i,j] = r*u[i,j]^2*(1-u[i,j]); + end for; +end AdvectionReaction2D; diff --git a/test/causalize/bug1.mo b/test/causalize/bug1.mo new file mode 100644 index 0000000..9cd82c2 --- /dev/null +++ b/test/causalize/bug1.mo @@ -0,0 +1,9 @@ +model RLC + constant Integer N = 10; + Real A[N], B[N]; +equation + for i in 1:N loop + A[i] + B[i] = 7; + A[i] - B[N-i+1] = 1; + end for; +end RLC; diff --git a/test/causalize/bug2.mo b/test/causalize/bug2.mo new file mode 100644 index 0000000..73bce11 --- /dev/null +++ b/test/causalize/bug2.mo @@ -0,0 +1,12 @@ +model RLC + constant Integer N = 1000000; + Real A[N], B[N]; +equation + for i in 1:N loop + A[i] + B[i] = 7; + end for; + for i in 1:N/2 loop + A[i] - B[i] = 1; + A[i+N/2] - B[i+N/2] = 3; + end for; +end RLC; diff --git a/test/causalize/bugVectorial.mo b/test/causalize/bugVectorial.mo new file mode 100644 index 0000000..94e5883 --- /dev/null +++ b/test/causalize/bugVectorial.mo @@ -0,0 +1,11 @@ +model RLC + constant Integer N = 10; + Real A[N], B[N]; +equation + for i in 1:N loop + B[i] = i; + end for; + for i in 1:N loop + A[i] * A[i] + B[2] = 12; + end for; +end RLC; diff --git a/test/causalize/causalization_strategy_test.cpp b/test/causalize/causalization_strategy_test.cpp index 274cb27..4eb812d 100644 --- a/test/causalize/causalization_strategy_test.cpp +++ b/test/causalize/causalization_strategy_test.cpp @@ -1,8 +1,14 @@ #include #include +<<<<<<< HEAD #include #include +======= +#include +#include +#include +>>>>>>> origin/experimental_multidim_intentional_causalization #include #include @@ -10,23 +16,27 @@ #include #include #include -#include +#include #include using namespace boost::unit_test; using namespace Modelica::AST; +using namespace Causalize; +<<<<<<< HEAD void check_causality(MMO_Class& mmoClass, ExpList unknowns) { const EquationList& causalEqs = mmoClass.equations_ref().equations_ref(); +======= +void check_causality(MMO_Class &mmo_class, ExpList unknowns) { - /* - * Here we collect the left side of each - * equation. - */ - ExpList knowns; + const EquationList &causalEqs = mmo_class.equations_ref().equations_ref(); +>>>>>>> origin/experimental_multidim_intentional_causalization + foreach_(Equation equation, causalEqs) { + +<<<<<<< HEAD foreach_(Equation equation, causalEqs) { Equality eqEq = boost::get(equation); @@ -42,11 +52,17 @@ void check_causality(MMO_Class& mmoClass, ExpList unknowns) foreach_(OptExp oe, output.args()) { if (oe) knowns.push_back(oe.get()); +======= + ContainsUnknown occurrs(unknowns, mmo_class.syms()); + ERROR_UNLESS(is(equation),"Must be only equality equations here"); + Equality eqEq = boost::get(equation); + Apply(occurrs, eqEq.right_ref()); + if (occurrs.getUsages().size()!=0) { + ERROR("Using no causalized unknown"); +>>>>>>> origin/experimental_multidim_intentional_causalization } - } else { - ERROR("Unexpected type for equation's left expression\n"); - } +<<<<<<< HEAD foreach_(Expression unknown, unknowns) { Modelica::contains occurrs(unknown); @@ -59,16 +75,38 @@ void check_causality(MMO_Class& mmoClass, ExpList unknowns) } } BOOST_CHECK(isKnown); +======= + ExpList::iterator known = std::find(unknowns.begin(), unknowns.end(), eqEq.left_ref()); + if (known!=unknowns.end()) { + unknowns.erase(known); + } else { + ERROR("Causalizing unknown already causalized"); +>>>>>>> origin/experimental_multidim_intentional_causalization } + } +<<<<<<< HEAD } +======= + + if (unknowns.size()!=0) { + ERROR("Uncausalized unknowns"); + } else { + std::cout << "Model causalized correctly\n"; + } + +>>>>>>> origin/experimental_multidim_intentional_causalization } void rlc_test() { bool r; +<<<<<<< HEAD StoredDef sd = parseFile("rlc.mo", r); +======= + StoredDef sd = Parser::ParseFile("rlc.mo",r); +>>>>>>> origin/experimental_multidim_intentional_causalization if (!r) ERROR("Can't parse file\n"); @@ -78,8 +116,8 @@ void rlc_test() UnknownsCollector collector(mmo); ExpList unknowns = collector.collectUnknowns(); - CausalizationStrategy cStrategy(mmo); - cStrategy.causalize("Anything"); + Causalize::CausalizationStrategy cStrategy(mmo); + cStrategy.Causalize(); check_causality(mmo, unknowns); } @@ -88,7 +126,11 @@ void rlc_simple_test() { bool r; +<<<<<<< HEAD StoredDef sd = parseFile("rlc.mo", r); +======= + StoredDef sd = Parser::ParseFile("rlc.mo",r); +>>>>>>> origin/experimental_multidim_intentional_causalization if (!r) ERROR("Can't parse file\n"); @@ -98,8 +140,8 @@ void rlc_simple_test() UnknownsCollector collector(mmo); ExpList unknowns = collector.collectUnknowns(); - CausalizationStrategy cStrategy(mmo); - cStrategy.causalize_simple("Anything"); + Causalize::CausalizationStrategy cStrategy(mmo); + cStrategy.CausalizeSimple(); check_causality(mmo, unknowns); } @@ -108,7 +150,11 @@ void rlc_loop_test() { bool r; +<<<<<<< HEAD StoredDef sd = parseFile("rlc_loop.mo", r); +======= + StoredDef sd = Parser::ParseFile("rlc_loop.mo",r); +>>>>>>> origin/experimental_multidim_intentional_causalization if (!r) ERROR("Can't parse file\n"); @@ -118,8 +164,8 @@ void rlc_loop_test() UnknownsCollector collector(mmo); ExpList unknowns = collector.collectUnknowns(); - CausalizationStrategy cStrategy(mmo); - cStrategy.causalize("Anything"); + Causalize::CausalizationStrategy cStrategy(mmo); + cStrategy.Causalize(); check_causality(mmo, unknowns); } @@ -128,7 +174,11 @@ void rlc_loop_tarjan_test() { bool r; +<<<<<<< HEAD StoredDef sd = parseFile("rlc_loop.mo", r); +======= + StoredDef sd = Parser::ParseFile("rlc_loop.mo",r); +>>>>>>> origin/experimental_multidim_intentional_causalization if (!r) ERROR("Can't parse file\n"); @@ -138,8 +188,8 @@ void rlc_loop_tarjan_test() UnknownsCollector collector(mmo); ExpList unknowns = collector.collectUnknowns(); - CausalizationStrategy cStrategy(mmo); - cStrategy.causalize_tarjan("Anything"); + Causalize::CausalizationStrategy cStrategy(mmo); + cStrategy.CausalizeTarjan(); check_causality(mmo, unknowns); } @@ -148,7 +198,11 @@ void OneDHeatTransferTI_FD_test() { bool r; +<<<<<<< HEAD StoredDef sd = parseFile("OneDHeatTransferTI_FD_100.mo", r); +======= + StoredDef sd = Parser::ParseFile("OneDHeatTransferTI_FD_100.mo",r); +>>>>>>> origin/experimental_multidim_intentional_causalization if (!r) ERROR("Can't parse file\n"); @@ -158,8 +212,8 @@ void OneDHeatTransferTI_FD_test() UnknownsCollector collector(mmo); ExpList unknowns = collector.collectUnknowns(); - CausalizationStrategy cStrategy(mmo); - cStrategy.causalize("Anything"); + Causalize::CausalizationStrategy cStrategy(mmo); + cStrategy.Causalize(); check_causality(mmo, unknowns); } @@ -168,7 +222,11 @@ void OneDHeatTransferTI_FD_simple_test() { bool r; +<<<<<<< HEAD StoredDef sd = parseFile("OneDHeatTransferTI_FD.mo", r); +======= + StoredDef sd = Parser::ParseFile("OneDHeatTransferTI_FD.mo",r); +>>>>>>> origin/experimental_multidim_intentional_causalization if (!r) ERROR("Can't parse file\n"); @@ -178,8 +236,8 @@ void OneDHeatTransferTI_FD_simple_test() UnknownsCollector collector(mmo); ExpList unknowns = collector.collectUnknowns(); - CausalizationStrategy cStrategy(mmo); - cStrategy.causalize_simple("Anything"); + Causalize::CausalizationStrategy cStrategy(mmo); + cStrategy.CausalizeSimple(); check_causality(mmo, unknowns); } diff --git a/test/causalize/ecvec.mo b/test/causalize/ecvec.mo new file mode 100644 index 0000000..55707ff --- /dev/null +++ b/test/causalize/ecvec.mo @@ -0,0 +1,9 @@ +model ECVEC + constant Integer N = 1; + Real A[N], B[N]; +equation + for i in 1:N loop + B[i] = i; + A[i] * A[i]- B[i] = 1; + end for; +end ECVEC; diff --git a/test/causalize/ecvec_newton.mo b/test/causalize/ecvec_newton.mo new file mode 100644 index 0000000..50709a3 --- /dev/null +++ b/test/causalize/ecvec_newton.mo @@ -0,0 +1,9 @@ +model ECVEC_NEWTON + constant Integer N = 10000; + Real A[N], B[N]; +equation + for i in 1:N loop + B[i] = i; + A[i] * A[i] - B[i] = 1; + end for; +end ECVEC_SOL; diff --git a/test/causalize/ecvec_newton_sol.mo b/test/causalize/ecvec_newton_sol.mo new file mode 100644 index 0000000..03afa4c --- /dev/null +++ b/test/causalize/ecvec_newton_sol.mo @@ -0,0 +1,17 @@ +model ECVEC_NEWTON_SOL + function fsolve1 + input Real u_0; + output Real y_0; + external "C" y_0 = fsolve1(u_0) annotation(Library={"m","gsl","blas"},Include="#include \"ECVEC.c\""); + end fsolve1; + constant Integer N=10000; + Real A[N]; + Real B[N]; +equation + for i in 1:N loop + B[i] = i; + end for; + for i in 1:N loop + A[i] = fsolve1(B[i]); + end for; +end ECVEC_NEWTON_SOL; diff --git a/test/causalize/ejemploKofman.mo b/test/causalize/ejemploKofman.mo new file mode 100644 index 0000000..5c5984d --- /dev/null +++ b/test/causalize/ejemploKofman.mo @@ -0,0 +1,21 @@ +model RLC + constant Integer N = 1000; + parameter Real R1=1,R2=1,L=1,C1=1,C2=1,Vs=1,R=1; + Real IR2[N], IL[N], UC1[N], Ua[N], IR1[N], UC2[N]; + Real VR, IR; +equation + L*der(IL[1]) = Vs - Ua[1]; + C2*der(UC2[N]) = IR2[N] - IR; + for i in 1:N loop + IR1[i] = (Ua[i] - UC1[i])/R1; + IR2[i] = (Ua[i] - UC2[i])/R2; + IL[i] = IR1[i] + IR2[i]; + C1*der(UC1[i]) = IR1[i]; + end for; + for i in 1:N-1 loop + C2*der(UC2[i]) = IR2[i] - IL[i+1]; + L*der(IL[i+1]) = UC2[i]-Ua[i+1]; + end for; + VR = R*IR; + UC2[N] = VR; +end RLC; diff --git a/test/causalize/kofman.mo b/test/causalize/kofman.mo new file mode 100755 index 0000000..93995c2 --- /dev/null +++ b/test/causalize/kofman.mo @@ -0,0 +1,21 @@ +model RLC + constant Integer N = 10; + parameter Real R1=1,R2=1,L=1,C1=1,C2=1,Vs=1,R=1; + Real IR2[N], IL[N], UC1[N], Ua[N], IR1[N], UC2[N]; + Real VR, IR; +equation + L*der(IL[1]) = Vs - Ua[1]; + C2*der(UC2[N]) = IR2[N] - IR; + for i in 1:N loop + IR1[i] = (Ua[i] - UC1[i])/R1; + IR2[i] = (Ua[i] - UC2[i])/R2; + IL[i] = IR1[i] + IR2[i]; + C1*der(UC1[i]) = IR1[i]; + end for; + for i in 1:N-1 loop + C2*der(UC2[i]) = IR2[i] - IL[i+1]; + L*der(IL[i+1]) = UC2[i]-Ua[i+1]; + end for; + VR = R*IR; + UC2[N] = VR; +end RLC; diff --git a/test/causalize/lazo_newton.mo b/test/causalize/lazo_newton.mo new file mode 100644 index 0000000..943ffdb --- /dev/null +++ b/test/causalize/lazo_newton.mo @@ -0,0 +1,10 @@ +model LAZO_NEWTON + constant Integer N = 1; + Real A[N],B[N],C[N]; +equation + for i in 1:N loop + C[i] = i; + A[i] * A[i] + B[i] * B[i] * B[i] + C[i] = 9; + A[i] * A[i] * A[i] + B[i] * B[i] = 10; + end for; +end LAZO_NEWTON; diff --git a/test/causalize/lazo_newton_sol.mo b/test/causalize/lazo_newton_sol.mo new file mode 100644 index 0000000..15a8038 --- /dev/null +++ b/test/causalize/lazo_newton_sol.mo @@ -0,0 +1,17 @@ +model LAZO_NEWTON_SOL + function fsolve1 + input Real u_0; + output Real y_0; + output Real y_1; + external "C" fsolve1(u_0,y_0,y_1) annotation(Library={"m","gsl","blas"},Include="#include \"LAZO_NEWTON.c\""); + end fsolve1; + constant Integer N=1; + Real A[N]; + Real B[N]; + Real C[N]; +equation + for i in 1:N loop + C[i] = i; + (A[i],B[i]) = fsolve1(C[i]); + end for; +end LAZO_NEWTON_SOL; diff --git a/test/causalize/redrc.mo b/test/causalize/redrc.mo new file mode 100644 index 0000000..6fb3164 --- /dev/null +++ b/test/causalize/redrc.mo @@ -0,0 +1,24 @@ +model REDRC + constant Integer N = 5; + Real iC[N]; + Real iR[N]; + Real uR[N]; + Real uC[N]; + parameter Real iL; + parameter Real v; + parameter Real R[N]; + parameter Real C[N]; +equation + for j in 1:N loop + R[j] * iR[j] - uR[j] = 0; + C[j] * der (uC[j]) - iC[j] = 0; + end for; + for i in 1:N-1 loop + iR[i] - iC[i] - iR[i+1] = 0; + end for; + for i in 2:N loop + uC[i-1] - uR[i] - uC[i] = 0; + end for; + v - uR[1] - uC[1] = 0; + iR[N] - iC[N] - iL = 0; +end REDRC; diff --git a/test/causalize/rlc_circuit.mo b/test/causalize/rlc_circuit.mo new file mode 100644 index 0000000..9091c7d --- /dev/null +++ b/test/causalize/rlc_circuit.mo @@ -0,0 +1,21 @@ +model RLC_CIRCUIT + constant Integer N = 10; + parameter Real R1=1,R2=1,L=1,C1=1,C2=1,Vs=1,R=1; + Real IR2[N], IL[N], UC1[N], Ua[N], IR1[N], UC2[N]; + Real VR, IR; +equation + L*der(IL[1]) = Vs - Ua[1]; + C2*der(UC2[N]) = IR2[N] - IR; + for i in 1:N loop + IR1[i] = (Ua[i] - UC1[i])/R1; + IR2[i] = (Ua[i] - UC2[i])/R2; + IL[i] = IR1[i] + IR2[i]; + C1*der(UC1[i]) = IR1[i]; + end for; + for i in 1:N-1 loop + C2*der(UC2[i]) = IR2[i] - IL[i+1]; + L*der(IL[i+1]) = UC2[i]-Ua[i+1]; + end for; + VR = R*IR; + UC2[N] = VR; +end RLC_CIRCUIT; diff --git a/test/causalize/tarjan1.mo b/test/causalize/tarjan1.mo new file mode 100644 index 0000000..d91abe6 --- /dev/null +++ b/test/causalize/tarjan1.mo @@ -0,0 +1,9 @@ +model RLC + constant Integer N = 10; + Real A[N], B[N]; +equation + for i in 1:N loop + A[i] + B[i] = 7; + A[i] - B[i] = 1; + end for; +end RLC; diff --git a/test/causalize/tarjan1.mo.mo b/test/causalize/tarjan1.mo.mo new file mode 100644 index 0000000..d91abe6 --- /dev/null +++ b/test/causalize/tarjan1.mo.mo @@ -0,0 +1,9 @@ +model RLC + constant Integer N = 10; + Real A[N], B[N]; +equation + for i in 1:N loop + A[i] + B[i] = 7; + A[i] - B[i] = 1; + end for; +end RLC; diff --git a/test/causalize/tarjan1b.mo b/test/causalize/tarjan1b.mo new file mode 100644 index 0000000..5bbc507 --- /dev/null +++ b/test/causalize/tarjan1b.mo @@ -0,0 +1,7 @@ +model RLC + constant Integer N = 1; + Real A[N], B[N]; +equation + A[1] + B[1] = 7; + A[1] - B[1] = 1; +end RLC; diff --git a/test/causalize/tarjan1c.mo b/test/causalize/tarjan1c.mo new file mode 100644 index 0000000..73a33da --- /dev/null +++ b/test/causalize/tarjan1c.mo @@ -0,0 +1,13 @@ +model RLC + constant Integer N = 5; + Real A[N], B[N]; +equation + for i in 1:N-1 loop + A[i] + B[i+1] = 7; + end for; + for i in 2:N loop + A[i-1] - B[i] = 1; + end for; + A[N] = 4; + B[1] = 3; +end RLC; diff --git a/test/causalize/tarjan1d.mo b/test/causalize/tarjan1d.mo new file mode 100644 index 0000000..6dc8d2d --- /dev/null +++ b/test/causalize/tarjan1d.mo @@ -0,0 +1,16 @@ +model RLC + constant Integer N = 10000000; + Real A[N], B[N], C[N]; +equation + for i in 1:N loop + C[i] = i; + end for; + for i in 1:N-1 loop + A[i] + B[i+1] = 7; + end for; + for i in 1:N-1 loop + A[i] - B[i+1] * B[i+1] + C[i+1] + i = 1; + end for; + A[N] = 4; + B[1] = 3; +end RLC; diff --git a/test/causalize/tarjan2.mo b/test/causalize/tarjan2.mo new file mode 100644 index 0000000..c8b7c1c --- /dev/null +++ b/test/causalize/tarjan2.mo @@ -0,0 +1,12 @@ +model RLC + constant Integer N = 10; + Real A[N], B[N]; +equation + for i in 1:N loop + A[i] + B[i] = 7; + end for; + for i in 1:N-1 loop + A[i+1] - B[i] = 1; + end for; + A[1] = 4; +end RLC; diff --git a/test/causalize/tarjan2D.mo b/test/causalize/tarjan2D.mo new file mode 100644 index 0000000..026d59c --- /dev/null +++ b/test/causalize/tarjan2D.mo @@ -0,0 +1,10 @@ +model RLC + constant Integer N = 5; + Real A[N,N], B[N,N], C[N,N]; +equation + for i in 1:N, j in 1:N loop + C[i,j] = i+j; + A[i,j] + B[i,j] * B[i,j] + C[i,j]+C[1,1] = 7; + A[i,j] - B[i,j] = 1; + end for; +end RLC; diff --git a/test/causalize/tarjan2b.mo b/test/causalize/tarjan2b.mo new file mode 100644 index 0000000..6628ef4 --- /dev/null +++ b/test/causalize/tarjan2b.mo @@ -0,0 +1,13 @@ +model RLC + constant Integer N = 10; + Real A[N], B[N]; +equation + + for i in 1:N loop + A[i] + B[i] = 7; + end for; + for i in 1:N-1 loop + A[i+1] - B[i] = 1; + end for; + A[1] = 4; +end RLC; diff --git a/test/causalize/tarjan3.mo b/test/causalize/tarjan3.mo new file mode 100644 index 0000000..8b8be06 --- /dev/null +++ b/test/causalize/tarjan3.mo @@ -0,0 +1,9 @@ +model RLC + constant Integer N = 10; + Real Y, A[N]; +equation + A[3] = 4; + for i in 1:N loop + A[i] + Y = 7; + end for; +end RLC; diff --git a/test/causalize/tarjan4.mo b/test/causalize/tarjan4.mo new file mode 100644 index 0000000..0bf3f00 --- /dev/null +++ b/test/causalize/tarjan4.mo @@ -0,0 +1,8 @@ +model RLC + constant Integer N = 3; + Real A[N]; +equation + A[1] + A[2] = 4; + A[2] + A[3] = 7; + A[3] + A[1] = 15; +end RLC; diff --git a/test/causalize/tarjan4D.mo b/test/causalize/tarjan4D.mo new file mode 100644 index 0000000..70698ec --- /dev/null +++ b/test/causalize/tarjan4D.mo @@ -0,0 +1,9 @@ +model RLC + constant Integer N = 5; + Real A[N,N,N,N], B[N,N,N,N]; +equation + for i in 1:N, j in 1:N, k in 1:N, q in 1:N loop + A[i,j,k,q] + B[i,j,k,q] = 7; + A[i,j,k,q] - B[i,j,k,q] = 1; + end for; +end RLC; diff --git a/test/causalize/tarjan5.mo b/test/causalize/tarjan5.mo new file mode 100644 index 0000000..4b9ba46 --- /dev/null +++ b/test/causalize/tarjan5.mo @@ -0,0 +1,10 @@ +model RLC + constant Integer N = 10; + Real C, A[N], B[N]; +equation + C + A[3] + B[3] = 9; + for i in 1:N loop + A[i] + B[i] = 7; + A[i] - B[i] = 1; + end for; +end RLC; diff --git a/test/causalize/tarjan6.mo b/test/causalize/tarjan6.mo new file mode 100644 index 0000000..a0c6b2a --- /dev/null +++ b/test/causalize/tarjan6.mo @@ -0,0 +1,9 @@ +model RLC + constant Integer N = 10; + Real A[N], B[N]; +equation + for i in 1:N loop + A[i] + B[i] = 2*i; + A[i] - B[i] = 2; + end for; +end RLC; diff --git a/test/causalize/test.mo b/test/causalize/test.mo new file mode 100644 index 0000000..f64bbbc --- /dev/null +++ b/test/causalize/test.mo @@ -0,0 +1,11 @@ +model RLC + constant Integer N = 3; + Real A[N],B[N]; +equation + B[1] = 1; + B[2] = 2; + B[3] = 3; + for i in 1:N loop + A[i] * A[i] + B[i] = 9; + end for; +end RLC; diff --git a/test/causalize/test2.mo b/test/causalize/test2.mo new file mode 100644 index 0000000..202f4b7 --- /dev/null +++ b/test/causalize/test2.mo @@ -0,0 +1,7 @@ +model RLC + constant Integer N = 3; + Real A[1],B[1]; +equation + B[1] = 3; + A[1] * A[1] + B[1] = 9; +end RLC; diff --git a/test/causalize/test3.mo b/test/causalize/test3.mo new file mode 100644 index 0000000..d81bf61 --- /dev/null +++ b/test/causalize/test3.mo @@ -0,0 +1,13 @@ +model LAZO_NEWTON + constant Integer N = 1; + constant Integer M = 10; + Real A[N],B[N],C[M]; +equation + for i in 1:M loop + C[i] = i; + end for; + for i in 1:N loop + A[i] * A[i] + B[i] * B[i] * B[i] + C[i] = 9; + A[i] * A[i] * A[i] + B[i] * B[i] = 10; + end for; +end LAZO_NEWTON; diff --git a/test/causalize/testDomRan1.mo b/test/causalize/testDomRan1.mo new file mode 100644 index 0000000..b25c7c5 --- /dev/null +++ b/test/causalize/testDomRan1.mo @@ -0,0 +1,14 @@ +model RLC + constant Integer N = 10; + Real A[N], B[N]; +equation + for i in 1:1 loop + A[1] = 5; + end for; + for i in 1:N loop + A[i] * A[i] + B[i] = 12; + end for; + for i in 1:N-1 loop + B[i+1] = 8; + end for; +end RLC; diff --git a/test/causalize/testDomRan2.mo b/test/causalize/testDomRan2.mo new file mode 100644 index 0000000..c7a3624 --- /dev/null +++ b/test/causalize/testDomRan2.mo @@ -0,0 +1,12 @@ +model RLC + constant Integer N = 10; + Real A[N], B[N]; +equation + A[1] = 5; + for i in 1:N loop + A[i] + B[i] = 12; + end for; + for i in 1:N-1 loop + B[i+1] = 8; + end for; +end RLC; diff --git a/test/causalize/testDomRan3.mo b/test/causalize/testDomRan3.mo new file mode 100644 index 0000000..3ec9e19 --- /dev/null +++ b/test/causalize/testDomRan3.mo @@ -0,0 +1,14 @@ +model RLC + constant Integer N = 1000000000; + Real A[N], B[N]; +equation + for i in 1:1 loop + A[1000000000] = 5; + end for; + for i in 1:N loop + A[i] + B[i] = 12; + end for; + for i in 1:N-1 loop + B[i] = 8; + end for; +end RLC; diff --git a/test/causalize/testDomRan4.mo b/test/causalize/testDomRan4.mo new file mode 100644 index 0000000..50a093b --- /dev/null +++ b/test/causalize/testDomRan4.mo @@ -0,0 +1,14 @@ +model RLC + constant Integer N = 1000000000; + Real A[N], B[N]; +equation + for i in 1:1 loop + A[1000000000] = 5; + end for; + for i in 1:N loop + A[i] + B[i] = 12; + end for; + for i in 2:N loop + B[i-1] = 8; + end for; +end RLC; diff --git a/util/ast_visitors/all_expressions.cpp b/util/ast_visitors/all_expressions.cpp new file mode 100644 index 0000000..d58ca26 --- /dev/null +++ b/util/ast_visitors/all_expressions.cpp @@ -0,0 +1,147 @@ +/***************************************************************************** + + 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 + +namespace Modelica { + AllExpressions::AllExpressions(Expression e): exp(e) {}; + AllExpressions::AllExpressions(Expression e, VarSymbolTable vst): exp(e), st(vst) {}; + Lexp AllExpressions::operator()(Integer v) const { return (exp==Expression(v)?Lexp(1,v):Lexp()); } + Lexp AllExpressions::operator()(Boolean v) const { return (exp==Expression(v)?Lexp(1,v):Lexp()); } + Lexp AllExpressions::operator()(String v) const { return (exp==Expression(v)?Lexp(1,v):Lexp()); } + Lexp AllExpressions::operator()(Name v) const { return (exp==Expression(v)?Lexp(1,v):Lexp()); } + Lexp AllExpressions::operator()(Real v) const { return (exp==Expression(v)?Lexp(1,v):Lexp()); } + Lexp AllExpressions::operator()(SubEnd v) const { return (exp==Expression(v)?Lexp(1,v):Lexp()); } + Lexp AllExpressions::operator()(SubAll v) const { return (exp==Expression(v)?Lexp(1,v):Lexp()); } + Lexp AllExpressions::operator()(BinOp v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + Expression l=v.left(), r=v.right(); + Lexp aux = ApplyThis(l); + rta.insert(rta.end(), aux.begin(), aux.end()); + aux = ApplyThis(r); + rta.insert(rta.end(), aux.begin(), aux.end()); + return rta; + } + Lexp AllExpressions::operator()(UnaryOp v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + Expression e=v.exp(); + Lexp aux = ApplyThis(e); + rta.insert(rta.end(), aux.begin(), aux.end()); + return rta; + } + Lexp AllExpressions::operator()(IfExp v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + Expression cond=v.cond(), then=v.then(), elseexp=v.elseexp(); + Lexp aux = ApplyThis(cond); + rta.insert(rta.end(), aux.begin(), aux.end()); + aux = ApplyThis(then); + rta.insert(rta.end(), aux.begin(), aux.end()); + aux = ApplyThis(elseexp); + rta.insert(rta.end(), aux.begin(), aux.end()); + return rta; + } + Lexp AllExpressions::operator()(Range v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + Expression start=v.start(), end=v.end(); + Lexp aux = ApplyThis(start); + rta.insert(rta.end(), aux.begin(), aux.end()); + aux = ApplyThis(end); + rta.insert(rta.end(), aux.begin(), aux.end()); + return rta; + } + Lexp AllExpressions::operator()(Brace v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + ERROR("ContainsExpression: Brace expression not supported"); + //TODO + return rta; + } + Lexp AllExpressions::operator()(Bracket v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + ERROR("ContainsExpression: Bracket expression not supported"); + //TODO + return rta; + } + Lexp AllExpressions::operator()(Call v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + foreach_ (Expression e, v.args()) { + Lexp aux = ApplyThis(e); + rta.insert(rta.end(), aux.begin(), aux.end()); + } + return rta; + } + + Lexp AllExpressions::operator()(FunctionExp v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + //TODO + return rta; + } + Lexp AllExpressions::operator()(ForExp v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + Indexes indexes = v.indices(); + ERROR_UNLESS(indexes.indexes().size() == 1, "Only unidimensional for expression supported"); + Index ind = indexes.indexes().front(); + if (!ind.exp()) + ERROR("Index with no expression"); + Expression exp_ind = ind.exp().get(); + ERROR_UNLESS(is(exp_ind), "Only range supported in for expression"); + EvalExpression ev(st); + Expression start_exp = get(exp_ind).start(), end_exp = get(exp_ind).end(); + int start = Apply(ev,start_exp); + int end = Apply(ev,end_exp); + int i; + for (i=start; i<= end ; i++) { + VarInfo vinfo = VarInfo(TypePrefixes(1,parameter), "Integer", Option(), Modification(ModEq(Expression(i)))); + st.insert(ind.name(), vinfo); + Expression exp_for = v.exp(); + Lexp aux = ApplyThis(exp_for); + rta.insert(rta.end(), aux.begin(), aux.end()); + } + return rta; + } + Lexp AllExpressions::operator()(Named v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + //TODO + return rta; + } + Lexp AllExpressions::operator()(Output v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + foreach_ (OptExp oe, v.args()) + if (oe){ + Lexp aux = ApplyThis(oe.get()); + rta.insert(rta.end(), aux.begin(), aux.end()); + } + return rta; + } + Lexp AllExpressions::operator()(Reference v) const { + Lexp rta = (exp==Expression(v)?Lexp(1,v):Lexp()); + if (is(exp)) { + Reference ref = get(exp); + // Check wheter a[1] is contained in a + //~ if (get<0>(v.ref().front())==get<0>(ref.ref().front())) + rta.push_back(v); + //~ if (get<0>(v.ref().front())==get<0>(ref.ref().front()) && get<1>(v.ref().front()).size()==1 && get<1>(ref.ref().front()).size()==1) + //~ return get<1>(v.ref().front()) == get<1>(ref.ref().front()); + + } + return rta; + } +} diff --git a/util/ast_visitors/all_expressions.h b/util/ast_visitors/all_expressions.h new file mode 100644 index 0000000..fba4724 --- /dev/null +++ b/util/ast_visitors/all_expressions.h @@ -0,0 +1,57 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#ifndef AST_VISITOR_ALL +#define AST_VISITOR_ALL +#include +#include +#include + +namespace Modelica { + typedef std::list Lexp; + using namespace Modelica::AST; + class AllExpressions: public boost::static_visitor { + public: + AllExpressions(Expression); + AllExpressions(Expression, VarSymbolTable); + Lexp operator()(Integer v) const; + Lexp operator()(Boolean v) const; + Lexp operator()(String v) const; + Lexp operator()(Name v) const; + Lexp operator()(Real v) const; + Lexp operator()(SubEnd v) const; + Lexp operator()(SubAll v) const; + Lexp operator()(BinOp) const; + Lexp operator()(UnaryOp) const; + Lexp operator()(Brace) const; + Lexp operator()(Bracket) const; + Lexp operator()(Call) const; + Lexp operator()(FunctionExp) const; + Lexp operator()(ForExp) const; + Lexp operator()(IfExp) const; + Lexp operator()(Named) const; + Lexp operator()(Output) const; + Lexp operator()(Reference) const; + Lexp operator()(Range) const; + private: + Expression exp; + mutable VarSymbolTable st; + }; +} +#endif diff --git a/util/ast_visitors/contains_unknown.cpp b/util/ast_visitors/contains_unknown.cpp new file mode 100644 index 0000000..dea7b3e --- /dev/null +++ b/util/ast_visitors/contains_unknown.cpp @@ -0,0 +1,179 @@ +/***************************************************************************** + + 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 boost; +using namespace Modelica; +using namespace Modelica::AST ; + +ContainsUnknown::ContainsUnknown(std::vector unks, const VarSymbolTable &s): syms(s){ + int i=0; + for (Expression e: unks) { + std::stringstream ss; + ss << e; + definedUnks.insert(make_pair(ss.str(),i++)); + } + +} +void ContainsUnknown::clear() { + usedUnks.clear(); +} + +bool ContainsUnknown::operator()(Modelica::AST::Integer v) const { return false; } + +bool ContainsUnknown::operator()(AddAll v) const { return false; } + +bool ContainsUnknown::operator()(Boolean v) const { return false; } + +bool ContainsUnknown::operator()(String v) const { return false; } + +bool ContainsUnknown::operator()(Name v) const { return false; } + +bool ContainsUnknown::operator()(Real v) const { return false; } + +bool ContainsUnknown::operator()(SubEnd v) const { return false; } + +bool ContainsUnknown::operator()(SubAll v) const { return false; } + +bool ContainsUnknown::operator()(BinOp v) const { + Expression l=v.left(), r=v.right(); + bool rl = ApplyThis(l); + bool rr = ApplyThis(r); + return rr || rl; +} + +bool ContainsUnknown::operator()(UnaryOp v) const { + Expression e=v.exp(); + return ApplyThis(e); +} + +bool ContainsUnknown::operator()(IfExp v) const { + Expression cond=v.cond(), then=v.then(), elseexp=v.elseexp(); + const bool rc = ApplyThis(cond); + const bool rt = ApplyThis(then); + const bool re = ApplyThis(elseexp); + return rc || rt || re; +} + +bool ContainsUnknown::operator()(Range v) const { + Expression start=v.start(), end=v.end(); + bool rs = ApplyThis(start); + bool re = ApplyThis(end); + return rs || re; +} + +bool ContainsUnknown::operator()(Brace v) const { + bool ret = false; + for (Expression exp: v.args()) { + bool b = ApplyThis(exp); + ret |= b; + } + return ret; +} + +bool ContainsUnknown::operator()(Bracket v) const { + bool ret = false; + for (auto &list: v.args()) { + for (Expression exp: list) { + bool b = ApplyThis(exp); + ret |= b; + } + } + return ret; +} // TODO: Warning! Modificado para que compile. + +bool ContainsUnknown::operator()(Call call) const { + if ("der"!=call.name()) + return false; + int usage = IsUsed(call); + if (usage!=-1) { + usedUnks.insert(usage); + return true; + } else { + return false; + } +} + +bool ContainsUnknown::operator()(FunctionExp v) const { + bool ret = false; + for (Expression exp: v.args()) { + bool b = ApplyThis(exp); + ret |= b; + } + return ret; +} + +bool ContainsUnknown::operator()(ForExp v) const { + Expression exp = v.exp(); + bool ret = ApplyThis(exp); + return ret; +} + +bool ContainsUnknown::operator()(Named v) const { + Expression exp = v.exp(); + bool ret = ApplyThis(exp); + return ret; +} + +bool ContainsUnknown::operator()(Output v) const { + bool ret = false; + for (Option exp: v.args()) { + if (exp) { + bool b = ApplyThis(exp.get()); + ret |= b; + } + } + return ret; +} + + +bool ContainsUnknown::operator()(Reference ref) const { + int usage = IsUsed(ref); + if (usage!=-1) { + usedUnks.insert(usage); + return true; + } else { + return false; + } +} + +std::set ContainsUnknown::getUsages() const { + return usedUnks; +} + +int ContainsUnknown::IsUsed(Expression e) const { + std::stringstream ss; + ss << e; + try { + return definedUnks.at(ss.str()); + } catch (const std::out_of_range& oor) { + return -1; + } +} + + + + + diff --git a/util/ast_visitors/contains_unknown.h b/util/ast_visitors/contains_unknown.h new file mode 100644 index 0000000..40b3b4d --- /dev/null +++ b/util/ast_visitors/contains_unknown.h @@ -0,0 +1,65 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#ifndef AST_VISITOR_CONTAINS_UNKNOWN +#define AST_VISITOR_CONTAINS_UNKNOWN + +#include +#include +#include +#include +#include + +using namespace Modelica; +using namespace Modelica::AST; + +class ContainsUnknown: public boost::static_visitor { +public: + ContainsUnknown(std::vector, const VarSymbolTable&); + bool operator()(Modelica::AST::Integer v) const; + bool operator()(AddAll v) const; + bool operator()(Boolean v) const; + bool operator()(String v) const; + bool operator()(Name v) const; + bool operator()(Real v) const; + bool operator()(SubEnd v) const; + bool operator()(SubAll v) const; + bool operator()(BinOp) const; + bool operator()(UnaryOp) const; + bool operator()(Brace) const; + bool operator()(Bracket) const; + bool operator()(Call) const; + bool operator()(FunctionExp) const; + bool operator()(ForExp) const; + bool operator()(IfExp) const; + bool operator()(Named) const; + bool operator()(Output) const; + bool operator()(Reference) const; + bool operator()(Range) const; + + std::set getUsages() const; + void clear(); +private: + int IsUsed(Expression) const; + mutable VarSymbolTable syms; + std::map definedUnks; + mutable std::set usedUnks; +}; + +#endif diff --git a/util/ast_visitors/contains_vector.cpp b/util/ast_visitors/contains_vector.cpp new file mode 100644 index 0000000..b211e7c --- /dev/null +++ b/util/ast_visitors/contains_vector.cpp @@ -0,0 +1,285 @@ +/***************************************************************************** + + 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 + +using namespace Modelica; +using namespace Modelica::AST ; + +namespace Causalize { + ContainsVector::ContainsVector(Expression e, VectorVertexProperty v, const VarSymbolTable &s): + exp(e), + unk2find(v), + syms(s), + foreq(false), + indexes() {}; + + /** + * Builds a ContainsVector class to find occurrences of the Expression 'e' + * using the table of symbols 's' and index list 'indexes' in 'for-equations'. + */ + ContainsVector::ContainsVector(VectorVertexProperty unk, VarSymbolTable &s, IndexList indexes): + exp(unk.unknown()), + unk2find(unk), + syms(s), + foreq(true), + indexes(indexes) { + EvalExpression ev(syms); + foreach_(Index i, indexes) { + if (!i.exp()) + ERROR("No index in for equation"); + ERROR_UNLESS(is(i.exp().get()), "Only range expressions supported"); + Range range = get(i.exp().get()); + forIndexIntervalList.push_back(Interval::closed(Apply(ev,range.start_ref()), Apply(ev,range.end_ref()))); + } + }; + + bool ContainsVector::operator()(Modelica::AST::Integer v) const { return exp==Expression(v); } + + bool ContainsVector::operator()(AddAll v) const { return false; } + + bool ContainsVector::operator()(Boolean v) const { return exp==Expression(v); } + + bool ContainsVector::operator()(String v) const { return exp==Expression(v); } + + bool ContainsVector::operator()(Name v) const { return exp==Expression(v); } + + bool ContainsVector::operator()(Real v) const { return exp==Expression(v); } + + bool ContainsVector::operator()(SubEnd v) const { return exp==Expression(v); } + + bool ContainsVector::operator()(SubAll v) const { return exp==Expression(v); } + + bool ContainsVector::operator()(BinOp v) const { + if (exp==Expression(v)) return true; + Expression l=v.left(), r=v.right(); + bool rl = ApplyThis(l); + bool rr = ApplyThis(r); + return rr || rl; + } + + bool ContainsVector::operator()(UnaryOp v) const { + if (exp==Expression(v)) return true; + Expression e=v.exp(); + return ApplyThis(e); + } + + bool ContainsVector::operator()(IfExp v) const { + if (exp==Expression(v)) return true; + Expression cond=v.cond(), then=v.then(), elseexp=v.elseexp(); + const bool rc = ApplyThis(cond); + const bool rt = ApplyThis(then); + const bool re = ApplyThis(elseexp); + return rc || rt || re; + } + + bool ContainsVector::operator()(Range v) const { + if (exp==Expression(v)) return true; + Expression start=v.start(), end=v.end(); + bool rs = ApplyThis(start); + bool re = ApplyThis(end); + return rs || re; + } + + bool ContainsVector::operator()(Brace v) const { + if (exp==Expression(v)) return true; + return false; + } + + bool ContainsVector::operator()(Bracket v) const { + if (exp==Expression(v)) return true; + return false; + } + + bool ContainsVector::operator()(Call call) const { + if (is(exp)) { //exp is a derivative expression + Call callExpr=get(exp); + if (call.name()=="der" && callExpr.name()=="der") { //call and exp are derivative expressions + ERROR_UNLESS(is(call.args().front()) && is(callExpr.args().front()), "Arguments to call must be a reference"); + Reference callRef=get(call.args().front()); + Reference callExprRef=get(callExpr.args().front()); + if (get<0>(callRef.ref().front())==get<0>(callExprRef.ref().front())) { //The references are the same + BuildPairs(callRef); + return true; + } + //The references are not the same + return false; + } + } else { //exp is not a derivative expression, find the occurrence of exp inside the call arguments + if (exp==Expression(call)) return true; + bool findOccur = false; + foreach_ (Expression e, call.args()) { + findOccur|=(ApplyThis(e)); + } + return findOccur; + } + + return false; + } + + bool ContainsVector::operator()(FunctionExp v) const { + if (exp==Expression(v)) return true; + return false; + } + + bool ContainsVector::operator()(ForExp v) const { + if (exp==Expression(v)) return true; + return false; + } + + bool ContainsVector::operator()(Named v) const { + if (exp==Expression(v)) return true; + return false; + } + + bool ContainsVector::operator()(Output v) const { + if (exp==Expression(v)) return true; + foreach_(OptExp oe, v.args()) + if (oe && ApplyThis(oe.get())) return true; + return false; + } + + + bool ContainsVector::operator()(Reference ref) const { + if (is(exp)) { + if (get<0>(ref.ref().front())==get<0>(get(exp).ref().front())) { //The references are the same + BuildPairs(ref); + return true; + } + } + return false; + } + + void ContainsVector::BuildPairs(Reference unkRef) const { + if (foreq) { //The equation is a for-equation + if (unk2find.unknown.dimension==0) { //the unknown is a scalar + Usage usage; + Offset offset; + labels.insert(IndexPair(MDI(forIndexIntervalList), MDI(0), offset, usage)); + } else { //the unknown is a vector + ERROR_UNLESS(unk2find.unknown.dimension==(int)get<1>(unkRef.ref().front()).size(), "Only complete usage of vectors are allowed"); + VarSymbolTable vst=syms; + std::vector iterator_names; + Usage usage_indexes; + foreach_(Index i, indexes) { + iterator_names.push_back(i.name()); + VarInfo vinfo = VarInfo(TypePrefixes(), "Integer", Option(), Modification()); + vst.insert(i.name(),vinfo); + } + IntervalList unk_indexes; + Expression unkRef_exp = unkRef; + Expression evaluated_expr=Apply(Modelica::PartialEvalExpression(vst),unkRef_exp); + ERROR_UNLESS(is(evaluated_expr), "Evaluated expression is not a reference"); + Reference r = get(evaluated_expr); + ExpList indexes_list = get<1>(r.ref().front()); + unsigned int total_index_uses = 0; + unsigned int index_count = 0; + std::vector offset_vector; + foreach_(Expression val,indexes_list) { + if (is(val)) { + int v = get(val); + unk_indexes.push_back(Interval::closed(v,v)); + usage_indexes.push_back(-1); + offset_vector.push_back(0); + } else if (is(val)) { + Reference ind_ref = get(val); + std::vector::iterator index_name = std::find(iterator_names.begin(), iterator_names.end(), get<0>(ind_ref.ref().front())); + ERROR_UNLESS(index_name!=iterator_names.end(), "Usage of variable in index expression not found"); + Index i = indexes.at(index_name-iterator_names.begin()); + if (!i.exp()) + ERROR("Implicit range not supported in for equations"); + ERROR_UNLESS(is(i.exp().get()), "Only range supported in for equations"); + Range range = get(i.exp().get()); + EvalExpression ev(syms); + int pos = index_name - iterator_names.begin(); + usage_indexes.push_back(pos); + unk_indexes.push_back(Interval::closed(Apply(ev,range.start_ref()), Apply(ev,range.end_ref()))); + total_index_uses++; + offset_vector.push_back(0); + } else if (is(val)) { + BinOp binop = get(Apply(Modelica::PartialEvalExpression(vst), val)); + ERROR_UNLESS(binop.op()==Add || + binop.op()==Sub , "Only addition and substraction are supported in indexes"); + ERROR_UNLESS(is(binop.left()),"Index must be of the form i+/-K where K is a constant"); + ERROR_UNLESS(is(binop.right()),"Index must be of the form i+/-K where K is a constant"); + int offset = get(binop.right()); + if (binop.op()==Sub) // Transform everything to an addition + offset *= -1; + Reference ind_ref = get(binop.left()); + std::vector::iterator index_name = std::find(iterator_names.begin(), iterator_names.end(), get<0>(ind_ref.ref().front())); + ERROR_UNLESS(index_name!=iterator_names.end(), "Usage of variable in index expression not found"); + Index i = indexes.at(index_name-iterator_names.begin()); + if (!i.exp()) + ERROR("Implicit range not supported in for equations"); + ERROR_UNLESS(is(i.exp().get()), "Only range supported in for equations"); + Range range = get(i.exp().get()); + EvalExpression ev(syms); + int pos = index_name - iterator_names.begin(); + offset_vector.push_back(offset); + usage_indexes.push_back(pos); + unk_indexes.push_back(Interval::closed(Apply(ev,range.start_ref())+offset, Apply(ev,range.end_ref())+offset)); + total_index_uses++; + } else { + ERROR("Index expression not supported"); + } + index_count++; + } + ERROR_UNLESS(total_index_uses == 0 || total_index_uses==forIndexIntervalList.size(), "The number of indexes does not match the number of uses"); + MDI mdi_eq(forIndexIntervalList), mdi_unk(unk_indexes); + ERROR_UNLESS( mdi_eq.Size() == mdi_unk.Size() + || mdi_eq.Size() == 1 + || mdi_unk.Size() == 1 + , "Edge of different size"); + labels.insert(IndexPair(mdi_eq, mdi_unk, Offset(offset_vector), usage_indexes)); + } + } else { //The equation is not a for-equation + if (unk2find.unknown.dimension==0) { //the unknown is a scalar + labels.insert(IndexPair(MDI(0), MDI(0), Offset(), Usage())); + } else { //the unknown is a vector + ERROR_UNLESS(unk2find.unknown.dimension==(int)get<1>(unkRef.ref().front()).size() || (int)get<1>(unkRef.ref().front()).size() ==0 , "Only complete usage of vectors are allowed"); + VarSymbolTable vst=syms; + Expression unkRef_exp = unkRef; + Expression evaluated_expr=Apply(Modelica::PartialEvalExpression(vst),unkRef_exp); + IntervalList unk_indexes; + ERROR_UNLESS(is(evaluated_expr), "Evaluated expression is not a reference"); + Reference r = get(evaluated_expr); + ExpList indexes = get<1>(r.ref().front()); + std::vector offset_vector(indexes.size(),0); + Usage usage_indexes(indexes.size(),-1); + foreach_(Expression val, indexes) { + ERROR_UNLESS(is(val), "Expression index could not be evaluated"); //TODO: See this error message + int v = get(val); + unk_indexes.push_back(Interval::closed(v,v)); + } + if (indexes.size()==0) // If no usage, use the whole array + for(int i : unk2find.unknown.dimensionList) + unk_indexes.push_back(Interval::closed(1,i)); + labels.insert(IndexPair(MDI(0), MDI(unk_indexes), Offset(offset_vector), usage_indexes)); + } + } + } + +} diff --git a/util/ast_visitors/contains_vector.h b/util/ast_visitors/contains_vector.h new file mode 100644 index 0000000..f6f7a7f --- /dev/null +++ b/util/ast_visitors/contains_vector.h @@ -0,0 +1,73 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#ifndef AST_VISITOR_CONTAINS_VECTOR +#define AST_VISITOR_CONTAINS_VECTOR +#include +#include +#include +#include +#include +#include + +namespace Causalize { + + using namespace Modelica::AST; + class ContainsVector: public boost::static_visitor { + public: + ContainsVector(Expression, VectorVertexProperty, const VarSymbolTable &); + ContainsVector(VectorVertexProperty, VarSymbolTable &, IndexList); + bool operator()(Modelica::AST::Integer v) const; + bool operator()(AddAll v) const; + bool operator()(Boolean v) const; + bool operator()(String v) const; + bool operator()(Name v) const; + bool operator()(Real v) const; + bool operator()(SubEnd v) const; + bool operator()(SubAll v) const; + bool operator()(BinOp) const; + bool operator()(UnaryOp) const; + bool operator()(Brace) const; + bool operator()(Bracket) const; + bool operator()(Call) const; + bool operator()(FunctionExp) const; + bool operator()(ForExp) const; + bool operator()(IfExp) const; + bool operator()(Named) const; + bool operator()(Output) const; + bool operator()(Reference) const; + bool operator()(Range) const; + IndexPairSet GetOccurrenceIndexes() { return labels; } + private: + void BuildPairs(Reference unkRef) const; + //void BuildPairs(int counters[], Reference unkRef) const; + //void NestedLoopOperation(int counters[], int length[], int level, Reference unkRef) const; + //std::string PrintListOfList(std::list > xss) const; + + Expression exp; + IntervalList forIndexIntervalList; + //std::list > BuildForIndexTuples(std::list > forIndexIntervalList) const; + mutable IndexPairSet labels; + VectorVertexProperty unk2find; + mutable VarSymbolTable syms; + bool foreq; + IndexList indexes; + }; +} +#endif diff --git a/util/ast_visitors/ginac_interface.cpp b/util/ast_visitors/ginac_interface.cpp index a42580f..2744549 100644 --- a/util/ast_visitors/ginac_interface.cpp +++ b/util/ast_visitors/ginac_interface.cpp @@ -25,15 +25,33 @@ #include #include #include +#include #include +#include +#include +#include +#include #include #include #include using namespace GiNaC; +using namespace std; REGISTER_FUNCTION(der, dummy()) REGISTER_FUNCTION(pre, dummy()) +REGISTER_FUNCTION(user_fun1_1, dummy()) +REGISTER_FUNCTION(user_fun1_2, dummy()) +REGISTER_FUNCTION(user_fun1_3, dummy()) + +REGISTER_FUNCTION(user_fun2_1, dummy()) +REGISTER_FUNCTION(user_fun2_2, dummy()) +REGISTER_FUNCTION(user_fun2_3, dummy()) + +REGISTER_FUNCTION(user_fun3_1, dummy()) +REGISTER_FUNCTION(user_fun3_2, dummy()) +REGISTER_FUNCTION(user_fun3_3, dummy()) + static ex var_derivative(const ex &x, const ex &y, unsigned diff_param) { return der(x); } REGISTER_FUNCTION(var, derivative_func(var_derivative)) @@ -72,9 +90,12 @@ void my_print_add_dflt(const add & s, const print_dflt & c, unsigned level) { namespace Modelica { using namespace GiNaC; +std::map ConvertToGiNaC::function3_directory; +int ConvertToGiNaC::user_func1 = 0; +int ConvertToGiNaC::user_func2 = 0; +int ConvertToGiNaC::user_func3 = 0; ConvertToGiNaC::ConvertToGiNaC(VarSymbolTable &var, bool forDerivation) : varEnv(var), _forDerivation(forDerivation) {} -GiNaC::ex ConvertToGiNaC::operator()(AddAll v) const { return ex(0); } GiNaC::ex ConvertToGiNaC::operator()(Integer v) const { return ex(v); } GiNaC::ex ConvertToGiNaC::operator()(Boolean v) const { @@ -165,22 +186,47 @@ GiNaC::ex ConvertToGiNaC::operator()(Call v) const Reference r = get(arg); GiNaC::ex exp = ConvertToGiNaC::operator()(r); std::stringstream ss; - ss << "der(" << exp << ")"; + ss << "der!" << exp; return getSymbol(ss.str()); } if ("exp" == v.name()) { return exp(ApplyThis(v.args()[0])); } if ("sum" == v.name()) { - std::stringstream ss; - ss << v; - return getSymbol(ss.str()); + // Expand sum over unidimensional arrays + ERROR_UNLESS(is(v.args().front()), "Call to sum with no reference"); + Reference ref = get(v.args().front()); + Option opt_vinfo = varEnv[refName(ref)]; + if (!opt_vinfo) ERROR("Variable %s not found", refName(ref)); + ERROR_UNLESS(opt_vinfo.get().indices() && opt_vinfo.get().indices().get().size() == 1, "sum operator over matrix not supported"); + Expression size_exp = opt_vinfo.get().indices().get().front(); + Real size = Apply(EvalExpression(varEnv), size_exp); + GiNaC::ex exp = ConvertToGiNaC::operator()(Reference(refName(ref), 1)); + for (int i = 2; i <= size; i++) { + exp = exp + ConvertToGiNaC::operator()(Reference(refName(ref), i)); + } + return exp; } if ("log" == v.name()) { - return log(ApplyThis(v.args()[0])); + return GiNaC::log(ApplyThis(v.args()[0])); } if ("log10" == v.name()) { - return log(ApplyThis(v.args()[0])) / log(10); + return GiNaC::log(ApplyThis(v.args()[0])) / GiNaC::log(10); + } + if (user_func3 < 3 && v.args().size() == 3) { + Expression arg1 = v.args().front(); + Expression arg2 = v.args().at(1); + Expression arg3 = v.args().at(2); + function3_directory.insert(make_pair(user_func3, v.name())); + // std::cerr << "Converting " << v.name() << " as user_fun3_" << user_func3+1 << "\n"; + switch (user_func3++) { + case 0: + return user_fun3_1(ApplyThis(arg1), ApplyThis(arg2), ApplyThis(arg3)); + case 1: + return user_fun3_2(ApplyThis(arg1), ApplyThis(arg2), ApplyThis(arg3)); + case 2: + return user_fun3_3(ApplyThis(arg1), ApplyThis(arg2), ApplyThis(arg3)); + } } WARNING("ConvertToGiNaC: conversion of function %s implemented. Returning 0.\n", v.name().c_str()); return 0; @@ -217,12 +263,25 @@ GiNaC::ex ConvertToGiNaC::operator()(Reference v) const Option oel = boost::get<1>(r[0]); std::string s = boost::get<0>(r[0]); if (!_forDerivation || isConstant(s, varEnv) || isParameter(s, varEnv) || isDiscrete(s, varEnv)) { - if (oel && oel.get().size() == 1) { + if (oel && oel.get().size()) { std::stringstream ss; - ss << s << "[" << oel.get().front() << "]"; + ss << s; + for (Expression e : oel.get()) { + ERROR_UNLESS(is(e) || is(e) || is(e), "Not suppoted conversion"); + if (!is(e)) + ss << "!" << e; + else { + BinOp bop = get(e); + int offset = get(bop.right()); + if (bop.op() == Sub) offset *= -1; + ss << "!" << bop.left(); + if (offset > 0) + ss << "@" << offset; + else + ss << "#" << -offset; + } + } return getSymbol(ss.str()); - } else if (oel && oel.get().size() > 1) { - ERROR("Multidimensional array not supported"); } return getSymbol(s); } else if (_forDerivation) { @@ -249,18 +308,110 @@ GiNaC::symbol &ConvertToGiNaC::getTime() const return directory.insert(make_pair(s, symbol(s))).first->second; } -Expression ConvertToExp(GiNaC::ex e) +class GiNaCtoModelica : public visitor, // this is required + public add::visitor, // visit add objects + public GiNaC::function::visitor, // visit add objects + public mul::visitor, // visit add objects + public power::visitor, // visit add objects + public GiNaC::numeric::visitor, // visit numeric objects + public symbol::visitor, // visit numeric objects + public basic::visitor // visit basic objects { - bool r; - std::stringstream s(std::ios_base::out), der_s(std::ios_base::out); - // set_print_func(my_print_power_dflt); - s << e; - Expression exp = Parser::ParseExpression(s.str(), r); - if (!r) { - WARNING("ConvertToGiNaC: conversion of output expression. Returning 0"); - return 0; + void visit(const power &x) { result_ = Output(BinOp(ConvertToExp(x.op(0)), Exp, ConvertToExp(x.op(1)))); } + void visit(const add &x) + { + result_ = Output(BinOp(ConvertToExp(x.op(0)), Add, ConvertToExp(x.op(1)))); + for (unsigned int op = 2; op < x.nops(); op++) result_ = Output(BinOp(result_, Add, ConvertToExp(x.op(op)))); } - return exp; + void visit(const GiNaC::function &x) + { + const std::string name = x.get_name(); + if ("sin" == name) { + result_ = Call(name, ConvertToExp(x.op(0))); + return; + } + if ("user_fun3_1" == name) { + // std::cerr << ConvertToGiNaC::function3_directory[0]; + result_ = Call(ConvertToGiNaC::function3_directory[0], {ConvertToExp(x.op(0)), ConvertToExp(x.op(1)), ConvertToExp(x.op(2))}); + return; + } + if ("user_fun3_2" == name) { + std::cerr << ConvertToGiNaC::function3_directory[1]; + result_ = Call(ConvertToGiNaC::function3_directory[1], {ConvertToExp(x.op(0)), ConvertToExp(x.op(1)), ConvertToExp(x.op(2))}); + return; + } + if ("user_fun3_3" == name) { + std::cerr << ConvertToGiNaC::function3_directory[2]; + result_ = Call(ConvertToGiNaC::function3_directory[2], {ConvertToExp(x.op(0)), ConvertToExp(x.op(1)), ConvertToExp(x.op(2))}); + return; + } + ERROR("Function not supported in GiNaC conversion"); + } + void visit(const mul &x) + { + result_ = Output(BinOp(ConvertToExp(x.op(0)), Mult, ConvertToExp(x.op(1)))); + for (unsigned int op = 2; op < x.nops(); op++) result_ = Output(BinOp(result_, Mult, ConvertToExp(x.op(op)))); + } + void visit(const GiNaC::numeric &x) + { + result_ = x.to_double(); + if (x.to_double() < 0) result_ = Output(result_); + } + void visit(const GiNaC::symbol &x) + { + std::string name = x.get_name(); + ; + std::vector sp, bop; + bool is_der = false; + bool found_name = false; + boost::algorithm::split(sp, name, boost::is_any_of("!")); + ExpList el; + for (std::string s : sp) { + if ("der" == s) { + is_der = true; + continue; + } + if (!found_name) { + name = s; + found_name = true; + continue; + } + try { + el.push_back(boost::lexical_cast(s)); + } catch (boost::bad_lexical_cast) { // Unprocess offset + if (boost::algorithm::find_first(s, "@")) { + boost::algorithm::split(bop, s, boost::is_any_of("@")); + el.push_back(BinOp(Reference(bop.front()), Add, boost::lexical_cast(bop.at(1)))); + } else if (boost::algorithm::find_first(s, "#")) { + boost::algorithm::split(bop, s, boost::is_any_of("#")); + el.push_back(BinOp(Reference(bop.front()), Sub, boost::lexical_cast(bop.at(1)))); + } else { + el.push_back(Reference(s)); + } + } + } + if (!is_der) + result_ = Reference(name, el); + else + result_ = Call("der", Reference(name, el)); + } + void visit(const basic &x) + { + std::cerr << x << std::endl; + ERROR("Could not convert GiNaC expression to Modelica"); + } + + Expression result_; + + public: + Expression exp() { return result_; } +}; + +Expression ConvertToExp(GiNaC::ex e) +{ + GiNaCtoModelica v; + e.accept(v); + return v.exp(); } } // namespace Modelica diff --git a/util/ast_visitors/ginac_interface.h b/util/ast_visitors/ginac_interface.h index 9f10580..05de8bc 100644 --- a/util/ast_visitors/ginac_interface.h +++ b/util/ast_visitors/ginac_interface.h @@ -32,6 +32,15 @@ DECLARE_FUNCTION_2P(var) DECLARE_FUNCTION_1P(der) DECLARE_FUNCTION_1P(pre) +DECLARE_FUNCTION_1P(user_fun1_1) +DECLARE_FUNCTION_1P(user_fun1_2) +DECLARE_FUNCTION_1P(user_fun1_3) +DECLARE_FUNCTION_2P(user_fun2_1) +DECLARE_FUNCTION_2P(user_fun2_2) +DECLARE_FUNCTION_2P(user_fun2_3) +DECLARE_FUNCTION_3P(user_fun3_1) +DECLARE_FUNCTION_3P(user_fun3_2) +DECLARE_FUNCTION_3P(user_fun3_3) namespace Modelica { using namespace Modelica::AST; @@ -39,7 +48,6 @@ Expression ConvertToExp(GiNaC::ex e); class ConvertToGiNaC : public boost::static_visitor { public: ConvertToGiNaC(VarSymbolTable& varEnv, bool forDerivation = false); - ::GiNaC::ex operator()(AddAll v) const; ::GiNaC::ex operator()(Integer v) const; ::GiNaC::ex operator()(Boolean v) const; ::GiNaC::ex operator()(String v) const; @@ -63,9 +71,13 @@ class ConvertToGiNaC : public boost::static_visitor { ::GiNaC::symbol& getSymbol(Modelica::AST::Name) const; ::GiNaC::symbol& getSymbol(Modelica::AST::Call); ::GiNaC::symbol& getTime() const; + static std::map function3_directory; private: mutable std::map directory; + static int user_func1; + static int user_func2; + static int user_func3; VarSymbolTable& varEnv; bool _forDerivation; }; diff --git a/util/ast_visitors/replace_index.cpp b/util/ast_visitors/replace_index.cpp new file mode 100644 index 0000000..7b533d5 --- /dev/null +++ b/util/ast_visitors/replace_index.cpp @@ -0,0 +1,202 @@ +/***************************************************************************** + + 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 + +namespace Modelica { + + ReplaceIndex::ReplaceIndex(const VarSymbolTable &v, bool eval):vtable(v),eval_parameters(eval) {counter=0;}; + Expression ReplaceIndex::operator()(Integer v) const { + if (v<0) return Output(v); + return v; + } + Expression ReplaceIndex::operator()(Real v) const { + if (v<0) return Output(v); + return v; + } + Expression ReplaceIndex::operator()(Boolean v) const { + return v; + } + Expression ReplaceIndex::operator()(String v) const { + return v; + } + Expression ReplaceIndex::operator()(Name v) const { + return v; + } + Expression ReplaceIndex::operator()(Expression v) const { + return v; + } + Expression ReplaceIndex::operator()(SubAll v) const { + return v; + } + Expression ReplaceIndex::operator()(SubEnd v) const { + return v; + } + Expression ReplaceIndex::operator()(BinOp v) const { + Expression l=v.left(), r=v.right(); + l=ApplyThis(l);r=ApplyThis(r); + if (eval_parameters && (is(l) || is(l)) && (is(r) || is(r))) { + Expression binop = BinOp(l,v.op(),r); + Expression e = Apply(EvalExpression(vtable),binop); + if (!is(l) && !is(r) && is(e)) { + return Integer(get(e)); + } + return Apply(EvalExpression(vtable),binop); + } + if (is(l) && is(r)) { // Only evaluate integer operations + Expression binop = BinOp(l,v.op(),r); + Expression e = Apply(EvalExpression(vtable),binop); + if (!is(l) && !is(r) && is(e)) { + return Integer(get(e)); + } + return Apply(EvalExpression(vtable),binop); + } + + if (v.op()==Add && isZero(l)) + return r; + if (v.op()==Add && isZero(r)) + return l; + if (v.op()==Sub && isZero(r)) + return l; + if (v.op()==Sub && isZero(l)) + return UnaryOp(r,Minus); + if (v.op()==Mult && isOne(l)) + return r; + if (v.op()==Mult && isOne(r)) + return l; + if (v.op()==Mult && (isZero(r) || isZero(l))) + return 0; + return BinOp(l,v.op(),r); + } + Expression ReplaceIndex::operator()(UnaryOp v) const { + Expression e=v.exp(); + Expression res= ApplyThis(e); + if (v.op()==Not && is(res)) { + if (get(res)==TRUE) + return Boolean(FALSE); + return Boolean(TRUE); + } + if (v.op()==Minus && is(res)) { + return Real(-get(res)); + } + if (v.op()==Minus && is(res)) + return Integer(-get(res)); + if (v.op()==Minus && is(res) && get(res).op()==Minus)// (-(-a)) == a + return get(res).exp(); + return UnaryOp(res, v.op()); + } + Expression ReplaceIndex::operator()(IfExp v) const { + WARNING("Not evaluating If exp"); + return v; + } + Expression ReplaceIndex::operator()(Range v) const { + Expression s=v.start(); + Expression e=v.end(); + if (!v.step()) + return Range(ApplyThis(s),ApplyThis(e)); + Expression st=v.step().get(); + return Range(ApplyThis(s),ApplyThis(st),ApplyThis(e)); + } + Expression ReplaceIndex::operator()(Brace v) const { + WARNING("Not evaluating brace exp"); + return v; + } + Expression ReplaceIndex::operator()(Bracket v) const { + return v; + } + Expression ReplaceIndex::operator()(Call v) const { + ExpList &args = v.args_ref(); + foreach_ (Expression &e, args) + e = ApplyThis(e); + return v; + } + Expression ReplaceIndex::operator()(FunctionExp v) const { + return v; + } + Expression ReplaceIndex::operator()(ForExp v) const { + Expression e = v.exp_; + Indexes i = v.indices_; + //~ table[e] = 1; + //~ if (!table.count(e)){; + //~ table[e] = counter++; + //~ } + return e; + //~ return e++reference_names2[e]; + } + Expression ReplaceIndex::operator()(Named v) const { + return v; + } + Expression ReplaceIndex::operator()(Output v) const { + if (v.args().size()==1 && v.args().front()) { + Expression e=v.args().front().get(); + if (is(e)) return e; + if (is(e)) return e; + if (is(e)) return ApplyThis(e); + return Output(ApplyThis(e)); + } + return v; + } + Expression ReplaceIndex::operator()(Reference v) const { + Ref r=v.ref(); + ERROR_UNLESS(r.size()==1,"ReplaceIndex conversion of dotted references not implemented"); + Option oel = boost::get<1>(r[0]); + Name s=boost::get<0>(r[0]); + if ((isConstant(s,vtable) || isParameter(s,vtable)) && (!oel || (oel && oel.get().size()==0))) { + Option vinfo = vtable[s]; + if (!vinfo) + ERROR("Variable %s not found",s.c_str()); + if (vinfo.get().type()=="Integer" && vinfo.get().modification()) { // evaluate integer parameters + Expression vv=v; + Real ret=Apply(EvalExpression(vtable),vv); + const int i=ret; + if (i==ret) { + if (i<0) return Output(i); + return i; + } + if (ret<0) return Output(Real(ret)); + return Real(ret); + } else if (vinfo.get().type()=="Boolean" && vinfo.get().modification()) { // evaluate boolean parameters + Expression vv=v; + Real ret=Apply(EvalExpression(vtable),vv); + if (ret==1.0) + return Boolean(TRUE); + return Boolean(FALSE); + } else if (eval_parameters && vinfo.get().type()=="Real" && !vinfo.get().indices() && vinfo.get().modification()) { // evaluate scalar parameters + Expression vv=v; + Real ret=Apply(EvalExpression(vtable),vv); + if (ret<0) return Output(Real(ret)); + return Real(ret); + } else { + return v; + } + } + if (oel) { + ExpList nl; + foreach_(Expression e, oel.get()) { + nl.push_back(ApplyThis(e)); + } + return Reference(Ref(1,RefTuple(s,nl))); + } + return v; + } +} diff --git a/util/ast_visitors/replace_index.h b/util/ast_visitors/replace_index.h new file mode 100644 index 0000000..3d76cbc --- /dev/null +++ b/util/ast_visitors/replace_index.h @@ -0,0 +1,66 @@ +/***************************************************************************** + + 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 . + +******************************************************************************/ + +#ifndef AST_VISITOR_REPLACEINDEX +#define AST_VISITOR_REPLACEINDEX +#include +#include +#include +#include +#include +#include + +namespace Modelica { + + using namespace Modelica::AST; + class ReplaceIndex: public boost::static_visitor { + public: + ReplaceIndex(const VarSymbolTable &, bool eval=false); + Expression operator()(Integer v) const; + Expression operator()(Real v) const; + Expression operator()(Boolean v) const; + Expression operator()(String v) const; + Expression operator()(Name v) const; + Expression operator()(Expression v) const; + Expression operator()(SubEnd v) const; + Expression operator()(SubAll v) const; + Expression operator()(BinOp) const; + Expression operator()(UnaryOp) const; + Expression operator()(Brace) const; + Expression operator()(Bracket) const; + Expression operator()(Call) const; + Expression operator()(FunctionExp) const; + Expression operator()(ForExp) const; + Expression operator()(IfExp) const; + Expression operator()(Named) const; + Expression operator()(Output) const; + Expression operator()(Reference) const; + Expression operator()(Range) const; + const VarSymbolTable &vtable; + bool eval_parameters; + int counter; + private: + //~ std::map reference_names; + std::unordered_map> table; + //~ std::map < int , int> reference_names2; + //~ std::unordered_set < Expression > reference_names; + + }; +} +#endif // AST_VISITOR_REPLACEINDEX diff --git a/util/ast_visitors/state_variables_finder.cpp b/util/ast_visitors/state_variables_finder.cpp index 508b9a2..90c4075 100644 --- a/util/ast_visitors/state_variables_finder.cpp +++ b/util/ast_visitors/state_variables_finder.cpp @@ -17,13 +17,6 @@ ******************************************************************************/ -/* - * findstate.cpp - * - * Created on: 28/04/2013 - * Author: Moya - */ - #include #include #include diff --git a/util/ast_visitors/state_variables_finder.h b/util/ast_visitors/state_variables_finder.h index 14f2576..b2368ac 100644 --- a/util/ast_visitors/state_variables_finder.h +++ b/util/ast_visitors/state_variables_finder.h @@ -17,13 +17,6 @@ ******************************************************************************/ -/* - * findstate.h - * - * Created on: 28/04/2013 - * Author: fede - */ - #include #include #include diff --git a/util/solve/solve.cpp b/util/solve/solve.cpp index 8d6c5fa..acbcb74 100644 --- a/util/solve/solve.cpp +++ b/util/solve/solve.cpp @@ -30,7 +30,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -60,7 +62,7 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable using namespace std; static int fsolve = 1; Modelica::ConvertToGiNaC tog(syms); - Modelica::PartialEvalExpression peval(syms, true); + Modelica::PartialEvalExpression peval(syms, false); Modelica::EvalExpression eval(syms); const int size = eqs.size(); @@ -69,9 +71,9 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable Expression l = Apply(peval, eq.left_ref()); Expression r = Apply(peval, eq.right_ref()); if (l == crs.front()) { - if (!Apply(Modelica::ContainsExpression(crs.front()), eq.right_ref())) return eqs; + if (!Apply(Modelica::ContainsExpression(crs.front(), syms), eq.right_ref())) return eqs; } else if (r == crs.front()) { - if (!Apply(Modelica::ContainsExpression(crs.front()), eq.left_ref())) { + if (!Apply(Modelica::ContainsExpression(crs.front(), syms), eq.left_ref())) { return EquationList(1, Equality(r, l)); } } @@ -79,7 +81,7 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable GiNaC::lst eqns, vars; foreach_(Expression exp, crs) { - if (debugIsEnabled('s')) std::cerr << "Solving variables " << exp; + if (debugIsEnabled('s')) std::cerr << "Solving variables " << exp << ": GiNaC " << Apply(tog, exp) << "\n"; vars.append(Apply(tog, exp)); } bool for_eq = false; @@ -102,6 +104,8 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable Equality eq = get(e); Expression l = Apply(peval, eq.left_ref()); Expression r = Apply(peval, eq.right_ref()); + /*Expression l=eq.left_ref(); + Expression r=eq.right_ref();*/ GiNaC::ex left = Apply(tog, l); GiNaC::ex right = Apply(tog, r); if (debugIsEnabled('s')) std::cerr << "GiNaC equation " << left << "=" << right << "\n"; @@ -111,9 +115,9 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable EquationList ret; try { - // if (size>1) - // throw std::logic_error("Blahh"); - if (debugIsEnabled('s')) std::cerr << "GiNaC equations " << eqns << "\n"; + /*if (size>1) + throw std::logic_error("Blahh");*/ + if (debugIsEnabled('s')) std::cerr << "GiNaC equations " << eqns << " variables " << vars << "\n"; GiNaC::ex solved = lsolve(eqns, vars, GiNaC::solve_algo::gauss); if (solved.nops() == 0) { std::cerr << "EquationSolver: cannot solve equation" << eqns << std::endl; @@ -122,35 +126,26 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable } for (unsigned int i = 0; i < solved.nops(); i++) { std::stringstream s(ios_base::out); - std::stringstream rhs(ios_base::out); set_print_func(my_print_power_dflt); if (debugIsEnabled('s')) std::cerr << "GiNaC result " << solved.op(i) << "\n"; - s << index_dimensions; - s << solved.op(i).op(0); - Expression lhs; - if (s.str().find("__der_") == 0) { - std::string ss = s.str().erase(0, 6); - lhs = Call("der", Reference(Ref(1, RefTuple(ss, ExpList(0))))); - } else { - lhs = Reference(Ref(1, RefTuple(s.str(), ExpList(0)))); - } - rhs << solved.op(i).op(1); - bool r; - Expression rhs_exp = Modelica::Parser::ParseExpression(rhs.str(), r); - if (!r) ERROR("Could not solve equation\n"); + Expression lhs = Modelica::ConvertToExp(solved.op(i).op(0)); + Expression rhs = Modelica::ConvertToExp(solved.op(i).op(1)); + if (debugIsEnabled('s')) std::cerr << "Modelica result " << lhs << "=" << rhs << "\n"; if (for_eq) { ForEq feq = get(eqs.front()); - feq.elements_ref().front() = Equality(lhs, rhs_exp); + feq.elements_ref().front() = Equality(lhs, rhs); ret.push_back(feq); } else { - ret.push_back(Equality(lhs, rhs_exp)); + ret.push_back(Equality(lhs, rhs)); } } } catch (std::logic_error &) { - ERROR_UNLESS(!for_eq, "Non linear solving of for loops not suported yet"); - OptExpList ol; - std::set args; - foreach_(Expression exp, crs) ol.push_back(exp); + //~ ERROR_UNLESS(!for_eq, "Non linear solving of for loops not suported yet"); + OptExpList ol, crs_copy; + std::vector args; + foreach_(Expression exp, crs) // TODO (tener cuidado en el crs) + ol.push_back(exp), + crs_copy.push_back(exp); std::stringstream fun_name; fun_name << "fsolve" << fsolve++; EquationList loop; @@ -159,47 +154,159 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable if (val.second.builtin()) continue; if (Modelica::isParameter(val.first, syms) || Modelica::isConstant(val.first, syms)) continue; if (crs.end() != std::find(crs.begin(), crs.end(), Expression(Reference(val.first)))) continue; - Modelica::ContainsExpression con(Reference(val.first)); - foreach_(Equation & e, eqs) - { - ERROR_UNLESS(is(e), "Algebraic loop including non-equality equations not supported"); - Equality eq = get(e); - if (Apply(con, eq.left_ref()) || Apply(con, eq.right_ref())) { - args.insert(val.first); + VarInfo vinfo = val.second; + //~ if (vinfo.indices() && vinfo.indices().get().size() > 1 ) { + //~ ERROR("Multidimensional arrays not supported yet"); + //~ } + if (vinfo.indices()) { + //~ Apply(eval,vinfo.indices().get().front()); + + //~ ExpList expi = vinfo.indices().get(); + //~ for (auto exp1 : expi) + //~ Apply(eval, exp1); + + Reference var(val.first, vinfo.indices().get().front()); + Modelica::AllExpressions all(var); // Este es el visitor que hay que modificar para que me devuelva todas las expresiones. + foreach_(Equation & e, eqs) + { + Equality eq; + if (is(e)) { + ForEq feq = get(e); + ERROR_UNLESS(is(feq.elements().front()), "Algebraic loop including non-equality equations not supported"); + eq = get(feq.elements().front()); + } else { + ERROR_UNLESS(is(e), "Algebraic loop including non-equality equations not supported"); + eq = get(e); + } + Expression pev = Apply(peval, eq.left_ref()); + auto rta = Apply(all, pev); + pev = Apply(peval, eq.right_ref()); + auto aux = Apply(all, pev); + rta.insert(rta.end(), aux.begin(), aux.end()); + + for (Expression exp : rta) { + if (crs_copy.end() == std::find(crs_copy.begin(), crs_copy.end(), Expression(exp))) { + crs_copy.push_back(Expression(exp)); + if (is(exp)) { + Reference ref = get(exp); + args.push_back(ref); + } + } + } + } + } else { + Modelica::AllExpressions all(Reference(val.first)); + foreach_(Equation & e, eqs) + { + Equality eq; + if (is(e)) { + ForEq feq = get(e); + ERROR_UNLESS(is(feq.elements().front()), "Algebraic loop including non-equality equations not supported"); + eq = get(feq.elements().front()); + } else { + ERROR_UNLESS(is(e), "Algebraic loop including non-equality equations not supported"); + eq = get(e); + } + Expression pev = Apply(peval, eq.left_ref()); + auto rta = Apply(all, pev); + pev = Apply(peval, eq.right_ref()); + auto aux = Apply(all, pev); + rta.insert(rta.end(), aux.begin(), aux.end()); + for (Expression exp : rta) { + if (crs_copy.end() == std::find(crs_copy.begin(), crs_copy.end(), Expression(exp))) { + crs_copy.push_back(Expression(exp)); + if (is(exp)) { + Reference ref = get(exp); + args.push_back(ref); + } + } + } } } } + int i; + Class c; + c.name_ref() = fun_name.str(); + Composition com; + External ext; + std::vector c_args; + std::vector c_crs; + + i = 0; + foreach_(Reference n, args) + { + std::stringstream arg_name; + arg_name << "u_" << i; + com.elements_ref().push_back(Component(TypePrefixes(1, input), "Real", Option(), DeclList(1, Declaration(arg_name.str())))); + ext.args_ref().push_back(Expression(Reference(arg_name.str()))); + c_args.push_back(Reference(arg_name.str())); + i++; + } + i = 0; + foreach_(Expression e, crs) + { + std::stringstream arg_name; + arg_name << "y_" << i; + com.elements_ref().push_back(Component(TypePrefixes(1, output), "Real", Option(), DeclList(1, Declaration(arg_name.str())))); + if (crs.size() > 1) { + ext.args_ref().push_back(Expression(Reference(arg_name.str()))); + } + c_crs.push_back(Expression(Reference(arg_name.str()))); + i++; + } std::ostringstream code; + setCFlag(code, 1); code << "int " << fun_name.str() << "_eval(const gsl_vector * __x, void * __p, gsl_vector * __f) {\n"; code << " double *args=(double*)__p;\n"; - int i = 0; - foreach_(Expression e, crs) { code << " const double " << e << " = gsl_vector_get(__x," << i++ << ");\n"; } i = 0; - foreach_(Name n, args) { code << " const double " << n << " = args[" << i++ << "];\n"; } + foreach_(Expression e, c_crs) { code << " const double " << e << " = gsl_vector_get(__x," << i++ << ");\n"; } + i = 0; + foreach_(Reference n, c_args) { code << " const double " << n << " = args[" << i++ << "];\n"; } i = 0; foreach_(Equation & e, eqs) { - ERROR_UNLESS(is(e), "Algebraic loop including non-equality equations not supported"); - Equality eq = get(e); - // loop.push_back(Equality(Apply(peval,eq.left_ref()), Apply(peval,eq.right_ref()))); - setCFlag(code, 1); - code << " gsl_vector_set (__f," << i++ << ", (" << Apply(peval, eq.left_ref()) << ") - (" << Apply(peval, eq.right_ref()) << "));\n"; + Equality eq; + if (is(e)) { + ForEq feq = get(e); + ERROR_UNLESS(is(feq.elements().front()), "Algebraic loop including non-equality equations not supported"); + eq = get(feq.elements().front()); + } else { + ERROR_UNLESS(is(e), "Algebraic loop including non-equality equations not supported"); + eq = get(e); + // loop.push_back(Equality(Apply(peval,eq.left_ref()), Apply(peval,eq.right_ref()))); + } + Expression l = Apply(peval, eq.left_ref()); + Expression r = Apply(peval, eq.right_ref()); + int j = 0; + for (Expression e : crs) { + Modelica::ReplaceExpression repl(e, c_crs[j++]); + l = Apply(repl, l); + r = Apply(repl, r); + } + j = 0; + for (Reference ref : args) { + Modelica::ReplaceExpression repl(Expression(ref), Expression(c_args[j++])); + l = Apply(repl, l); + r = Apply(repl, r); + } + + code << " gsl_vector_set (__f," << i++ << ", (" << l << ") - (" << r << "));\n"; } code << " return GSL_SUCCESS;\n"; code << "}\n"; - if (crs.size() > 1) + if (c_crs.size() > 1) code << "void " << fun_name.str() << "("; else code << "double " << fun_name.str() << "("; i = 0; - foreach_(Name n, args) { code << (++i > 1 ? "," : "") << "double " << n; } + foreach_(Reference n, c_args) { code << (++i > 1 ? "," : "") << "double " << n; } i = 0; - if (crs.size() > 1) { - if (args.size()) code << ","; - foreach_(Expression e, crs) + if (c_crs.size() > 1) { + if (c_args.size()) code << ","; + foreach_(Expression e, c_crs) { code << "double *" << e; - if (++i < (int)crs.size()) code << ","; + if (++i < (int)c_crs.size()) code << ","; } } code << ") { \n"; @@ -247,7 +354,7 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable code << " __F.f = " << fun_name.str() << "_eval;\n"; code << " double __args[" << args.size() << "];\n"; i = 0; - foreach_(Name n, args) { code << " __args[" << i++ << "] = " << n << ";\n"; } + foreach_(Reference n, c_args) { code << " __args[" << i++ << "] = " << n << ";\n"; } code << " __F.params = __args;\n"; code << " gsl_vector *__f = gsl_vector_alloc(" << eqs.size() << ");\n"; code << " // Try if we are already in the solution from the start (useful for discrete dependendt loops) \n"; @@ -255,11 +362,11 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable code << " if (gsl_multiroot_test_residual(__f, 1e-7)==GSL_SUCCESS) {\n"; code << " gsl_vector_free(__f);\n"; code << " gsl_multiroot_fsolver_free (__s);\n"; - if (crs.size() == 1) { + if (c_crs.size() == 1) { code << " return gsl_vector_get (__x, 0 );\n"; } else { i = 0; - foreach_(Expression e, crs) + foreach_(Expression e, c_crs) { code << " " << e << "[0] = " << "gsl_vector_get(__x," << i << ");\n"; @@ -274,12 +381,12 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable code << " __status = gsl_multiroot_fsolver_iterate (__s);\n"; code << " if (__status) /* check if solver is stuck */\n"; code << " break;\n"; - code << " __status = gsl_multiroot_test_residual (__s->f, 1e-7);\n"; + code << " __status = gsl_multiroot_test_residual (__s->f, 1e-7);\n"; code << " } while (__status == GSL_CONTINUE && __iter < 100);\n"; code << " if (__iter == 100) printf(\"Warning: GSL could not solve an algebraic loop after %d iterations\\n\",(int) __iter); \n"; i = 0; - if (crs.size() > 1) { - foreach_(Expression e, crs) + if (c_crs.size() > 1) { + foreach_(Expression e, c_crs) { code << " " << e << "[0] = " << "gsl_vector_get(__s->x," << i << ");\n"; @@ -288,7 +395,7 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable } code << " gsl_multiroot_fsolver_free (__s);\n"; } - if (crs.size() == 1) { + if (c_crs.size() == 1) { code << " " << "double ret = " << "gsl_vector_get(__s->x,0);\n"; @@ -299,34 +406,20 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable code << "}\n"; c_code.push_back(code.str()); - ExpList exp_args; - i = 0; - foreach_(Name n, args) { exp_args.push_back(Reference(n)); } - if (crs.size() > 1) - ret.push_back(Equality(Output(ol), Call(fun_name.str(), exp_args))); - else - ret.push_back(Equality(crs.front(), Call(fun_name.str(), exp_args))); - Class c; - c.name_ref() = fun_name.str(); - Composition com; - External ext; - i = 0; - foreach_(Name n, args) - { - std::stringstream arg_name; - arg_name << "u_" << i; - com.elements_ref().push_back(Component(TypePrefixes(1, input), "Real", Option(), DeclList(1, Declaration(arg_name.str())))); - ext.args_ref().push_back(Expression(Reference(arg_name.str()))); - i++; - } + ExpList exp_args(args.begin(), args.end()); i = 0; - foreach_(Expression e, crs) - { - std::stringstream arg_name; - arg_name << "y_" << i; - com.elements_ref().push_back(Component(TypePrefixes(1, output), "Real", Option(), DeclList(1, Declaration(arg_name.str())))); - if (crs.size() > 1) ext.args_ref().push_back(Expression(Reference(arg_name.str()))); - i++; + if (for_eq) { + ForEq feq = get(eqs.front()); + if (crs.size() > 1) + feq.elements_ref().front() = (Equality(Output(ol), Call(fun_name.str(), exp_args))); + else + feq.elements_ref().front() = (Equality(crs.front(), Call(fun_name.str(), exp_args))); + ret.push_back(feq); + } else { + if (crs.size() > 1) + ret.push_back(Equality(Output(ol), Call(fun_name.str(), exp_args))); + else + ret.push_back(Equality(crs.front(), Call(fun_name.str(), exp_args))); } if (crs.size() == 1) ext.comp_ref_ref() = Expression(Reference("y_0")); c.prefixes_ref() = ClassPrefixes(1, Modelica::function); @@ -342,7 +435,6 @@ EquationList EquationSolver::Solve(EquationList eqs, ExpList crs, VarSymbolTable Argument(ElMod("Include", ModEq(String("#include \\\"" + path + "\\\"")))))); com.ext_annot_ref() = ext_anot; c.composition_ref() = com; - funs.push_back(c); } return ret;