2008-02-03 11:28:36 +01:00
|
|
|
|
/*
|
2022-01-06 14:54:57 +01:00
|
|
|
|
* Copyright © 2003-2022 Dynare Team
|
2008-02-03 11:28:36 +01:00
|
|
|
|
*
|
|
|
|
|
* This file is part of Dynare.
|
|
|
|
|
*
|
|
|
|
|
* Dynare 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.
|
|
|
|
|
*
|
|
|
|
|
* Dynare 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
|
2021-06-09 16:52:20 +02:00
|
|
|
|
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
|
2008-02-03 11:28:36 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifndef _MODELTREE_HH
|
|
|
|
|
#define _MODELTREE_HH
|
|
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
2009-09-30 17:10:31 +02:00
|
|
|
|
#include <deque>
|
2008-02-03 11:28:36 +01:00
|
|
|
|
#include <map>
|
|
|
|
|
#include <ostream>
|
2018-10-11 11:21:58 +02:00
|
|
|
|
#include <array>
|
2019-04-04 17:01:37 +02:00
|
|
|
|
#include <filesystem>
|
2022-05-05 18:39:27 +02:00
|
|
|
|
#include <optional>
|
2022-07-11 17:33:09 +02:00
|
|
|
|
#include <cassert>
|
2018-10-26 11:44:26 +02:00
|
|
|
|
|
2008-02-03 11:28:36 +01:00
|
|
|
|
#include "DataTree.hh"
|
2020-02-20 15:29:10 +01:00
|
|
|
|
#include "EquationTags.hh"
|
2016-05-12 12:02:34 +02:00
|
|
|
|
#include "ExtendedPreprocessorTypes.hh"
|
2022-06-23 14:28:13 +02:00
|
|
|
|
#include "Bytecode.hh"
|
2008-02-03 11:28:36 +01:00
|
|
|
|
|
2022-01-06 14:54:57 +01:00
|
|
|
|
using namespace std;
|
|
|
|
|
|
2018-11-15 16:39:53 +01:00
|
|
|
|
// Helper to convert a vector into a tuple
|
2019-12-20 16:59:30 +01:00
|
|
|
|
template<typename T, size_t... Indices>
|
|
|
|
|
auto
|
|
|
|
|
vectorToTupleHelper(const vector<T> &v, index_sequence<Indices...>)
|
|
|
|
|
{
|
|
|
|
|
return tuple(v[Indices] ...);
|
2018-11-15 16:39:53 +01:00
|
|
|
|
}
|
2019-12-20 16:59:30 +01:00
|
|
|
|
template<size_t N, typename T>
|
|
|
|
|
auto
|
|
|
|
|
vectorToTuple(const vector<T> &v)
|
|
|
|
|
{
|
2018-11-15 16:39:53 +01:00
|
|
|
|
assert(v.size() >= N);
|
|
|
|
|
return vectorToTupleHelper(v, make_index_sequence<N>());
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-16 19:18:45 +02:00
|
|
|
|
//! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation
|
2020-05-07 15:20:11 +02:00
|
|
|
|
using equation_type_and_normalized_equation_t = vector<pair<EquationType, BinaryOpNode *>>;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
|
|
|
|
|
//! Vector describing variables: max_lag in the block, max_lead in the block
|
2020-03-19 17:46:10 +01:00
|
|
|
|
using lag_lead_vector_t = vector<pair<int, int>>;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
|
2009-04-14 16:39:53 +02:00
|
|
|
|
//! Shared code for static and dynamic models
|
2008-02-03 11:28:36 +01:00
|
|
|
|
class ModelTree : public DataTree
|
|
|
|
|
{
|
2009-12-16 14:21:31 +01:00
|
|
|
|
friend class DynamicModel;
|
|
|
|
|
friend class StaticModel;
|
2019-12-02 19:21:14 +01:00
|
|
|
|
public:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
// Set via the `compiler` command
|
|
|
|
|
string user_set_add_flags, user_set_subst_flags, user_set_add_libs, user_set_subst_libs, user_set_compiler;
|
2009-04-14 16:39:53 +02:00
|
|
|
|
protected:
|
2019-10-29 12:56:53 +01:00
|
|
|
|
/*
|
|
|
|
|
* ************** BEGIN **************
|
|
|
|
|
* The following structures keep track of the model equations and must all be updated
|
|
|
|
|
* when adding or removing an equation. Hence, if a new parallel structure is added
|
|
|
|
|
* in the future, it must be maintained whereever these structures are updated
|
2020-01-06 18:26:35 +01:00
|
|
|
|
* See in particular methods clearEquations(), replaceMyEquations() and
|
|
|
|
|
* computeRamseyPolicyFOCs() of DynamicModel class.
|
2019-10-29 12:56:53 +01:00
|
|
|
|
* NB: This message added with the introduction of the `exclude_eqs` option, hence
|
|
|
|
|
* that's a place to update future structures.
|
|
|
|
|
*/
|
2009-09-30 17:10:31 +02:00
|
|
|
|
//! Stores declared and generated auxiliary equations
|
2008-02-03 11:28:36 +01:00
|
|
|
|
vector<BinaryOpNode *> equations;
|
2022-05-05 18:39:27 +02:00
|
|
|
|
/* Stores line numbers of declared equations; undefined in some cases (e.g.
|
|
|
|
|
auxiliary equations) */
|
|
|
|
|
vector<optional<int>> equations_lineno;
|
2019-10-29 12:56:53 +01:00
|
|
|
|
//! Stores equation tags
|
2020-02-20 15:29:10 +01:00
|
|
|
|
EquationTags equation_tags;
|
2019-10-29 12:56:53 +01:00
|
|
|
|
/*
|
|
|
|
|
* ************** END **************
|
|
|
|
|
*/
|
|
|
|
|
|
2009-09-30 17:10:31 +02:00
|
|
|
|
//! Only stores generated auxiliary equations, in an order meaningful for evaluation
|
2018-07-27 14:19:59 +02:00
|
|
|
|
/*! These equations only contain the definition of auxiliary variables, and
|
|
|
|
|
may diverge from those in the main model (equations), if other model
|
|
|
|
|
transformations applied subsequently. This is not a problem, since
|
|
|
|
|
aux_equations is only used for regenerating the values of auxiliaries
|
|
|
|
|
given the others.
|
|
|
|
|
|
|
|
|
|
For example, such a divergence appears when there is an expectation
|
|
|
|
|
operator in a ramsey model, see
|
|
|
|
|
tests/optimal_policy/nk_ramsey_expectation.mod */
|
2019-12-03 14:19:32 +01:00
|
|
|
|
vector<BinaryOpNode *> aux_equations;
|
2020-01-20 17:22:32 +01:00
|
|
|
|
|
|
|
|
|
//! Maximum order at which (endogenous) derivatives have been computed
|
|
|
|
|
int computed_derivs_order{0};
|
2009-09-30 17:10:31 +02:00
|
|
|
|
|
2018-11-15 16:39:53 +01:00
|
|
|
|
//! Stores derivatives
|
|
|
|
|
/*! Index 0 is not used, index 1 contains first derivatives, ...
|
|
|
|
|
For each derivation order, stores a map whose key is a vector of integer: the
|
|
|
|
|
first integer is the equation index, the remaining ones are the derivation
|
2018-11-22 14:32:40 +01:00
|
|
|
|
IDs of variables (in non-decreasing order, to avoid storing symmetric
|
2022-06-13 16:24:33 +02:00
|
|
|
|
elements several times). Only non-zero derivatives are stored. */
|
2018-11-15 16:39:53 +01:00
|
|
|
|
vector<map<vector<int>, expr_t>> derivatives;
|
2012-11-29 18:07:48 +01:00
|
|
|
|
|
2018-11-15 16:39:53 +01:00
|
|
|
|
//! Number of non-zero derivatives
|
|
|
|
|
/*! Index 0 is not used, index 1 contains number of non-zero first
|
|
|
|
|
derivatives, ... */
|
|
|
|
|
vector<int> NNZDerivatives;
|
|
|
|
|
|
|
|
|
|
//! Derivatives with respect to parameters
|
|
|
|
|
/*! The key of the outer map is a pair (derivation order w.r.t. endogenous,
|
|
|
|
|
derivation order w.r.t. parameters). For e.g., { 1, 2 } corresponds to the jacobian
|
|
|
|
|
differentiated twice w.r.t. to parameters.
|
|
|
|
|
In inner maps, the vector of integers consists of: the equation index, then
|
2018-11-22 15:41:11 +01:00
|
|
|
|
the derivation IDs of endogenous (in non-decreasing order),
|
|
|
|
|
then the IDs of parameters (in non-decreasing order)*/
|
2018-11-15 16:39:53 +01:00
|
|
|
|
map<pair<int,int>, map<vector<int>, expr_t>> params_derivatives;
|
2012-11-29 18:07:48 +01:00
|
|
|
|
|
2018-11-16 16:53:07 +01:00
|
|
|
|
//! Used model local variables, that will be treated as temporary terms
|
|
|
|
|
/*! See the comments in ModelTree::computeTemporaryTerms() */
|
2020-06-05 17:11:29 +02:00
|
|
|
|
map<VariableNode *, expr_t, ExprNodeLess> temporary_terms_mlv;
|
2018-11-15 16:39:53 +01:00
|
|
|
|
|
|
|
|
|
//! Temporary terms for residuals and derivatives
|
|
|
|
|
/*! Index 0 is temp. terms of residuals, index 1 for first derivatives, ... */
|
|
|
|
|
vector<temporary_terms_t> temporary_terms_derivatives;
|
2012-11-29 18:07:48 +01:00
|
|
|
|
|
2018-11-30 12:22:13 +01:00
|
|
|
|
//! Stores, for each temporary term, its index in the MATLAB/Julia vector
|
2018-03-27 17:14:30 +02:00
|
|
|
|
temporary_terms_idxs_t temporary_terms_idxs;
|
|
|
|
|
|
2018-11-15 16:39:53 +01:00
|
|
|
|
//! Temporary terms for parameter derivatives, under a disaggregated form
|
|
|
|
|
/*! The pair of integers is to be interpreted as in param_derivatives */
|
2019-12-20 16:59:30 +01:00
|
|
|
|
map<pair<int, int>, temporary_terms_t> params_derivs_temporary_terms;
|
2012-11-29 18:07:48 +01:00
|
|
|
|
|
2018-11-30 12:22:13 +01:00
|
|
|
|
//! Stores, for each temporary term in param. derivs, its index in the MATLAB/Julia vector
|
2018-05-28 15:23:15 +02:00
|
|
|
|
temporary_terms_idxs_t params_derivs_temporary_terms_idxs;
|
|
|
|
|
|
2010-10-15 19:05:16 +02:00
|
|
|
|
//! Trend variables and their growth factors
|
2013-03-26 16:46:18 +01:00
|
|
|
|
map<int, expr_t> trend_symbols_map;
|
|
|
|
|
|
|
|
|
|
//! for all trends; the boolean is true if this is a log-trend, false otherwise
|
2018-06-04 14:31:26 +02:00
|
|
|
|
using nonstationary_symbols_map_t = map<int, pair<bool, expr_t>>;
|
2013-03-26 16:46:18 +01:00
|
|
|
|
|
2010-10-15 19:05:16 +02:00
|
|
|
|
//! Nonstationary variables and their deflators
|
2013-03-26 16:46:18 +01:00
|
|
|
|
nonstationary_symbols_map_t nonstationary_symbols_map;
|
2008-02-03 11:28:36 +01:00
|
|
|
|
|
2020-04-17 14:55:55 +02:00
|
|
|
|
/* Maps indices of equations in the block-decomposition order into original
|
|
|
|
|
equation IDs */
|
|
|
|
|
vector<int> eq_idx_block2orig;
|
|
|
|
|
/* Maps indices of (endogenous) variables in the block-decomposition order into original
|
|
|
|
|
type-specific endogenous IDs */
|
|
|
|
|
vector<int> endo_idx_block2orig;
|
|
|
|
|
/* Maps original variable and equation indices into the block-decomposition order.
|
|
|
|
|
Set by updateReverseVariableEquationOrderings() */
|
|
|
|
|
vector<int> eq_idx_orig2block, endo_idx_orig2block;
|
2011-06-22 11:56:07 +02:00
|
|
|
|
|
2020-03-17 18:58:34 +01:00
|
|
|
|
//! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation
|
|
|
|
|
equation_type_and_normalized_equation_t equation_type_and_normalized_equation;
|
|
|
|
|
|
2020-04-30 16:00:16 +02:00
|
|
|
|
/* Stores derivatives of each block w.r.t. endogenous that belong to it.
|
2020-04-24 12:29:02 +02:00
|
|
|
|
The tuple is: equation number (inside the block), variable number (inside
|
|
|
|
|
the block), lead/lag */
|
|
|
|
|
vector<map<tuple<int, int, int>, expr_t>> blocks_derivatives;
|
2020-03-17 18:58:34 +01:00
|
|
|
|
|
2020-04-21 18:10:46 +02:00
|
|
|
|
class BlockInfo
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
BlockSimulationType simulation_type;
|
|
|
|
|
int first_equation; // Stores a block-ordered equation ID
|
|
|
|
|
int size{0};
|
|
|
|
|
int mfs_size{0}; // Size of the minimal feedback set
|
|
|
|
|
bool linear{true}; // Whether the block is linear in endogenous variable
|
|
|
|
|
int n_static{0}, n_forward{0}, n_backward{0}, n_mixed{0};
|
2020-04-30 11:15:55 +02:00
|
|
|
|
int max_endo_lag{0}, max_endo_lead{0}; // Maximum lag/lead on endos that appear in and *that belong to* the block
|
|
|
|
|
int max_other_endo_lag{0}, max_other_endo_lead{0}; // Maximum lag/lead on endos that appear in but do not belong to the block
|
|
|
|
|
int max_exo_lag{0}, max_exo_lead{0};
|
|
|
|
|
int max_exo_det_lag{0}, max_exo_det_lead{0};
|
|
|
|
|
int max_lag{0}, max_lead{0}; // The max over all endo/exo variables
|
2020-04-23 16:04:02 +02:00
|
|
|
|
|
2022-06-24 15:08:49 +02:00
|
|
|
|
int
|
|
|
|
|
getRecursiveSize() const
|
|
|
|
|
{
|
|
|
|
|
return size - mfs_size;
|
|
|
|
|
};
|
2020-04-21 18:10:46 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Stores various informations on the blocks
|
|
|
|
|
vector<BlockInfo> blocks;
|
|
|
|
|
|
2020-04-29 16:41:33 +02:00
|
|
|
|
// Maps endogenous type-specific IDs to the block number to which it belongs
|
|
|
|
|
vector<int> endo2block;
|
|
|
|
|
/* Maps (original) equation number to the block number to which it belongs.
|
|
|
|
|
It verifies: ∀i, eq2block[endo2eq[i]] = endo2block[i] */
|
|
|
|
|
vector<int> eq2block;
|
|
|
|
|
|
2020-05-13 16:58:19 +02:00
|
|
|
|
/* Temporary terms for block decomposed models.
|
|
|
|
|
- the outer vector has as many elements as there are blocks in the model
|
|
|
|
|
- the inner vector has as many elements as there are equations in the
|
|
|
|
|
block, plus a last one which contains the temporary terms for
|
|
|
|
|
derivatives
|
|
|
|
|
|
|
|
|
|
It’s necessary to track temporary terms per equation, because some
|
|
|
|
|
equations are evaluated instead of solved, and an equation E1 may depend
|
|
|
|
|
on the value of an endogenous Y computed by a previously evaluated equation
|
|
|
|
|
E2; in this case, if some temporary term TT of equation E2 contains Y,
|
|
|
|
|
then TT needs to be computed after E1, but before E2. */
|
|
|
|
|
vector<vector<temporary_terms_t>> blocks_temporary_terms;
|
2020-05-06 17:13:47 +02:00
|
|
|
|
|
|
|
|
|
/* Stores, for each temporary term in block decomposed models, its index in
|
|
|
|
|
the vector of all temporary terms */
|
|
|
|
|
temporary_terms_idxs_t blocks_temporary_terms_idxs;
|
|
|
|
|
|
2018-11-22 14:32:40 +01:00
|
|
|
|
//! Computes derivatives
|
|
|
|
|
/*! \param order the derivation order
|
|
|
|
|
\param vars the derivation IDs w.r.t. which compute the derivatives */
|
|
|
|
|
void computeDerivatives(int order, const set<int> &vars);
|
2012-11-29 18:07:48 +01:00
|
|
|
|
//! Computes derivatives of the Jacobian and Hessian w.r. to parameters
|
2016-05-18 12:26:19 +02:00
|
|
|
|
void computeParamsDerivatives(int paramsDerivsOrder);
|
2009-04-20 12:48:54 +02:00
|
|
|
|
//! Computes temporary terms (for all equations and derivatives)
|
2018-09-25 15:56:52 +02:00
|
|
|
|
void computeTemporaryTerms(bool is_matlab, bool no_tmp_terms);
|
2020-05-06 17:13:47 +02:00
|
|
|
|
//! Computes temporary terms per block
|
|
|
|
|
void computeBlockTemporaryTerms();
|
|
|
|
|
/* Add additional temporary terms for a given block. This method is called by
|
|
|
|
|
computeBlockTemporaryTerms(). It does nothing by default, but is meant to
|
|
|
|
|
be overriden by subclasses (actually by DynamicModel, who needs extra
|
|
|
|
|
temporary terms for derivatives w.r.t. exogenous and other endogenous) */
|
|
|
|
|
virtual void additionalBlockTemporaryTerms(int blk,
|
2020-05-13 16:58:19 +02:00
|
|
|
|
vector<vector<temporary_terms_t>> &blocks_temporary_terms,
|
|
|
|
|
map<expr_t, tuple<int, int, int>> &reference_count) const;
|
2012-11-29 18:07:48 +01:00
|
|
|
|
//! Computes temporary terms for the file containing parameters derivatives
|
|
|
|
|
void computeParamsDerivativesTemporaryTerms();
|
2017-06-14 07:01:31 +02:00
|
|
|
|
//! Writes temporary terms
|
2018-11-16 16:53:07 +01:00
|
|
|
|
void writeTemporaryTerms(const temporary_terms_t &tt, temporary_terms_t &temp_term_union, const temporary_terms_idxs_t &tt_idxs, ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const;
|
2019-04-18 14:34:48 +02:00
|
|
|
|
void writeJsonTemporaryTerms(const temporary_terms_t &tt, temporary_terms_t &temp_term_union, ostream &output, deriv_node_temp_terms_t &tef_terms, const string &concat) const;
|
2022-06-23 14:28:13 +02:00
|
|
|
|
//! Writes temporary terms in bytecode
|
2022-07-06 16:44:51 +02:00
|
|
|
|
void writeBytecodeTemporaryTerms(BytecodeWriter &code_file, ExprNodeBytecodeOutputType output_type, temporary_terms_t &temporary_terms_union, const temporary_terms_idxs_t &temporary_terms_idxs, deriv_node_temp_terms_t &tef_terms) const;
|
2020-05-19 17:43:35 +02:00
|
|
|
|
//! Adds information for (non-block) bytecode simulation in a separate .bin file
|
|
|
|
|
void writeBytecodeBinFile(const string &filename, int &u_count_int, bool &file_open, bool is_two_boundaries) const;
|
2016-12-30 11:26:56 +01:00
|
|
|
|
//! Fixes output when there are more than 32 nested parens, Issue #1201
|
2017-01-05 15:19:13 +01:00
|
|
|
|
void fixNestedParenthesis(ostringstream &output, map<string, string> &tmp_paren_vars, bool &message_printed) const;
|
2016-12-30 11:26:56 +01:00
|
|
|
|
//! Tests if string contains more than 32 nested parens, Issue #1201
|
|
|
|
|
bool testNestedParenthesis(const string &str) const;
|
2018-11-16 16:53:07 +01:00
|
|
|
|
void writeModelLocalVariableTemporaryTerms(temporary_terms_t &temp_term_union,
|
2018-11-16 18:13:34 +01:00
|
|
|
|
const temporary_terms_idxs_t &tt_idxs,
|
2018-03-27 17:14:30 +02:00
|
|
|
|
ostream &output, ExprNodeOutputType output_type,
|
|
|
|
|
deriv_node_temp_terms_t &tef_terms) const;
|
2008-02-03 11:28:36 +01:00
|
|
|
|
//! Writes model equations
|
2018-03-27 17:14:30 +02:00
|
|
|
|
void writeModelEquations(ostream &output, ExprNodeOutputType output_type,
|
2018-05-24 19:29:53 +02:00
|
|
|
|
const temporary_terms_t &temporary_terms) const;
|
2022-07-11 17:33:09 +02:00
|
|
|
|
|
|
|
|
|
// Returns outputs for derivatives and temporary terms at each derivation order
|
|
|
|
|
template<ExprNodeOutputType output_type>
|
|
|
|
|
pair<vector<ostringstream>, vector<ostringstream>> writeModelFileHelper() const;
|
|
|
|
|
|
2022-07-12 12:27:22 +02:00
|
|
|
|
/* Helper for writing derivatives w.r.t. parameters.
|
|
|
|
|
Returns { tt, rp, gp, rpp, gpp, hp, g3p }.
|
|
|
|
|
g3p is empty if requesting a static output type. */
|
|
|
|
|
template<ExprNodeOutputType output_type>
|
|
|
|
|
tuple<ostringstream, ostringstream, ostringstream, ostringstream,
|
|
|
|
|
ostringstream, ostringstream, ostringstream> writeParamsDerivativesFileHelper() const;
|
|
|
|
|
|
2017-02-02 15:09:43 +01:00
|
|
|
|
//! Writes JSON model equations
|
2017-02-20 12:18:11 +01:00
|
|
|
|
//! if residuals = true, we are writing the dynamic/static model.
|
|
|
|
|
//! Otherwise, just the model equations (with line numbers, no tmp terms)
|
|
|
|
|
void writeJsonModelEquations(ostream &output, bool residuals) const;
|
2020-06-05 16:07:52 +02:00
|
|
|
|
/* Writes JSON model local variables.
|
|
|
|
|
Optionally put the external function variable calls into TEF terms */
|
|
|
|
|
void writeJsonModelLocalVariables(ostream &output, bool write_tef_terms, deriv_node_temp_terms_t &tef_terms) const;
|
2022-06-23 14:28:13 +02:00
|
|
|
|
//! Writes model equations in bytecode
|
2022-07-06 16:44:51 +02:00
|
|
|
|
void writeBytecodeModelEquations(BytecodeWriter &code_file, ExprNodeBytecodeOutputType output_type, const temporary_terms_t &temporary_terms_union, const temporary_terms_idxs_t &temporary_terms_idxs, const deriv_node_temp_terms_t &tef_terms) const;
|
2008-02-03 11:28:36 +01:00
|
|
|
|
|
2009-04-30 15:14:33 +02:00
|
|
|
|
//! Writes LaTeX model file
|
2019-12-16 19:42:59 +01:00
|
|
|
|
void writeLatexModelFile(const string &mod_basename, const string &latex_basename, ExprNodeOutputType output_type, bool write_equation_tags) const;
|
2009-04-30 15:14:33 +02:00
|
|
|
|
|
2020-04-28 18:00:26 +02:00
|
|
|
|
//! Sparse matrix of double to store the values of the static Jacobian
|
2009-12-16 14:21:31 +01:00
|
|
|
|
/*! First index is equation number, second index is endogenous type specific ID */
|
2018-06-04 14:31:26 +02:00
|
|
|
|
using jacob_map_t = map<pair<int, int>, double>;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
|
2020-03-24 16:57:45 +01:00
|
|
|
|
//! Normalization of equations, as computed by computeNonSingularNormalization()
|
2009-12-16 14:21:31 +01:00
|
|
|
|
/*! Maps endogenous type specific IDs to equation numbers */
|
|
|
|
|
vector<int> endo2eq;
|
|
|
|
|
|
2020-04-15 17:56:28 +02:00
|
|
|
|
/* Compute a pseudo-Jacobian whose all elements are either zero or one,
|
|
|
|
|
depending on whether the variable symbolically appears in the equation */
|
|
|
|
|
jacob_map_t computeSymbolicJacobian() const;
|
|
|
|
|
|
2020-04-17 14:55:55 +02:00
|
|
|
|
// Compute {var,eq}_idx_orig2block from {var,eq}_idx_block2orig
|
2020-04-15 17:56:28 +02:00
|
|
|
|
void updateReverseVariableEquationOrderings();
|
|
|
|
|
|
2009-12-16 14:21:31 +01:00
|
|
|
|
//! Compute the matching between endogenous and variable using the jacobian contemporaneous_jacobian
|
2009-12-21 11:29:21 +01:00
|
|
|
|
/*!
|
|
|
|
|
\param contemporaneous_jacobian Jacobian used as an incidence matrix: all elements declared in the map (even if they are zero), are used as vertices of the incidence matrix
|
|
|
|
|
\return True if a complete normalization has been achieved
|
|
|
|
|
*/
|
2022-04-19 17:06:37 +02:00
|
|
|
|
bool computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool dynamic, bool verbose);
|
2009-12-21 11:29:21 +01:00
|
|
|
|
|
2009-12-16 14:21:31 +01:00
|
|
|
|
//! Try to compute the matching between endogenous and variable using a decreasing cutoff
|
2009-12-21 11:29:21 +01:00
|
|
|
|
/*!
|
|
|
|
|
Applied to the jacobian contemporaneous_jacobian and stop when a matching is found.
|
|
|
|
|
If no matching is found using a strictly positive cutoff, then a zero cutoff is applied (i.e. use a symbolic normalization); in that case, the method adds zeros in the jacobian matrices to reflect all the edges in the symbolic incidence matrix.
|
2020-03-24 16:57:45 +01:00
|
|
|
|
If no matching is found with a zero cutoff, an error message is printed.
|
|
|
|
|
The resulting normalization is stored in endo2eq.
|
2009-12-21 11:29:21 +01:00
|
|
|
|
*/
|
2022-04-19 17:06:37 +02:00
|
|
|
|
void computeNonSingularNormalization(const jacob_map_t &contemporaneous_jacobian, bool dynamic);
|
2020-03-20 18:42:59 +01:00
|
|
|
|
//! Evaluate the jacobian (w.r.t. endogenous) and suppress all the elements below the cutoff
|
2020-05-06 18:09:44 +02:00
|
|
|
|
/*! Returns the contemporaneous_jacobian.
|
2020-04-28 18:00:26 +02:00
|
|
|
|
Elements below the cutoff are discarded. External functions are evaluated to 1. */
|
2020-05-06 18:09:44 +02:00
|
|
|
|
jacob_map_t evaluateAndReduceJacobian(const eval_context_t &eval_context) const;
|
2020-04-30 12:48:16 +02:00
|
|
|
|
/* Search the equations and variables belonging to the prologue and the
|
|
|
|
|
epilogue of the model.
|
|
|
|
|
Initializes “eq_idx_block2orig” and “endo_idx_block2orig”.
|
|
|
|
|
Returns the sizes of the prologue and epilogue. */
|
|
|
|
|
pair<int, int> computePrologueAndEpilogue();
|
2020-03-20 18:47:29 +01:00
|
|
|
|
//! Determine the type of each equation of model and try to normalize the unnormalized equation
|
2020-03-20 15:23:23 +01:00
|
|
|
|
void equationTypeDetermination(const map<tuple<int, int, int>, expr_t> &first_order_endo_derivatives, int mfs);
|
2020-04-30 11:15:55 +02:00
|
|
|
|
/* Fills the max lags/leads and n_{static,mixed,forward,backward} fields of a
|
|
|
|
|
given block.
|
|
|
|
|
Needs the fields size and first_equation. */
|
|
|
|
|
void computeDynamicStructureOfBlock(int blk);
|
2020-04-30 12:48:16 +02:00
|
|
|
|
/* Fills the simulation_type field of a given block.
|
|
|
|
|
Needs the fields size, max_endo_lag and max_endo_lead. */
|
|
|
|
|
void computeSimulationTypeOfBlock(int blk);
|
2020-04-21 18:10:46 +02:00
|
|
|
|
/* Compute the block decomposition and for a non-recusive block find the minimum feedback set
|
|
|
|
|
|
2020-04-30 12:48:16 +02:00
|
|
|
|
Initializes the “blocks”, “endo2block” and “eq2block” structures. */
|
|
|
|
|
void computeBlockDecomposition(int prologue, int epilogue);
|
2020-04-21 18:10:46 +02:00
|
|
|
|
/* Reduce the number of block by merging the same type of equations in the
|
2020-04-30 12:48:16 +02:00
|
|
|
|
prologue and the epilogue */
|
|
|
|
|
void reduceBlockDecomposition();
|
2020-04-17 19:21:37 +02:00
|
|
|
|
/* The 1st output gives, for each equation (in original order) the (max_lag,
|
|
|
|
|
max_lead) across all endogenous that appear in the equation and that
|
|
|
|
|
belong to the same block (i.e. those endogenous are solved in the same
|
|
|
|
|
block).
|
|
|
|
|
|
|
|
|
|
The 2nd output gives, for each type-specific endo IDs, its (max_lag,
|
|
|
|
|
max_lead) across all its occurences inside the equations of the block to
|
|
|
|
|
which it belongs. */
|
2020-04-29 16:41:33 +02:00
|
|
|
|
pair<lag_lead_vector_t, lag_lead_vector_t> getVariableLeadLagByBlock() const;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
//! Print an abstract of the block structure of the model
|
2020-04-15 17:56:28 +02:00
|
|
|
|
void printBlockDecomposition() const;
|
2009-12-16 14:21:31 +01:00
|
|
|
|
//! Determine for each block if it is linear or not
|
2020-03-20 15:23:23 +01:00
|
|
|
|
void determineLinearBlocks();
|
2009-12-16 14:21:31 +01:00
|
|
|
|
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the type of equation belonging to the block
|
2020-04-17 16:04:19 +02:00
|
|
|
|
EquationType
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockEquationType(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return equation_type_and_normalized_equation[eq_idx_block2orig[blocks[blk].first_equation+eq]].first;
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2009-12-16 14:21:31 +01:00
|
|
|
|
//! Return true if the equation has been normalized
|
2020-04-17 16:04:19 +02:00
|
|
|
|
bool
|
2020-04-23 16:04:02 +02:00
|
|
|
|
isBlockEquationRenormalized(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-05-20 11:49:32 +02:00
|
|
|
|
return equation_type_and_normalized_equation[eq_idx_block2orig[blocks[blk].first_equation + eq]].first == EquationType::evaluateRenormalized;
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the expr_t of equation belonging to the block
|
2020-05-07 15:20:11 +02:00
|
|
|
|
BinaryOpNode *
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockEquationExpr(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return equations[eq_idx_block2orig[blocks[blk].first_equation + eq]];
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the expr_t of renormalized equation belonging to the block
|
2020-05-07 15:20:11 +02:00
|
|
|
|
BinaryOpNode *
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockEquationRenormalizedExpr(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return equation_type_and_normalized_equation[eq_idx_block2orig[blocks[blk].first_equation + eq]].second;
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the original number of equation belonging to the block
|
2020-04-17 16:04:19 +02:00
|
|
|
|
int
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockEquationID(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return eq_idx_block2orig[blocks[blk].first_equation + eq];
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the original number of variable belonging to the block
|
2020-04-17 16:04:19 +02:00
|
|
|
|
int
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockVariableID(int blk, int var) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return endo_idx_block2orig[blocks[blk].first_equation + var];
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the position of an equation (given by its original index) inside its block
|
2020-04-17 16:04:19 +02:00
|
|
|
|
int
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockInitialEquationID(int blk, int eq) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return eq_idx_orig2block[eq] - blocks[blk].first_equation;
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2020-04-23 16:04:02 +02:00
|
|
|
|
//! Return the position of a variable (given by its original index) inside its block
|
2020-04-17 16:04:19 +02:00
|
|
|
|
int
|
2020-04-23 16:04:02 +02:00
|
|
|
|
getBlockInitialVariableID(int blk, int var) const
|
2020-04-17 16:04:19 +02:00
|
|
|
|
{
|
2020-04-23 16:04:02 +02:00
|
|
|
|
return endo_idx_orig2block[var] - blocks[blk].first_equation;
|
2020-04-17 16:04:19 +02:00
|
|
|
|
};
|
2011-06-22 11:56:07 +02:00
|
|
|
|
//! Initialize equation_reordered & variable_reordered
|
|
|
|
|
void initializeVariablesAndEquations();
|
2020-03-30 14:51:53 +02:00
|
|
|
|
//! Returns the 1st derivatives w.r.t. endogenous in a different format
|
|
|
|
|
/*! Returns a map (equation, type-specific ID, lag) → derivative.
|
|
|
|
|
Assumes that derivatives have already been computed. */
|
|
|
|
|
map<tuple<int, int, int>, expr_t> collectFirstOrderDerivativesEndogenous();
|
2018-10-09 18:27:19 +02:00
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
//! Internal helper for the copy constructor and assignment operator
|
|
|
|
|
/*! Copies all the structures that contain ExprNode*, by the converting the
|
|
|
|
|
pointers into their equivalent in the new tree */
|
|
|
|
|
void copyHelper(const ModelTree &m);
|
2018-10-26 11:44:26 +02:00
|
|
|
|
//! Returns the name of the MATLAB architecture given the extension used for MEX files
|
|
|
|
|
static string matlab_arch(const string &mexext);
|
2021-09-13 15:14:10 +02:00
|
|
|
|
#ifdef __APPLE__
|
|
|
|
|
//! Finds a suitable GCC compiler on macOS
|
2022-05-23 10:22:57 +02:00
|
|
|
|
static string findGccOnMacos(const string &mexext);
|
2021-09-13 15:14:10 +02:00
|
|
|
|
#endif
|
2020-05-29 16:12:01 +02:00
|
|
|
|
//! Compiles a MEX file
|
2020-06-23 15:13:04 +02:00
|
|
|
|
void compileMEX(const string &basename, const string &funcname, const string &mexext, const vector<filesystem::path> &src_files, const filesystem::path &matlabroot, const filesystem::path &dynareroot) const;
|
2018-10-09 18:27:19 +02:00
|
|
|
|
|
2008-02-03 11:28:36 +01:00
|
|
|
|
public:
|
2018-08-14 14:23:21 +02:00
|
|
|
|
ModelTree(SymbolTable &symbol_table_arg,
|
|
|
|
|
NumericalConstants &num_constants_arg,
|
2018-10-09 18:27:19 +02:00
|
|
|
|
ExternalFunctionsTable &external_functions_table_arg,
|
|
|
|
|
bool is_dynamic_arg = false);
|
|
|
|
|
|
2022-05-18 18:24:13 +02:00
|
|
|
|
protected:
|
2018-10-09 18:27:19 +02:00
|
|
|
|
ModelTree(const ModelTree &m);
|
2019-12-20 16:59:30 +01:00
|
|
|
|
ModelTree &operator=(const ModelTree &m);
|
2018-10-09 18:27:19 +02:00
|
|
|
|
|
2022-05-18 18:24:13 +02:00
|
|
|
|
public:
|
2011-06-22 11:56:07 +02:00
|
|
|
|
//! Absolute value under which a number is considered to be zero
|
2018-10-04 17:18:27 +02:00
|
|
|
|
double cutoff{1e-15};
|
2011-06-22 11:56:07 +02:00
|
|
|
|
//! Compute the minimum feedback set
|
|
|
|
|
/*! 0 : all endogenous variables are considered as feedback variables
|
|
|
|
|
1 : the variables belonging to non normalized equation are considered as feedback variables
|
|
|
|
|
2 : the variables belonging to a non linear equation are considered as feedback variables
|
|
|
|
|
3 : the variables belonging to a non normalizable non linear equation are considered as feedback variables
|
|
|
|
|
default value = 0 */
|
2018-10-04 17:18:27 +02:00
|
|
|
|
int mfs{0};
|
2014-01-27 16:41:43 +01:00
|
|
|
|
//! Declare a node as an equation of the model; also give its line number
|
2022-05-05 18:39:27 +02:00
|
|
|
|
void addEquation(expr_t eq, optional<int> lineno);
|
2013-04-11 17:07:39 +02:00
|
|
|
|
//! Declare a node as an equation of the model, also giving its tags
|
2022-05-05 18:39:27 +02:00
|
|
|
|
void addEquation(expr_t eq, optional<int> lineno, const map<string, string> &eq_tags);
|
2009-09-30 17:10:31 +02:00
|
|
|
|
//! Declare a node as an auxiliary equation of the model, adding it at the end of the list of auxiliary equations
|
2010-09-16 19:18:45 +02:00
|
|
|
|
void addAuxEquation(expr_t eq);
|
2008-10-17 19:21:22 +02:00
|
|
|
|
//! Returns the number of equations in the model
|
2008-02-03 11:28:36 +01:00
|
|
|
|
int equation_number() const;
|
2010-10-15 19:05:16 +02:00
|
|
|
|
//! Adds a trend variable with its growth factor
|
2019-07-05 18:36:10 +02:00
|
|
|
|
void addTrendVariables(const vector<int> &trend_vars, expr_t growth_factor) noexcept(false);
|
2013-03-26 16:46:18 +01:00
|
|
|
|
//! Adds a nonstationary variables with their (common) deflator
|
2019-07-05 18:36:10 +02:00
|
|
|
|
void addNonstationaryVariables(const vector<int> &nonstationary_vars, bool log_deflator, expr_t deflator) noexcept(false);
|
2013-10-29 11:47:59 +01:00
|
|
|
|
//! Is a given variable non-stationary?
|
|
|
|
|
bool isNonstationary(int symb_id) const;
|
2011-06-22 11:56:07 +02:00
|
|
|
|
void set_cutoff_to_zero();
|
2019-12-03 14:19:32 +01:00
|
|
|
|
/*! Reorder auxiliary variables so that they appear in recursive order in
|
|
|
|
|
set_auxiliary_variables.m and dynamic_set_auxiliary_series.m */
|
|
|
|
|
void reorderAuxiliaryEquations();
|
2020-03-27 18:14:17 +01:00
|
|
|
|
//! Find equations of the form “variable=constant”, excluding equations with “mcp” tag (see dynare#1697)
|
|
|
|
|
void findConstantEquationsWithoutMcpTag(map<VariableNode *, NumConstNode *> &subst_table) const;
|
2021-10-26 18:06:26 +02:00
|
|
|
|
/* Given an expression, searches for the first equation that has exactly this
|
|
|
|
|
expression on the LHS, and returns the RHS of that equation.
|
|
|
|
|
If no such equation can be found, throws an ExprNode::MatchFailureExpression */
|
|
|
|
|
expr_t getRHSFromLHS(expr_t lhs) const;
|
2019-12-13 17:15:03 +01:00
|
|
|
|
|
|
|
|
|
//! Returns all the equation tags associated to an equation
|
2022-06-24 15:08:49 +02:00
|
|
|
|
map<string, string>
|
2019-12-20 16:59:30 +01:00
|
|
|
|
getEquationTags(int eq) const
|
2019-12-13 17:15:03 +01:00
|
|
|
|
{
|
2020-02-20 15:29:10 +01:00
|
|
|
|
return equation_tags.getTagsByEqn(eq);
|
2019-12-13 17:15:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 14:52:29 +02:00
|
|
|
|
//! Returns the vector of non-zero derivative counts
|
2022-06-24 15:08:49 +02:00
|
|
|
|
const vector<int> &
|
2021-04-22 14:52:29 +02:00
|
|
|
|
getNNZDerivatives() const
|
|
|
|
|
{
|
|
|
|
|
return NNZDerivatives;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-11 12:37:31 +02:00
|
|
|
|
//! Returns the vector of temporary terms derivatives
|
2022-06-24 15:08:49 +02:00
|
|
|
|
const vector<temporary_terms_t> &
|
2021-06-11 12:37:31 +02:00
|
|
|
|
getTemporaryTermsDerivatives() const
|
|
|
|
|
{
|
|
|
|
|
return temporary_terms_derivatives;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 14:52:29 +02:00
|
|
|
|
//!Returns the maximum order of computed derivatives
|
2022-06-24 15:08:49 +02:00
|
|
|
|
int
|
2021-04-22 14:52:29 +02:00
|
|
|
|
getComputedDerivsOrder() const
|
|
|
|
|
{
|
|
|
|
|
return computed_derivs_order;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 15:08:49 +02:00
|
|
|
|
static string
|
2020-03-20 17:31:14 +01:00
|
|
|
|
BlockSim(BlockSimulationType type)
|
2009-12-16 18:13:23 +01:00
|
|
|
|
{
|
|
|
|
|
switch (type)
|
|
|
|
|
{
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::evaluateForward:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "EVALUATE FORWARD ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::evaluateBackward:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "EVALUATE BACKWARD ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveForwardSimple:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE FORWARD SIMPLE ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveBackwardSimple:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE BACKWARD SIMPLE ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveTwoBoundariesSimple:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE TWO BOUNDARIES SIMPLE ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveForwardComplete:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE FORWARD COMPLETE ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveBackwardComplete:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE BACKWARD COMPLETE ";
|
2020-03-20 17:31:14 +01:00
|
|
|
|
case BlockSimulationType::solveTwoBoundariesComplete:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "SOLVE TWO BOUNDARIES COMPLETE";
|
2009-12-16 18:13:23 +01:00
|
|
|
|
default:
|
2019-12-16 19:42:59 +01:00
|
|
|
|
return "UNKNOWN ";
|
2009-12-16 18:13:23 +01:00
|
|
|
|
}
|
2020-03-20 18:00:56 +01:00
|
|
|
|
}
|
2008-02-03 11:28:36 +01:00
|
|
|
|
};
|
|
|
|
|
|
2022-07-11 17:33:09 +02:00
|
|
|
|
template<ExprNodeOutputType output_type>
|
|
|
|
|
pair<vector<ostringstream>, vector<ostringstream>>
|
|
|
|
|
ModelTree::writeModelFileHelper() const
|
|
|
|
|
{
|
|
|
|
|
vector<ostringstream> d_output(derivatives.size()); // Derivatives output (at all orders, including 0=residual)
|
|
|
|
|
vector<ostringstream> tt_output(derivatives.size()); // Temp terms output (at all orders)
|
|
|
|
|
|
|
|
|
|
deriv_node_temp_terms_t tef_terms;
|
|
|
|
|
temporary_terms_t temp_term_union;
|
|
|
|
|
|
|
|
|
|
writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_idxs,
|
|
|
|
|
tt_output[0], output_type, tef_terms);
|
|
|
|
|
|
|
|
|
|
writeTemporaryTerms(temporary_terms_derivatives[0],
|
|
|
|
|
temp_term_union,
|
|
|
|
|
temporary_terms_idxs,
|
|
|
|
|
tt_output[0], output_type, tef_terms);
|
|
|
|
|
|
|
|
|
|
writeModelEquations(d_output[0], output_type, temp_term_union);
|
|
|
|
|
|
|
|
|
|
// Writing Jacobian
|
|
|
|
|
if (!derivatives[1].empty())
|
|
|
|
|
{
|
|
|
|
|
writeTemporaryTerms(temporary_terms_derivatives[1],
|
|
|
|
|
temp_term_union,
|
|
|
|
|
temporary_terms_idxs,
|
|
|
|
|
tt_output[1], output_type, tef_terms);
|
|
|
|
|
|
|
|
|
|
for (const auto &[indices, d1] : derivatives[1])
|
|
|
|
|
{
|
|
|
|
|
auto [eq, var] = vectorToTuple<2>(indices);
|
|
|
|
|
|
|
|
|
|
d_output[1] << "g1" << LEFT_ARRAY_SUBSCRIPT(output_type);
|
|
|
|
|
if constexpr(isMatlabOutput(output_type) || isJuliaOutput(output_type))
|
|
|
|
|
d_output[1] << eq + 1 << "," << getJacobianCol(var) + 1;
|
|
|
|
|
else
|
|
|
|
|
d_output[1] << eq + getJacobianCol(var)*equations.size();
|
|
|
|
|
d_output[1] << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
|
|
|
|
|
d1->writeOutput(d_output[1], output_type,
|
|
|
|
|
temp_term_union, temporary_terms_idxs, tef_terms);
|
|
|
|
|
d_output[1] << ";" << endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write derivatives for order ≥ 2
|
|
|
|
|
for (size_t i = 2; i < derivatives.size(); i++)
|
|
|
|
|
if (!derivatives[i].empty())
|
|
|
|
|
{
|
|
|
|
|
writeTemporaryTerms(temporary_terms_derivatives[i],
|
|
|
|
|
temp_term_union,
|
|
|
|
|
temporary_terms_idxs,
|
|
|
|
|
tt_output[i], output_type, tef_terms);
|
|
|
|
|
|
|
|
|
|
/* When creating the sparse matrix (in MATLAB or C mode), since storage
|
|
|
|
|
is in column-major order, output the first column, then the second,
|
|
|
|
|
then the third. This gives a significant performance boost in use_dll
|
|
|
|
|
mode (at both compilation and runtime), because it facilitates memory
|
|
|
|
|
accesses and expression reusage. */
|
|
|
|
|
ostringstream i_output, j_output, v_output;
|
|
|
|
|
|
|
|
|
|
for (int k{0}; // Current line index in the 3-column matrix
|
|
|
|
|
const auto &[vidx, d] : derivatives[i])
|
|
|
|
|
{
|
|
|
|
|
int eq{vidx[0]};
|
|
|
|
|
|
|
|
|
|
int col_idx{0};
|
|
|
|
|
for (size_t j = 1; j < vidx.size(); j++)
|
|
|
|
|
{
|
|
|
|
|
col_idx *= getJacobianColsNbr();
|
|
|
|
|
col_idx += getJacobianCol(vidx[j]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if constexpr(isJuliaOutput(output_type))
|
|
|
|
|
{
|
2022-07-12 13:07:33 +02:00
|
|
|
|
d_output[i] << " g" << i << "[" << eq + 1 << "," << col_idx + 1 << "] = ";
|
2022-07-11 17:33:09 +02:00
|
|
|
|
d->writeOutput(d_output[i], output_type, temp_term_union, temporary_terms_idxs, tef_terms);
|
|
|
|
|
d_output[i] << endl;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
i_output << "g" << i << "_i" << LEFT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< "=" << eq + 1 << ";" << endl;
|
|
|
|
|
j_output << "g" << i << "_j" << LEFT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< "=" << col_idx + 1 << ";" << endl;
|
|
|
|
|
v_output << "g" << i << "_v" << LEFT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
|
|
|
|
|
d->writeOutput(v_output, output_type, temp_term_union, temporary_terms_idxs, tef_terms);
|
|
|
|
|
v_output << ";" << endl;
|
|
|
|
|
|
|
|
|
|
k++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Output symetric elements at order 2
|
|
|
|
|
if (i == 2 && vidx[1] != vidx[2])
|
|
|
|
|
{
|
|
|
|
|
int col_idx_sym{getJacobianCol(vidx[2]) * getJacobianColsNbr() + getJacobianCol(vidx[1])};
|
|
|
|
|
|
|
|
|
|
if constexpr(isJuliaOutput(output_type))
|
2022-07-12 13:07:33 +02:00
|
|
|
|
d_output[2] << " g2[" << eq + 1 << "," << col_idx_sym + 1 << "] = "
|
2022-07-11 17:33:09 +02:00
|
|
|
|
<< "g2[" << eq + 1 << "," << col_idx + 1 << "]" << endl;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
i_output << "g" << i << "_i" << LEFT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< "=" << eq + 1 << ";" << endl;
|
|
|
|
|
j_output << "g" << i << "_j" << LEFT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< "=" << col_idx_sym + 1 << ";" << endl;
|
|
|
|
|
v_output << "g" << i << "_v" << LEFT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "="
|
|
|
|
|
<< "g" << i << "_v" << LEFT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< k-1 + ARRAY_SUBSCRIPT_OFFSET(output_type)
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << ";" << endl;
|
|
|
|
|
|
|
|
|
|
k++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if constexpr(!isJuliaOutput(output_type))
|
|
|
|
|
d_output[i] << i_output.str() << j_output.str() << v_output.str();
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-12 12:19:17 +02:00
|
|
|
|
if constexpr(isMatlabOutput(output_type))
|
|
|
|
|
{
|
|
|
|
|
// Check that we don't have more than 32 nested parenthesis because MATLAB does not suppor this. See Issue #1201
|
|
|
|
|
map<string, string> tmp_paren_vars;
|
|
|
|
|
bool message_printed {false};
|
|
|
|
|
for (auto &it : tt_output)
|
|
|
|
|
fixNestedParenthesis(it, tmp_paren_vars, message_printed);
|
|
|
|
|
for (auto &it : d_output)
|
|
|
|
|
fixNestedParenthesis(it, tmp_paren_vars, message_printed);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-11 17:33:09 +02:00
|
|
|
|
return { move(d_output), move(tt_output) };
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-12 12:27:22 +02:00
|
|
|
|
template<ExprNodeOutputType output_type>
|
|
|
|
|
tuple<ostringstream, ostringstream, ostringstream, ostringstream,
|
|
|
|
|
ostringstream, ostringstream, ostringstream>
|
|
|
|
|
ModelTree::writeParamsDerivativesFileHelper() const
|
|
|
|
|
{
|
|
|
|
|
static_assert(!isCOutput(output_type), "C output is not implemented");
|
|
|
|
|
|
|
|
|
|
ostringstream tt_output; // Used for storing model temp vars and equations
|
|
|
|
|
ostringstream rp_output; // 1st deriv. of residuals w.r.t. parameters
|
|
|
|
|
ostringstream gp_output; // 1st deriv. of Jacobian w.r.t. parameters
|
|
|
|
|
ostringstream rpp_output; // 2nd deriv of residuals w.r.t. parameters
|
|
|
|
|
ostringstream gpp_output; // 2nd deriv of Jacobian w.r.t. parameters
|
|
|
|
|
ostringstream hp_output; // 1st deriv. of Hessian w.r.t. parameters
|
|
|
|
|
ostringstream g3p_output; // 1st deriv. of 3rd deriv. matrix w.r.t. parameters (only in dynamic case)
|
|
|
|
|
|
|
|
|
|
temporary_terms_t temp_term_union;
|
|
|
|
|
deriv_node_temp_terms_t tef_terms;
|
|
|
|
|
|
|
|
|
|
writeModelLocalVariableTemporaryTerms(temp_term_union, params_derivs_temporary_terms_idxs, tt_output, output_type, tef_terms);
|
|
|
|
|
for (const auto &[order, tts] : params_derivs_temporary_terms)
|
|
|
|
|
writeTemporaryTerms(tts, temp_term_union, params_derivs_temporary_terms_idxs, tt_output, output_type, tef_terms);
|
|
|
|
|
|
|
|
|
|
for (const auto &[indices, d1] : params_derivatives.find({ 0, 1 })->second)
|
|
|
|
|
{
|
|
|
|
|
auto [eq, param] { vectorToTuple<2>(indices) };
|
|
|
|
|
|
|
|
|
|
int param_col { symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1 };
|
|
|
|
|
|
|
|
|
|
rp_output << "rp" << LEFT_ARRAY_SUBSCRIPT(output_type) << eq+1 << ", " << param_col
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << " = ";
|
|
|
|
|
d1->writeOutput(rp_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
|
|
|
|
|
rp_output << ";" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const auto &[indices, d2] : params_derivatives.find({ 1, 1 })->second)
|
|
|
|
|
{
|
|
|
|
|
auto [eq, var, param] { vectorToTuple<3>(indices) };
|
|
|
|
|
|
|
|
|
|
int var_col { getJacobianCol(var) + 1 };
|
|
|
|
|
int param_col { symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1 };
|
|
|
|
|
|
|
|
|
|
gp_output << "gp" << LEFT_ARRAY_SUBSCRIPT(output_type) << eq+1 << ", " << var_col
|
|
|
|
|
<< ", " << param_col << RIGHT_ARRAY_SUBSCRIPT(output_type) << " = ";
|
|
|
|
|
d2->writeOutput(gp_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
|
|
|
|
|
gp_output << ";" << endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i {1};
|
|
|
|
|
const auto &[indices, d2] : params_derivatives.find({ 0, 2 })->second)
|
|
|
|
|
{
|
|
|
|
|
auto [eq, param1, param2] { vectorToTuple<3>(indices) };
|
|
|
|
|
|
|
|
|
|
int param1_col { symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1 };
|
|
|
|
|
int param2_col { symbol_table.getTypeSpecificID(getSymbIDByDerivID(param2)) + 1 };
|
|
|
|
|
|
|
|
|
|
rpp_output << "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
|
|
|
|
|
<< "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param1_col << ";" << endl
|
|
|
|
|
<< "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param2_col << ";" << endl
|
|
|
|
|
<< "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
|
|
|
|
|
d2->writeOutput(rpp_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
|
|
|
|
|
rpp_output << ";" << endl;
|
|
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
if (param1 != param2)
|
|
|
|
|
{
|
|
|
|
|
// Treat symmetric elements
|
|
|
|
|
rpp_output << "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
|
|
|
|
|
<< "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param2_col << ";" << endl
|
|
|
|
|
<< "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param1_col << ";" << endl
|
|
|
|
|
<< "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< "=rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i-1 << ",4"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << ";" << endl;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i {1};
|
|
|
|
|
const auto &[indices, d2] : params_derivatives.find({ 1, 2 })->second)
|
|
|
|
|
{
|
|
|
|
|
auto [eq, var, param1, param2] { vectorToTuple<4>(indices) };
|
|
|
|
|
|
|
|
|
|
int var_col { getJacobianCol(var) + 1 };
|
|
|
|
|
int param1_col { symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1 };
|
|
|
|
|
int param2_col { symbol_table.getTypeSpecificID(getSymbIDByDerivID(param2)) + 1 };
|
|
|
|
|
|
|
|
|
|
gpp_output << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
|
|
|
|
|
<< "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var_col << ";" << endl
|
|
|
|
|
<< "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param1_col << ";" << endl
|
|
|
|
|
<< "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param2_col << ";" << endl
|
|
|
|
|
<< "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",5"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
|
|
|
|
|
d2->writeOutput(gpp_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
|
|
|
|
|
gpp_output << ";" << endl;
|
|
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
if (param1 != param2)
|
|
|
|
|
{
|
|
|
|
|
// Treat symmetric elements
|
|
|
|
|
gpp_output << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
|
|
|
|
|
<< "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var_col << ";" << endl
|
|
|
|
|
<< "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param2_col << ";" << endl
|
|
|
|
|
<< "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param1_col << ";" << endl
|
|
|
|
|
<< "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",5"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< "=gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i-1 << ",5"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << ";" << endl;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i {1};
|
|
|
|
|
const auto &[indices, d2] : params_derivatives.find({ 2, 1 })->second)
|
|
|
|
|
{
|
|
|
|
|
auto [eq, var1, var2, param] { vectorToTuple<4>(indices) };
|
|
|
|
|
|
|
|
|
|
int var1_col { getJacobianCol(var1) + 1 };
|
|
|
|
|
int var2_col { getJacobianCol(var2) + 1 };
|
|
|
|
|
int param_col { symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1 };
|
|
|
|
|
|
|
|
|
|
hp_output << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
|
|
|
|
|
<< "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var1_col << ";" << endl
|
|
|
|
|
<< "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var2_col << ";" << endl
|
|
|
|
|
<< "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param_col << ";" << endl
|
|
|
|
|
<< "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",5"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
|
|
|
|
|
d2->writeOutput(hp_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
|
|
|
|
|
hp_output << ";" << endl;
|
|
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
|
|
|
|
|
if (var1 != var2)
|
|
|
|
|
{
|
|
|
|
|
// Treat symmetric elements
|
|
|
|
|
hp_output << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
|
|
|
|
|
<< "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var2_col << ";" << endl
|
|
|
|
|
<< "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var1_col << ";" << endl
|
|
|
|
|
<< "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param_col << ";" << endl
|
|
|
|
|
<< "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",5"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
|
|
|
|
|
<< "=hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i-1 << ",5"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << ";" << endl;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if constexpr(output_type == ExprNodeOutputType::matlabDynamicModel
|
|
|
|
|
|| output_type == ExprNodeOutputType::juliaDynamicModel)
|
|
|
|
|
for (int i {1};
|
|
|
|
|
const auto &[indices, d2] : params_derivatives.find({ 3, 1 })->second)
|
|
|
|
|
{
|
|
|
|
|
auto [eq, var1, var2, var3, param] { vectorToTuple<5>(indices) };
|
|
|
|
|
|
|
|
|
|
int var1_col { getJacobianCol(var1) + 1 };
|
|
|
|
|
int var2_col { getJacobianCol(var2) + 1 };
|
|
|
|
|
int var3_col { getJacobianCol(var3) + 1 };
|
|
|
|
|
int param_col { symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1 };
|
|
|
|
|
|
|
|
|
|
g3p_output << "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
|
|
|
|
|
<< "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var1_col << ";" << endl
|
|
|
|
|
<< "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var2_col << ";" << endl
|
|
|
|
|
<< "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var3_col << ";" << endl
|
|
|
|
|
<< "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",5"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param_col << ";" << endl
|
|
|
|
|
<< "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",6"
|
|
|
|
|
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
|
|
|
|
|
d2->writeOutput(g3p_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
|
|
|
|
|
g3p_output << ";" << endl;
|
|
|
|
|
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if constexpr(isMatlabOutput(output_type))
|
|
|
|
|
{
|
|
|
|
|
// Check that we don't have more than 32 nested parenthesis because MATLAB does not support this. See Issue #1201
|
|
|
|
|
map<string, string> tmp_paren_vars;
|
|
|
|
|
bool message_printed {false};
|
|
|
|
|
fixNestedParenthesis(tt_output, tmp_paren_vars, message_printed);
|
|
|
|
|
fixNestedParenthesis(rp_output, tmp_paren_vars, message_printed);
|
|
|
|
|
fixNestedParenthesis(gp_output, tmp_paren_vars, message_printed);
|
|
|
|
|
fixNestedParenthesis(rpp_output, tmp_paren_vars, message_printed);
|
|
|
|
|
fixNestedParenthesis(gpp_output, tmp_paren_vars, message_printed);
|
|
|
|
|
fixNestedParenthesis(hp_output, tmp_paren_vars, message_printed);
|
|
|
|
|
fixNestedParenthesis(g3p_output, tmp_paren_vars, message_printed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { move(tt_output), move(rp_output), move(gp_output),
|
|
|
|
|
move(rpp_output), move(gpp_output), move(hp_output), move(g3p_output) };
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-03 11:28:36 +01:00
|
|
|
|
#endif
|