From c9c36c037aa6d6c67f8fbb2236b03729a22e5878 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Tue, 13 Jul 2021 14:35:10 +0200
Subject: [PATCH] =?UTF-8?q?New=20preprocessor=20option=20=E2=80=9Cnocommut?=
 =?UTF-8?q?ativity=E2=80=9D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This option tells the preprocessor not to use the commutativity of addition and
multiplication when looking for common subexpressions.

As a consequence, when using this option, equations in various outputs (LaTeX,
JSON…) will appear as the user entered them.

There is however a potential performance cost to using this option, yet to be
determined.

Ref. dynare#1788
---
 src/DataTree.cc   | 6 ++++--
 src/DataTree.hh   | 9 +++++++++
 src/DynareMain.cc | 4 +++-
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/src/DataTree.cc b/src/DataTree.cc
index a74ea03c..afa52880 100644
--- a/src/DataTree.cc
+++ b/src/DataTree.cc
@@ -27,6 +27,8 @@
 
 #include "DataTree.hh"
 
+bool DataTree::no_commutativity = false;
+
 void
 DataTree::initConstants()
 {
@@ -205,7 +207,7 @@ DataTree::AddPlus(expr_t iArg1, expr_t iArg2)
 
   // To treat commutativity of "+"
   // Nodes iArg1 and iArg2 are sorted by index
-  if (iArg1->idx > iArg2->idx)
+  if (iArg1->idx > iArg2->idx && !no_commutativity)
     swap(iArg1, iArg2);
   return AddBinaryOp(iArg1, BinaryOpcode::plus, iArg2);
 }
@@ -284,7 +286,7 @@ DataTree::AddTimes(expr_t iArg1, expr_t iArg2)
 
   // To treat commutativity of "*"
   // Nodes iArg1 and iArg2 are sorted by index
-  if (iArg1->idx > iArg2->idx)
+  if (iArg1->idx > iArg2->idx && !no_commutativity)
     swap(iArg1, iArg2);
   return AddBinaryOp(iArg1, BinaryOpcode::times, iArg2);
 }
diff --git a/src/DataTree.hh b/src/DataTree.hh
index 39d7ff31..11bd2278 100644
--- a/src/DataTree.hh
+++ b/src/DataTree.hh
@@ -89,6 +89,9 @@ private:
   using second_deriv_external_function_node_map_t = map<tuple<vector<expr_t>, int, int, int>, SecondDerivExternalFunctionNode *>;
   second_deriv_external_function_node_map_t second_deriv_external_function_node_map;
 
+  // Flag to disable simplifications related to commutativity of addition and multiplication
+  static bool no_commutativity;
+
 protected:
   //! Stores local variables value (maps symbol ID to corresponding node)
   map<int, expr_t> local_variables_table;
@@ -340,6 +343,12 @@ public:
 
     return it->second;
   }
+
+  static void
+  setNoCommutativity()
+  {
+    no_commutativity = true;
+  }
 };
 
 inline expr_t
diff --git a/src/DynareMain.cc b/src/DynareMain.cc
index 7ab8d785..723d948a 100644
--- a/src/DynareMain.cc
+++ b/src/DynareMain.cc
@@ -53,7 +53,7 @@ usage()
        << " [-D<variable>[=<value>]] [-I/path] [nostrict] [stochastic] [fast] [minimal_workspace] [compute_xrefs] [output=second|third] [language=matlab|julia]"
        << " [params_derivs_order=0|1|2] [transform_unary_ops] [exclude_eqs=<equation_tag_list_or_file>] [include_eqs=<equation_tag_list_or_file>]"
        << " [json=parse|check|transform|compute] [jsonstdout] [onlyjson] [jsonderivsimple] [nopathchange] [nopreprocessoroutput]"
-       << " [mexext=<extension>] [matlabroot=<path>] [onlymodel] [notime] [use_dll]"
+       << " [mexext=<extension>] [matlabroot=<path>] [onlymodel] [notime] [use_dll] [nocommutativity]"
        << endl;
   exit(EXIT_FAILURE);
 }
@@ -415,6 +415,8 @@ main(int argc, char **argv)
         gui = true;
       else if (s == "use_dll")
         use_dll = true;
+      else if (s == "nocommutativity")
+        DataTree::setNoCommutativity();
       else
         {
           cerr << "Unknown option: " << s << endl;
-- 
GitLab