1 #ifndef CPPAD_CG_COLLECT_VARIABLE_INCLUDED 2 #define CPPAD_CG_COLLECT_VARIABLE_INCLUDED 18 #include <cppad/cg/evaluator/evaluator_solve.hpp> 19 #include <cppad/cg/lang/dot/dot.hpp> 26 const SourceCodePath& path1,
27 const SourceCodePath& path2,
29 CPPADCG_ASSERT_UNKNOWN(lastCommon >= 0);
30 CPPADCG_ASSERT_UNKNOWN(path1.size() > lastCommon);
31 CPPADCG_ASSERT_UNKNOWN(path2.size() > lastCommon);
37 for(
size_t i = 0;i < lastCommon; ++i) {
39 CPPADCG_ASSERT_UNKNOWN(path2[i] == path1[i]);
46 SourceCodePath leftPath(path1.begin() + lastCommon, path1.end());
47 SourceCodePath rightPath(path2.begin() + lastCommon, path2.end());
49 CG<Base> subExpression = collectVariableAddSub(leftPath, rightPath);
57 std::vector<CG<Base>*> replace(lastCommon + 1,
nullptr);
59 std::vector<const std::vector<CG<Base>*>*> replaceOnPath{&replace};
61 SourceCodePath initPath(path1.begin(), path1.begin() + lastCommon + 1);
62 std::vector<const SourceCodePath*> initPaths{&initPath};
68 std::vector<CG<Base>> indep(this->_independentVariables.size());
69 for (
size_t i = 0; i < indep.size(); ++i)
70 indep[i] =
CG<Base>(*this->_independentVariables[i]);
75 size_t bifurcations = 0;
76 BidirGraph<Base> graphToCommon = findPathGraph(expression, *path1[lastCommon].node, bifurcations);
77 std::map<const PathNodeEdges<Base>*,
CG<Base>> replacementNodes;
78 replacementNodes[&graphToCommon[*path1[lastCommon].node]] = subExpression;
81 e.
evaluate(indep.data(), indep.size(),
82 &expression2, &expressionOrig, 1);
101 const SourceCodePath& pathRight) {
105 if(pathLeft[0].node ==
nullptr) {
107 }
else if(pathLeft[0].node != pathRight[0].node) {
108 throw CGException(
"The first element in each path must be the same.");
111 auto& expression = *pathLeft[0].node;
113 auto initCommonOp = expression.getOperationType();
114 if (initCommonOp != CGOpCode::Add &&
115 initCommonOp != CGOpCode::Sub) {
116 throw CGException(
"Invalid path! It must start with either an addition or subtraction.");
119 if(pathLeft.back().node ==
nullptr || pathRight.back().node ==
nullptr)
120 throw CGException(
"Invalid path! It must end with a non null node.");
122 if(pathLeft.back().node != pathRight.back().node)
123 throw CGException(
"Invalid paths! They must end with the same node.");
130 isCollectableVariableAddSub(pathLeft, pathRight,
true);
136 std::array<std::vector<CG<Base>*>, 2> replace;
138 std::vector<const SourceCodePath*> paths{&pathLeft, &pathRight};
142 for (
size_t j = 0; j < paths.size(); ++j) {
143 const auto& p = *paths[j];
144 replace[j] = std::vector<CG<Base>*>(p.size(),
nullptr);
145 replace[j].back() = &zero;
151 if (initCommonOp == CGOpCode::Sub && j == 1) {
155 for (
size_t i = 1; i < p.size() - 1; ++i) {
156 const auto* node = p[i].node;
157 if (node ==
nullptr) {
158 throw CGException(
"Failed to combine multiple occurrences of a variable into one expression");
161 auto op = node->getOperationType();
163 if (op == CGOpCode::Add) {
166 }
else if (op == CGOpCode::Sub) {
167 if (p[i - 1].argIndex == 1)
172 }
else if (op == CGOpCode::UnMinus) {
175 }
else if (op == CGOpCode::Mul) {
176 CPPADCG_ASSERT_UNKNOWN(p[i].argIndex == 0 || p[i].argIndex == 1);
177 const auto& pArgs = node->getArguments();
178 c *= (p[i].argIndex == 0) ? pArgs[1] : pArgs[0];
180 }
else if (op == CGOpCode::Div) {
181 CPPADCG_ASSERT_UNKNOWN(p[i].argIndex == 0);
182 c /=
CG<Base>(node->getArguments()[1]);
184 }
else if (op == CGOpCode::Alias) {
189 CPPADCG_ASSERT_UNKNOWN(
false);
197 for (
size_t i1 = p.size() - 1; i1 > 0; --i1) {
199 if (p[i].node->getOperationType() == CGOpCode::Mul ||
200 p[i].node->getOperationType() == CGOpCode::UnMinus ||
201 p[i].node->getOperationType() == CGOpCode::Div ||
202 p[i].node->getOperationType() == CGOpCode::Alias) {
203 replace[j][i] = &zero;
210 const auto& replaceLeft = replace[0];
211 const auto& replaceRight = replace[1];
212 bool keepCommon = replaceLeft[1] ==
nullptr || replaceRight[1] ==
nullptr;
219 std::vector<const std::vector<CG<Base>*>*> replaceOnPath{&replaceLeft, &replaceRight};
222 std::vector<CG<Base>> indep(this->_independentVariables.size());
223 for (
size_t i = 0; i < indep.size(); ++i)
224 indep[i] =
CG<Base>(*this->_independentVariables[i]);
226 CG<Base> expressionOrig(expression);
228 e.
evaluate(indep.data(), indep.size(),
229 &expression2, &expressionOrig, 1);
236 return cSum * v + expression2;
241 const SourceCodePath& pathRight,
246 std::vector<const SourceCodePath*> paths{&pathLeft, &pathRight};
247 for (
const SourceCodePath* p: paths) {
248 for (
size_t i = 1; i < p->size() - 1; ++i) {
249 const auto* node = (*p)[i].node;
251 if (node ==
nullptr) {
253 throw CGException(
"Failed to combine multiple occurrences of a variable into one expression");
257 auto op = node->getOperationType();
258 if (op != CGOpCode::Add &&
259 op != CGOpCode::Sub &&
260 op != CGOpCode::Mul &&
261 op != CGOpCode::UnMinus &&
262 op != CGOpCode::Alias) {
264 if (op == CGOpCode::Div) {
265 if ((*p)[i].argIndex != 0) {
267 throw CGException(
"Unable to combine operations which are present in denominators (not implemented yet).");
275 throw CGException(
"Failed to combine multiple occurrences of a variable into one expression." 276 " Unable to combine operations diverging at a '", op,
"' operation.");
std::vector< CG< Scalar > > evaluate(ArrayView< const CG< Scalar > > indepNew, ArrayView< const CG< Scalar > > depOld)
bool isCollectableVariableAddSub(const SourceCodePath &pathLeft, const SourceCodePath &pathRight, bool throwEx)
CGB collectVariableAddSub(const SourceCodePath &pathLeft, const SourceCodePath &pathRight)
CGB collectVariable(Node &expression, const SourceCodePath &path1, const SourceCodePath &path2, size_t bifPos)