48 std::vector<Vnode<Base>*> vnodes_;
49 std::vector<Enode<Base>*> enodes_;
65 int timeOrigVarIndex_;
77 const std::vector<DaeVarInfo>&
varInfo,
78 const std::vector<std::string>&
eqName,
85 timeOrigVarIndex_(-1),
91 CPPADCG_ASSERT_UNKNOWN(
fun_ !=
nullptr);
92 const size_t m =
fun.Range();
93 const size_t n =
fun.Domain();
95 CPPADCG_ASSERT_UNKNOWN(
varInfo_.size() ==
n);
96 for (
size_t j = 0;
j <
n; ++
j) {
101 for (
size_t j = 0;
j <
n; ++
j) {
109 for (
size_t j = 0;
j <
n; ++
j) {
114 enodes_.reserve(1.2 * m + 1);
116 for (
size_t i = 0;
i < m;
i++) {
124 for (
size_t dj = 0;
dj <
n;
dj++) {
126 if (timeOrigVarIndex_ >= 0) {
127 throw CGException(
"More than one time variable (integrated variable) defined");
129 timeOrigVarIndex_ =
dj;
136 for (
size_t tape = 0; tape <
derivOrder.size(); ++tape) {
145 if (timeOrigVarIndex_ < 0) {
148 if (
varInfo_[timeOrigVarIndex_].getName().empty()) {
149 varInfo_[timeOrigVarIndex_].setName(
"t");
161 if (
var.getName().empty()) {
169 }
else if (order == 0) {
172 if (
var.getName().empty()) {
179 }
else if (order > 0) {
182 if (
var.getName().empty()) {
206 for (
size_t j = 0;
j < vnodes_.size();
j++) {
209 const std::string& name =
varInfo_[tapeIndex].getName();
211 CPPADCG_ASSERT_UNKNOWN(
varInfo_[tapeIndex].isFunctionOfIntegrated());
218 vnodes_[
j] =
new Vnode<Base>(
j, tapeIndex, derivativeOf, name);
225 for (
size_t i = 0;
i < m;
i++) {
226 for (
size_t p = 0;
p <
n;
p++) {
229 enodes_[
i]->addVariable(vnodes_[
j]);
236 for (
size_t j = 0;
j < vnodes_.size();
j++) {
238 if (!
jj->isParameter() &&
239 (
jj->antiDerivative() !=
nullptr ||
240 jj->derivative() ==
nullptr)
247 throw CGException(
"The system is not well determined. "
248 "The of number of equations (", enodes_.size(),
")"
249 " does not match the number of unknown variables "
259 for (
size_t i = 0;
i < enodes_.size();
i++)
262 for (
size_t j = 0;
j < vnodes_.size();
j++)
267 inline std::vector<Vnode<Base>*>& variables() {
271 inline const std::vector<Vnode<Base>*>& variables()
const {
275 inline std::vector<Enode<Base>*>& equations() {
279 inline const std::vector<Enode<Base>*>& equations()
const {
283 const std::vector<DaeVarInfo>& getOriginalVariableInfo()
const {
287 inline size_t getOrigTimeDependentCount()
const {
315 size_t origM = this->fun_->Range();
316 if (
origM == enodes_.size()) {
321 if (
jj.getDerivative() < 0 && !
jj.isIntegratedVariable() &&
jj.isFunctionOfIntegrated()) {
334 for (
size_t i =
origM;
i < enodes_.size();
i++) {
337 if (
ii->derivative() ==
nullptr) {
339 while (
eq->derivativeOf() !=
nullptr) {
340 eq =
eq->derivativeOf();
351 inline void printResultInfo(
const std::string&
method) {
352 logger_.log() <<
"\n" <<
method <<
" DAE differentiation/structural index reduction:\n\n"
353 " Equations count: " << enodes_.size() <<
"\n";
355 logger_.log() <<
" " <<
ii->index() <<
" - " << *
ii <<
"\n";
358 logger_.log() <<
"\n Variable count: " << vnodes_.size() <<
"\n";
361 logger_.log() <<
" " <<
jj->index() <<
" - " << *
jj;
362 if (
jj->assignmentEquation() !=
nullptr) {
363 logger_.log() <<
" assigned to " << *
jj->assignmentEquation() <<
"\n";
364 }
else if (
jj->isParameter()) {
365 logger_.log() <<
" is a parameter (time independent)\n";
367 logger_.log() <<
" NOT assigned to any equation\n";
371 logger_.log() <<
"\n Degrees of freedom: " << vnodes_.size() - enodes_.size() << std::endl;
374 inline void uncolorAll() {
379 for (Enode<Base>*
i : enodes_) {
385 if (
j.derivative() !=
nullptr)
386 return j.derivative();
393 vnodes_.push_back(
jDiff);
395 if (logger_.getVerbosity() >= Verbosity::High)
396 logger_.log() <<
"Created " << *
jDiff <<
"\n";
401 inline Enode<Base>* createDerivate(Enode<Base>&
i,
403 if (
i.derivative() !=
nullptr)
404 return i.derivative();
406 Enode<Base>*
iDiff =
new Enode<Base> (enodes_.size(), &
i);
407 enodes_.push_back(
iDiff);
412 if (logger_.getVerbosity() >= Verbosity::High)
413 logger_.log() <<
"Created " << *
iDiff <<
"\n";
428 CPPADCG_ASSERT_UNKNOWN(enodes_[
i.index()] == &
i);
429 CPPADCG_ASSERT_UNKNOWN(
i.derivative() ==
nullptr);
433 auto&
eqs =
j->equations();
434 auto it = std::find(
eqs.begin(),
eqs.end(), &
i);
435 CPPADCG_ASSERT_UNKNOWN(
it !=
eqs.end());
441 while(
j->equations().empty()) {
442 CPPADCG_ASSERT_UNKNOWN(vnodes_[
j->index()] ==
j);
444 if (
j->derivative() ==
nullptr) {
445 vnodes_.erase(vnodes_.cbegin() +
j->index());
448 for (
size_t jj =
j->index();
jj < vnodes_.size(); ++
jj) {
449 vnodes_[
jj]->setTapeIndex(vnodes_[
jj]->tapeIndex() - 1);
450 vnodes_[
jj]->setIndex(vnodes_[
jj]->index() - 1);
453 auto*
jOrig =
j->antiDerivative();
454 CPPADCG_ASSERT_UNKNOWN(
jOrig !=
nullptr);
455 jOrig->setDerivative(
nullptr);
465 for (
size_t ii =
i.index() + 1;
ii < enodes_.size(); ++
ii) {
466 CPPADCG_ASSERT_UNKNOWN(enodes_[
ii]->index() > 0);
467 CPPADCG_ASSERT_UNKNOWN(enodes_[
ii]->index() ==
ii);
468 enodes_[
ii]->setIndex(enodes_[
ii]->index() - 1);
471 if(
i.derivativeOf() !=
nullptr) {
472 i.derivativeOf()->setDerivative(
nullptr);
475 auto it = std::find(enodes_.begin(), enodes_.end(), &
i);
476 CPPADCG_ASSERT_UNKNOWN(
it != enodes_.end());
506 if (
jj->derivative() !=
nullptr) {
507 iDiff.addVariable(
jj->derivative());
508 }
else if(!
jj->isParameter()) {
509 iDiff.addVariable(createDerivate(*
jj));
519 const std::vector<Base>& x) {
528 size_t origM = this->fun_->Range();
529 for (
size_t i = 0;
i <
origM;
i++) {
530 if (enodes_[
i]->derivative() !=
nullptr) {
531 CPPADCG_ASSERT_UNKNOWN(enodes_[
i]->derivativeOf() ==
nullptr);
532 newEqs.push_back(enodes_[
i]->derivative());
536 while (
newEqs.size() > 0) {
540 for (
size_t i = 0;
i <
eqs.size();
i++) {
541 if (
eqs[
i]->derivative() !=
nullptr) {
565 CPPADCG_ASSERT_UNKNOWN(
jj->antiDerivative() !=
nullptr);
566 size_t antiDeriv =
jj->antiDerivative()->tapeIndex();
575 if (
jj->derivative() !=
nullptr) {
576 newVar.setDerivative(
jj->derivative()->tapeIndex());
581 for (
size_t j = 0;
j < vnodes_.size();
j++) {
583 if (
jj->assignmentEquation() !=
nullptr) {
589 for (
size_t i = 0;
i < enodes_.size();
i++) {
591 int derivativeOf =
ii->derivativeOf() !=
nullptr ?
ii->derivativeOf()->index() : -1;
612 if (timeOrigVarIndex_ >= 0) {
621 for (
size_t j = 0;
j < x.size();
j++) {
633 depNew.resize(enodes_.size());
637 }
catch (
const std::exception&
ex) {
641 if (logger_.getVerbosity() >= Verbosity::High) {
642 logger_.log() <<
"Original model:\n";
682 }
else if (timeOrigVarIndex_ < 0) {
690 for (
size_t j = 0;
j < x.size();
j++) {
709 }
catch (
const std::exception&
ex) {
713 if (logger_.getVerbosity() >= Verbosity::High) {
714 logger_.log() << equations.size() <<
" new equations:\n";
729 std::vector<CGBase>
u(m, CGBase(0));
731 std::vector<CGBase> v;
734 }
catch (
const std::exception&
ex) {
735 throw CGException(
"Failed to determine model Jacobian (forward mode): ",
ex.what());
738 for (
size_t e = 0;
e < equations.size();
e++) {
739 dep[equations[
e]->index()] = v[equations[
e]->derivativeOf()->index()];
744 const std::vector<Enode<Base>*>& equations,
745 std::vector<CG<Base> >&
dep,
749 std::vector<CGBase>
u(m);
750 std::vector<CGBase> v(
n);
752 for (
size_t e = 0;
e < equations.size();
e++) {
753 size_t i = equations[
e]->derivativeOf()->index();
755 dep[equations[
e]->index()] = 0;
763 }
catch (
const std::exception&
ex) {
764 throw CGException(
"Failed to determine model Jacobian (reverse mode): ",
ex.what());
800 if (
jj.getDerivative() >= 0) {
817 inline void printModel(std::ostream&
out,
829 const std::vector<DaeVarInfo>&
varInfo,
830 const std::vector<DaeEquationInfo>&
eqInfo)
const {
836 for (
size_t i = 0;
i <
eqInfo.size(); ++
i) {
838 CPPADCG_ASSERT_UNKNOWN(
eqInfo[
i].getAssignedVarIndex() >= 0);
841 eqnames[
i] =
"res[" + std::to_string(
i) +
"]";
858 const std::vector<std::string>&
depNames = std::vector<std::string>())
const {
877 std::ostringstream
code;
879 out <<
"\n" <<
code.str() << std::endl;
882 inline void printDot(std::ostream&
out)
const {
883 out <<
"digraph {\n";
884 out <<
" overlap=false\n";
885 out <<
" rankdir=LR\n";
886 out <<
" node [style=filled, fillcolor=\"#bdcef5\", color=\"#17128e\"]\n";
887 out <<
" edge [splines=false, dir=none]\n";
890 out <<
" subgraph variables {\n";
891 out <<
" rank=min\n";
893 if(!
j->isDeleted()) {
894 out <<
" v" <<
j->index() <<
" [label=\"" <<
j->name() <<
"\"";
896 out <<
", color=\"#17c68e\"";
903 out <<
" subgraph equations {\n";
904 out <<
" rank=max\n";
905 for (
const Enode<Base>*
i : enodes_) {
906 out <<
" e" <<
i->index() <<
" [label=\"" <<
i->name() <<
"\"";
908 out <<
", color=\"#17c68e\"";
914 out <<
" subgraph eq_derivatives {\n";
915 out <<
" edge[dir=forward, color=grey]\n";
916 for (
const Enode<Base>*
i : enodes_) {
917 if (
i->derivative() !=
nullptr &&
i->derivativeOf() ==
nullptr) {
918 while (
i->derivative() !=
nullptr) {
919 out <<
" e" <<
i->index() <<
":e -> e" <<
i->derivative()->index() <<
":e\n";
927 out <<
" subgraph var_derivatives {\n";
928 out <<
" edge[dir=forward, color=grey]\n";
930 if (!
j->isDeleted() &&
j->derivative() !=
nullptr && (
j->antiDerivative() ==
nullptr ||
j->antiDerivative()->isDeleted())) {
931 if (!
j->derivative()->isDeleted()) {
932 while (
j->derivative() !=
nullptr && !
j->derivative()->isDeleted()) {
933 out <<
" v" <<
j->index() <<
":w -> v" <<
j->derivative()->index() <<
":w\n";
942 for (
const Enode<Base>*
i : enodes_) {
945 if (!
j->isDeleted() &&
j->assignmentEquation() !=
i) {
950 out <<
"e" <<
i->index() <<
" -> v" <<
j->index() <<
" ";
957 out <<
" subgraph assigned {\n";
958 out <<
" edge[color=blue,penwidth=3.0,style=dashed]\n";
959 for (
const Enode<Base>*
i : enodes_) {
963 if (!
j->isDeleted() &&
j->assignmentEquation() ==
i) {
968 out <<
"e" <<
i->index() <<
" -> v" <<
j->index() <<
" ";
980 template<
class VectorCGB>
987 std::ostream
out(&
b);
995 static inline std::vector<int> determineVariableDiffOrder(
const std::vector<DaeVarInfo>&
varInfo) {
999 for (
size_t dj = 0;
dj <
n;
dj++) {
1007 static inline int determineVariableDiffOrder(
const std::vector<DaeVarInfo>&
varInfo,
size_t index,
size_t&
j0) {
1010 if (
varInfo[index].isFunctionOfIntegrated()) {
1012 while (
varInfo[
j0].getAntiDerivative() >= 0) {
1013 CPPADCG_ASSERT_UNKNOWN(
j0 <
varInfo.size());
1014 CPPADCG_ASSERT_UNKNOWN(
varInfo[
j0].isFunctionOfIntegrated());
1024 inline void determineVariableOrder(DaeVarInfo&
var) {
1025 if (
var.getAntiDerivative() >= 0) {
1027 if (
antiD.getOriginalAntiDerivative() < 0) {
1028 determineVariableOrder(
antiD);
1030 var.setOrder(
antiD.getOrder() + 1);
1031 var.setOriginalAntiDerivative(
var.getOrder() == 1 ?
antiD.getOriginalIndex() :
antiD.getOriginalAntiDerivative());