Skip to content

Commit 28e249c

Browse files
committed
Analyser: fixed a topological NLA dependency order and added an opaque symbol swap condition.
1 parent 429394d commit 28e249c

4 files changed

Lines changed: 49 additions & 17 deletions

File tree

src/analysersymengine.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,8 +1401,9 @@ AnalyserEquationAstPtr Analyser::AnalyserImpl::symEngineToAst(const SEExpression
14011401
auto seExpressionRhs = (seExpressionArgsSize > 1) ? seExpressionArgs.back() : SEExpression();
14021402

14031403
if ((parentAst == nullptr)
1404-
&& ((osName2osInfoMap != nullptr)
1405-
|| (seExpressionLhs->get_type_code() != SymEngine::SYMENGINE_SYMBOL))) {
1404+
&& ((seExpressionLhs->get_type_code() != SymEngine::SYMENGINE_SYMBOL)
1405+
|| ((osName2osInfoMap != nullptr)
1406+
&& (osName2osInfoMap->count(SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(seExpressionLhs)->get_name()) > 0)))) {
14061407
std::swap(seExpressionArgs.front(), seExpressionArgs.back());
14071408
}
14081409

src/generator.cpp

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ limitations under the License.
1616

1717
#include "libcellml/generator.h"
1818

19+
#include <algorithm>
1920
#include <format>
2021
#include <set>
22+
#include <unordered_map>
2123
#include <unordered_set>
2224

2325
#include "libcellml/analyserequation.h"
@@ -755,7 +757,8 @@ void Generator::GeneratorImpl::addNlaSystemsCode()
755757
if ((analyserEquation->type() == AnalyserEquation::Type::NLA)
756758
&& (handledNlaAnalyserEquations.find(analyserEquation.get()) == handledNlaAnalyserEquations.end())) {
757759
// 1) Generate some code for the objectiveFunction[INDEX]() method.
758-
// a) Retrieve the values from our NLA solver's u array.
760+
// a) Assign the values to our NLA solver's f array for the current equation's algebraic variables
761+
// and collect them in the process.
759762

760763
std::string methodBody;
761764
auto i = MAX_SIZE_T;
@@ -771,17 +774,14 @@ void Generator::GeneratorImpl::addNlaSystemsCode()
771774
+ mProfile->commandSeparatorString() + "\n";
772775
}
773776

774-
// b) Initialise any untracked constant or computed constant that is needed by our NLA system.
777+
// b) Collect the equations that we need to generate code for.
775778

776779
methodBody += "\n";
777780

778-
auto methodBodySize = methodBody.size();
779781
std::vector<AnalyserEquationPtr> nlaEquations;
780782
const auto &nlaSiblings = analyserEquation->nlaSiblings();
781-
const auto &analyserEquations = mAnalyserModel->analyserEquations();
782-
std::unordered_set<AnalyserEquationPtr> dummyRemainingAnalyserEquations(analyserEquations.begin(), analyserEquations.end());
783-
std::unordered_set<AnalyserEquationPtr> dummyAnalyserEquationsForDependencies;
784-
std::unordered_set<AnalyserVariablePtr> dummyGeneratedConstantDependencies;
783+
std::unordered_set<AnalyserEquation *> seenDependencyEquations;
784+
std::vector<AnalyserEquationPtr> collectedDependencies;
785785

786786
nlaEquations.reserve(1 + nlaSiblings.size());
787787

@@ -798,16 +798,42 @@ void Generator::GeneratorImpl::addNlaSystemsCode()
798798
for (const auto &dependency : nlaEquation->dependencies()) {
799799
if (((dependency->type() == AnalyserEquation::Type::CONSTANT)
800800
|| (dependency->type() == AnalyserEquation::Type::COMPUTED_CONSTANT))
801-
&& isTrackedEquation(dependency, false)) {
802-
methodBody += generateEquationCode(dependency, dummyRemainingAnalyserEquations,
803-
dummyAnalyserEquationsForDependencies,
804-
dummyGeneratedConstantDependencies, false,
805-
GenerateEquationCodeTarget::OBJECTIVE_FUNCTION);
801+
&& isTrackedEquation(dependency, false)
802+
&& seenDependencyEquations.insert(dependency.get()).second) {
803+
collectedDependencies.push_back(dependency);
806804
}
807805
}
808806
}
809807

