From be1c5a0226f80dab7a5e332f6250be62b20cc5b8 Mon Sep 17 00:00:00 2001 From: Alan Garny Date: Tue, 5 Nov 2024 13:33:19 +1300 Subject: [PATCH] Generator: various speed improvements. --- src/generator.cpp | 105 ++++++++++++++++++++++------------------------ src/generator_p.h | 4 +- src/utilities.cpp | 45 ++++++++++++++------ src/utilities.h | 14 ++++++- 4 files changed, 96 insertions(+), 72 deletions(-) diff --git a/src/generator.cpp b/src/generator.cpp index 434324b1fb..64ea45616f 100644 --- a/src/generator.cpp +++ b/src/generator.cpp @@ -44,13 +44,18 @@ void Generator::GeneratorImpl::reset() mCode = {}; } -std::string Generator::GeneratorImpl::doVariableIndexString(const AnalyserModelPtr &model, - const AnalyserVariablePtr &variable, - const std::vector &variables) +std::string Generator::GeneratorImpl::variableIndexString(const AnalyserModelPtr &model, + const AnalyserVariablePtr &variable) { // Determine the actual index of the variable in the list of variables by accounting for the fact that some // variables may be untracked. + auto variables = libcellml::variables(variable); + + if (variables.empty()) { + return convertToString(variable->index()); + } + size_t i = MAX_SIZE_T; size_t res = MAX_SIZE_T; @@ -69,36 +74,21 @@ std::string Generator::GeneratorImpl::doVariableIndexString(const AnalyserModelP return convertToString(res); } -std::string Generator::GeneratorImpl::variableIndexString(const AnalyserModelPtr &model, - const AnalyserVariablePtr &variable) -{ - switch (variable->type()) { - case AnalyserVariable::Type::CONSTANT: - return doVariableIndexString(model, variable, model->constants()); - case AnalyserVariable::Type::COMPUTED_CONSTANT: - return doVariableIndexString(model, variable, model->computedConstants()); - case AnalyserVariable::Type::ALGEBRAIC: - return doVariableIndexString(model, variable, model->algebraic()); - default: - break; - } - - return convertToString(variable->index()); -} - bool Generator::GeneratorImpl::doIsTrackedEquation(const AnalyserEquationPtr &equation, bool tracked) { switch (equation->type()) { - case AnalyserEquation::Type::COMPUTED_CONSTANT: - return isTrackedVariable(equation->computedConstants().front()) == tracked; - case AnalyserEquation::Type::NLA: - return true; - case AnalyserEquation::Type::ALGEBRAIC: - return isTrackedVariable(equation->algebraic().front()) == tracked; - case AnalyserEquation::Type::EXTERNAL: - return isTrackedVariable(equation->externals().front()) == tracked; + case AnalyserEquation::Type::COMPUTED_CONSTANT: { + auto variable = equation->computedConstants().front(); + + return doIsTrackedVariable(variable->model(), variable) == tracked; + } + case AnalyserEquation::Type::ALGEBRAIC: { + auto variable = equation->algebraic().front(); + + return doIsTrackedVariable(variable->model(), variable) == tracked; + } default: - return false; + return true; } } @@ -130,15 +120,7 @@ bool Generator::GeneratorImpl::doIsTrackedVariable(const AnalyserVariablePtr &va return false; } - auto model = variable->model(); - - for (const auto &modelVariable : variables(model, false)) { - if ((variable == modelVariable) && trackableVariable(modelVariable, tracked, false)) { - return doIsTrackedVariable(model, modelVariable, tracked); - } - } - - return tracked; + return doIsTrackedVariable(variable->model(), variable, tracked); } bool Generator::GeneratorImpl::isTrackedVariable(const AnalyserVariablePtr &variable) @@ -309,7 +291,7 @@ void Generator::GeneratorImpl::doTrackVariable(const AnalyserVariablePtr &variab auto model = variable->model(); - for (const auto &modelVariable : variables(model, false)) { + for (const auto &modelVariable : variables(variable)) { if (variable == modelVariable) { if (trackableVariable(variable, tracked)) { mTrackedVariables[modelVariable->model()][modelVariable] = tracked; @@ -425,17 +407,29 @@ void Generator::GeneratorImpl::untrackAllAlgebraic(const AnalyserModelPtr &model } } +std::vector Generator::GeneratorImpl::trackableVariables(const AnalyserModelPtr &model) const +{ + auto res = model->constants(); + auto computedConstants = model->computedConstants(); + auto algebraic = model->algebraic(); + + res.insert(res.end(), computedConstants.begin(), computedConstants.end()); + res.insert(res.end(), algebraic.begin(), algebraic.end()); + + return res; +} + void Generator::GeneratorImpl::trackAllVariables(const AnalyserModelPtr &model) { if (validModel(model)) { - doTrackVariables(variables(model, false), true); + doTrackVariables(trackableVariables(model), true); } } void Generator::GeneratorImpl::untrackAllVariables(const AnalyserModelPtr &model) { if (validModel(model)) { - doTrackVariables(variables(model, false), false); + doTrackVariables(trackableVariables(model), false); } } @@ -519,7 +513,7 @@ size_t Generator::GeneratorImpl::trackedVariableCount(const AnalyserModelPtr &mo return 0; } - return doTrackedVariableCount(model, variables(model, false), true); + return doTrackedVariableCount(model, trackableVariables(model), true); } size_t Generator::GeneratorImpl::untrackedVariableCount(const AnalyserModelPtr &model) @@ -528,7 +522,7 @@ size_t Generator::GeneratorImpl::untrackedVariableCount(const AnalyserModelPtr & return 0; } - return doTrackedVariableCount(model, variables(model, false), false); + return doTrackedVariableCount(model, trackableVariables(model), false); } bool Generator::GeneratorImpl::modelHasOdes(const AnalyserModelPtr &model) const @@ -783,7 +777,7 @@ void Generator::GeneratorImpl::addStateAndVariableCountCode(const AnalyserModelP code += interface ? mProfile->interfaceConstantCountString() : replace(mProfile->implementationConstantCountString(), - "[CONSTANT_COUNT]", std::to_string(trackedConstantCount(model))); + "[CONSTANT_COUNT]", std::to_string(doTrackedVariableCount(model, model->constants(), true))); } if ((interface && !mProfile->interfaceComputedConstantCountString().empty()) @@ -791,7 +785,7 @@ void Generator::GeneratorImpl::addStateAndVariableCountCode(const AnalyserModelP code += interface ? mProfile->interfaceComputedConstantCountString() : replace(mProfile->implementationComputedConstantCountString(), - "[COMPUTED_CONSTANT_COUNT]", std::to_string(trackedComputedConstantCount(model))); + "[COMPUTED_CONSTANT_COUNT]", std::to_string(doTrackedVariableCount(model, model->computedConstants(), true))); } if ((interface && !mProfile->interfaceAlgebraicCountString().empty()) @@ -799,7 +793,7 @@ void Generator::GeneratorImpl::addStateAndVariableCountCode(const AnalyserModelP code += interface ? mProfile->interfaceAlgebraicCountString() : replace(mProfile->implementationAlgebraicCountString(), - "[ALGEBRAIC_COUNT]", std::to_string(trackedAlgebraicCount(model))); + "[ALGEBRAIC_COUNT]", std::to_string(doTrackedVariableCount(model, model->algebraic(), true))); } if ((model->externalCount() != 0) @@ -825,7 +819,7 @@ std::string Generator::GeneratorImpl::generateVariableInfoObjectCode(const Analy size_t unitsSize = 0; for (const auto &variable : variables(model)) { - if (isTrackedVariable(variable)) { + if (doIsTrackedVariable(model, variable)) { updateVariableInfoSizes(componentSize, nameSize, unitsSize, variable); } } @@ -898,10 +892,11 @@ void Generator::GeneratorImpl::doAddImplementationVariableInfoCode(const std::st if (!variableInfoString.empty() && !mProfile->variableInfoEntryString().empty() && !mProfile->arrayElementSeparatorString().empty()) { + auto model = variables.empty() ? nullptr : variables.front()->model(); std::string infoElementsCode; for (const auto &variable : variables) { - if (isTrackedVariable(variable)) { + if (doIsTrackedVariable(model, variable)) { if (!infoElementsCode.empty()) { infoElementsCode += mProfile->arrayElementSeparatorString() + "\n"; } @@ -1233,7 +1228,7 @@ void Generator::GeneratorImpl::addNlaSystemsCode(const AnalyserModelPtr &model) auto methodBodySize = methodBody.size(); for (const auto &constantDependency : equation->mPimpl->mConstantDependencies) { - if (isUntrackedVariable(constantDependency)) { + if (doIsTrackedVariable(model, constantDependency, false)) { methodBody += generateInitialisationCode(model, constantDependency, true); } } @@ -1395,7 +1390,7 @@ std::string Generator::GeneratorImpl::generateVariableNameCode(const AnalyserMod return mProfile->voiString(); } - if (isUntrackedVariable(analyserVariable)) { + if (doIsTrackedVariable(model, analyserVariable, false)) { return owningComponent(analyserVariable->variable())->name() + "_" + analyserVariable->variable()->name(); } @@ -2105,7 +2100,7 @@ std::string Generator::GeneratorImpl::generateCode(const AnalyserModelPtr &model if ((model != nullptr) && (astParent->type() == AnalyserEquationAst::Type::EQUALITY) && (astParent->leftChild() == ast) - && isUntrackedVariable(model->variable(ast->variable()))) { + && doIsTrackedVariable(model, model->variable(ast->variable()), false)) { // Note: we want this AST to be its parent's left child since a declaration is always of the form x = RHS, // not LHS = x. @@ -2166,7 +2161,7 @@ bool Generator::GeneratorImpl::isToBeComputedAgain(const AnalyserEquationPtr &eq case AnalyserEquation::Type::ALGEBRAIC: if (equation->isStateRateBased()) { for (const auto &variable : variables(equation)) { - if (isTrackedVariable(variable)) { + if (doIsTrackedVariable(variable->model(), variable)) { return true; } } @@ -2202,7 +2197,7 @@ std::string Generator::GeneratorImpl::generateZeroInitialisationCode(const Analy std::string Generator::GeneratorImpl::generateInitialisationCode(const AnalyserModelPtr &model, const AnalyserVariablePtr &variable, bool force) { - if (!force && isUntrackedVariable(variable)) { + if (!force && doIsTrackedVariable(model, variable, false)) { return {}; } @@ -2219,7 +2214,7 @@ std::string Generator::GeneratorImpl::generateInitialisationCode(const AnalyserM + scalingFactorCode + generateDoubleOrConstantVariableNameCode(model, initialisingVariable) + mProfile->commandSeparatorString() + "\n"; - if (isUntrackedVariable(variable)) { + if (doIsTrackedVariable(model, variable, false)) { code = replace(mProfile->variableDeclarationString(), "[CODE]", code); } @@ -2253,7 +2248,7 @@ std::string Generator::GeneratorImpl::generateEquationCode(const AnalyserModelPt for (const auto &constantDependency : equation->mPimpl->mConstantDependencies) { if ((equation->type() != AnalyserEquation::Type::NLA) - && isUntrackedVariable(constantDependency) + && doIsTrackedVariable(model, constantDependency, false) && (std::find(generatedConstantDependencies.begin(), generatedConstantDependencies.end(), constantDependency) == generatedConstantDependencies.end())) { res += generateInitialisationCode(model, constantDependency, true); diff --git a/src/generator_p.h b/src/generator_p.h index 3489d47863..decee926b4 100644 --- a/src/generator_p.h +++ b/src/generator_p.h @@ -43,8 +43,6 @@ struct Generator::GeneratorImpl: public Logger::LoggerImpl void reset(); - std::string doVariableIndexString(const AnalyserModelPtr &model, const AnalyserVariablePtr &variable, - const std::vector &variables); std::string variableIndexString(const AnalyserModelPtr &model, const AnalyserVariablePtr &variable); bool doIsTrackedEquation(const AnalyserEquationPtr &equation, bool tracked); @@ -82,6 +80,8 @@ struct Generator::GeneratorImpl: public Logger::LoggerImpl void trackAllAlgebraic(const AnalyserModelPtr &model); void untrackAllAlgebraic(const AnalyserModelPtr &model); + std::vector trackableVariables(const AnalyserModelPtr &model) const; + void trackAllVariables(const AnalyserModelPtr &model); void untrackAllVariables(const AnalyserModelPtr &model); diff --git a/src/utilities.cpp b/src/utilities.cpp index ca5778a044..9b2a92a6b1 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -28,6 +28,7 @@ limitations under the License. #include "libcellml/analyserequation.h" #include "libcellml/analysermodel.h" +#include "libcellml/analyservariable.h" #include "libcellml/component.h" #include "libcellml/importsource.h" #include "libcellml/model.h" @@ -1317,33 +1318,51 @@ XmlNodePtr mathmlChildNode(const XmlNodePtr &node, size_t index) return res; } -std::vector variables(const AnalyserModelPtr &model, bool allVariables) +std::vector variables(const AnalyserVariablePtr &variable) { std::vector res; - if (allVariables) { - if (model->voi() != nullptr) { - res.push_back(model->voi()); - } + switch (variable->type()) { + case AnalyserVariable::Type::CONSTANT: + return variable->model()->constants(); + + break; + case AnalyserVariable::Type::COMPUTED_CONSTANT: + return variable->model()->computedConstants(); - auto states = model->states(); + break; + case AnalyserVariable::Type::ALGEBRAIC: + return variable->model()->algebraic(); - res.insert(res.end(), states.begin(), states.end()); + break; + default: + break; } + return {}; +} + +std::vector variables(const AnalyserModelPtr &model) +{ + std::vector res; + + if (model->voi() != nullptr) { + res.push_back(model->voi()); + } + + auto states = model->states(); + + res.insert(res.end(), states.begin(), states.end()); + auto constants = model->constants(); auto computedConstants = model->computedConstants(); auto algebraic = model->algebraic(); + auto externals = model->externals(); res.insert(res.end(), constants.begin(), constants.end()); res.insert(res.end(), computedConstants.begin(), computedConstants.end()); res.insert(res.end(), algebraic.begin(), algebraic.end()); - - if (allVariables) { - auto externals = model->externals(); - - res.insert(res.end(), externals.begin(), externals.end()); - } + res.insert(res.end(), externals.begin(), externals.end()); return res; } diff --git a/src/utilities.h b/src/utilities.h index 94b2de820c..fbf9863fa2 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -870,17 +870,27 @@ size_t mathmlChildCount(const XmlNodePtr &node); */ XmlNodePtr mathmlChildNode(const XmlNodePtr &node, size_t index); +/** + * @brief Return the variables of the same type as the given variable. + * + * Return the variables of the same type as the given variable. + * + * @param variable The variable for which we want the variables of the same type. + * + * @return The variables of the same type as the given variable. + */ +std::vector variables(const AnalyserVariablePtr &variable); + /** * @brief Return the variables in the given model. * * Return the variables in the given model. * * @param model The model for which we want the variables. - * @param allVariables Whether to return all variables or just the ones that can be untracked. * * @return The variables in the given model. */ -std::vector variables(const AnalyserModelPtr &model, bool allVariables = true); +std::vector variables(const AnalyserModelPtr &model); /** * @brief Return the variables in the given equation.