@@ -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 )
0 commit comments