810-
// c) Generate our NLA system's objective functions.
808+
// c) Sort the collected dependencies according to the order in which they appear in our NLA
809+
// system's dependency graph.
810+
811+
const auto &analyserEquations = mAnalyserModel->analyserEquations();
812+
std::unordered_map<AnalyserEquation *, size_t> equationIndices;
813+
814+
for (size_t j = 0; j < analyserEquations.size(); ++j) {
815+
equationIndices[analyserEquations[j].get()] = j;
816+
}
817+
818+
std::sort(collectedDependencies.begin(), collectedDependencies.end(), [&equationIndices](const AnalyserEquationPtr &ae1, const AnalyserEquationPtr &ae2) {
819+
return equationIndices.at(ae1.get()) < equationIndices.at(ae2.get());
820+
});
821+
822+
// d) Generate code for the collected dependencies.
823+
824+
auto methodBodySize = methodBody.size();
825+
std::unordered_set<AnalyserEquationPtr> dummyRemainingAnalyserEquations(analyserEquations.begin(), analyserEquations.end());
826+
std::unordered_set<AnalyserEquationPtr> dummyAnalyserEquationsForDependencies;
827+
std::unordered_set<AnalyserVariablePtr> dummyGeneratedConstantDependencies;
828+
829+
for (const auto &dependency : collectedDependencies) {
830+
methodBody += generateEquationCode(dependency, dummyRemainingAnalyserEquations,
831+
dummyAnalyserEquationsForDependencies,
832+
dummyGeneratedConstantDependencies, false,
833+
GenerateEquationCodeTarget::OBJECTIVE_FUNCTION);
834+
}
835+
836+
// e) Generate code for the current equation and any of its NLA siblings.
811837

812838
methodBody += (methodBody.size() == methodBodySize) ? "" : "\n";
813839

@@ -1980,7 +2006,8 @@ std::string Generator::GeneratorImpl::generateEquationCode(const AnalyserEquatio
19802006
}
19812007
}
19822008

1983-
if (!isSomeConstant(analyserEquation, includeComputedConstants)) {
2009+
if (!isSomeConstant(analyserEquation, includeComputedConstants)
2010+
|| (target == GenerateEquationCodeTarget::OBJECTIVE_FUNCTION)) {
19842011
for (const auto &dependency : analyserEquation->dependencies()) {
19852012
if (((analyserEquation->type() != AnalyserEquation::Type::NLA)
19862013
&& (dependency->type() == AnalyserEquation::Type::COMPUTED_CONSTANT)

tests/analyser/analysersymengine.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,11 @@ TEST(AnalyserSymEngine, rearrangeUncommonArithmeticEquations)
214214

215215
EXPECT_EQ("a = 2.0-sqrt(w)", libcellml::Generator::equationCode(analyserModel->analyserEquation(0)->ast()));
216216
EXPECT_EQ("b = pow(w, -0.25)", libcellml::Generator::equationCode(analyserModel->analyserEquation(1)->ast()));
217+
#ifdef _WIN32
217218
EXPECT_EQ("c = 3.0*fabs(x-y)", libcellml::Generator::equationCode(analyserModel->analyserEquation(2)->ast()));
219+
#else
220+
EXPECT_EQ("c = 3.0*fabs(-y+x)", libcellml::Generator::equationCode(analyserModel->analyserEquation(2)->ast()));
221+
#endif
218222
EXPECT_EQ("d = w-ceil(0.4+x)", libcellml::Generator::equationCode(analyserModel->analyserEquation(3)->ast()));
219223
EXPECT_EQ("e = 1.0+floor(0.5*z)", libcellml::Generator::equationCode(analyserModel->analyserEquation(4)->ast()));
220224
EXPECT_EQ("f = 0.2*min(x, y)", libcellml::Generator::equationCode(analyserModel->analyserEquation(5)->ast()));

tests/resources/coverage/generator/model.no.tracking_linux.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,8 @@ void objectiveFunction0(double *u, double *f, void *data)
185185
algebraicVariables[1] = u[1];
186186

187187
double my_component_m = 123.0;
188-
double my_component_eqnComputedConstant2 = 3.0;
189188
double my_component_eqnComputedConstant1 = 1.0;
189+
double my_component_eqnComputedConstant2 = 3.0;
190190
double my_component_eqnComputedConstant3 = my_component_eqnComputedConstant1+my_component_eqnComputedConstant2;
191191

192192
f[0] = sin(algebraicVariables[1])+sin(algebraicVariables[0])+states[0]+my_component_eqnComputedConstant3+my_component_m-1.0;

0 commit comments

Comments
 (0)