CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
arithmetic.hpp
1#ifndef CPPAD_CG_ARITHMETIC_INCLUDED
2#define CPPAD_CG_ARITHMETIC_INCLUDED
3/* --------------------------------------------------------------------------
4 * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5 * Copyright (C) 2012 Ciengis
6 *
7 * CppADCodeGen is distributed under multiple licenses:
8 *
9 * - Eclipse Public License Version 1.0 (EPL1), and
10 * - GNU General Public License Version 3 (GPL3).
11 *
12 * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
13 * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
14 * ----------------------------------------------------------------------------
15 * Author: Joao Leal
16 */
17
18namespace CppAD {
19namespace cg {
20
21template<class Base>
22CodeHandler<Base>* getHandler(const CG<Base>& left,
23 const CG<Base>& right) {
24
25 CPPADCG_ASSERT_UNKNOWN(!left.isParameter() || !right.isParameter());
26
27 CodeHandler<Base>* lh = left.getCodeHandler();
28 CodeHandler<Base>* rh = right.getCodeHandler();
29
30 if (lh == nullptr) {
31 return rh;
32 } else if (rh == nullptr) {
33 return lh;
34 } else {
35 if (lh != rh) {
36 throw CGException("Attempting to use several source code generation handlers in the same source code generation");
37 }
38 return lh;
39 }
40}
41
42template<class Base>
43inline CG<Base> operator+(const CG<Base>& left, const CG<Base>& right) {
44 if (left.isParameter() && right.isParameter()) {
45 return CG<Base> (left.getValue() + right.getValue());
46
47 } else {
48 if (left.isParameter()) {
49 if (left.isIdenticalZero()) {
50 return right;
51 }
52 } else if (right.isParameter()) {
53 if (right.isIdenticalZero()) {
54 return left;
55 }
56 }
57
58 CodeHandler<Base>* handler = getHandler(left, right);
59
60 CG<Base> result(*handler->makeNode(CGOpCode::Add,{left.argument(), right.argument()}));
61 if (left.isValueDefined() && right.isValueDefined()) {
62 result.setValue(left.getValue() + right.getValue());
63 }
64 return result;
65 }
66}
67
68template<class Base>
69inline CG<Base> operator-(const CG<Base>& left, const CG<Base>& right) {
70 if (left.isParameter() && right.isParameter()) {
71 return CG<Base> (left.getValue() - right.getValue());
72
73 } else {
74 if (right.isParameter()) {
75 if (right.isIdenticalZero()) {
76 return left;
77 }
78 }
79
80 CodeHandler<Base>* handler = getHandler(left, right);
81
82 CG<Base> result(*handler->makeNode(CGOpCode::Sub,{left.argument(), right.argument()}));
83 if (left.isValueDefined() && right.isValueDefined()) {
84 result.setValue(left.getValue() - right.getValue());
85 }
86 return result;
87 }
88}
89
90template<class Base>
91inline CG<Base> operator*(const CG<Base>& left, const CG<Base>& right) {
92 if (left.isParameter() && right.isParameter()) {
93 return CG<Base> (left.getValue() * right.getValue());
94
95 } else {
96 if (left.isParameter()) {
97 if (left.isIdenticalZero()) {
98 return CG<Base> (Base(0.0)); // does not consider the possibility of right being infinity
99 } else if (left.isIdenticalOne()) {
100 return right;
101 }
102 } else if (right.isParameter()) {
103 if (right.isIdenticalZero()) {
104 return CG<Base> (Base(0.0)); // does not consider the possibility of left being infinity
105 } else if (right.isIdenticalOne()) {
106 return left;
107 }
108 }
109
110 CodeHandler<Base>* handler = getHandler(left, right);
111
112 CG<Base> result(*handler->makeNode(CGOpCode::Mul,{left.argument(), right.argument()}));
113 if (left.isValueDefined() && right.isValueDefined()) {
114 result.setValue(left.getValue() * right.getValue());
115 }
116 return result;
117 }
118}
119
120template<class Base>
121inline CG<Base> operator/(const CG<Base>& left, const CG<Base>& right) {
122 if (left.isParameter() && right.isParameter()) {
123 return CG<Base> (left.getValue() / right.getValue());
124
125 } else {
126 if (left.isParameter()) {
127 if (left.isIdenticalZero()) {
128 return CG<Base> (Base(0.0)); // does not consider the possibility of right being infinity or zero
129 }
130 } else if (right.isParameter()) {
131 if (right.isIdenticalOne()) {
132 return left;
133 }
134 } else if (left.getOperationNode() == right.getOperationNode()) {
135 return CG<Base>(Base(1.0)); // does not consider the possibility of left/right being infinity or zero
136 }
137
138 CodeHandler<Base>* handler = getHandler(left, right);
139
140 CG<Base> result(*handler->makeNode(CGOpCode::Div,{left.argument(), right.argument()}));
141 if (left.isValueDefined() && right.isValueDefined()) {
142 result.setValue(left.getValue() / right.getValue());
143 }
144 return result;
145 }
146}
147
148template<class Base>
149inline CG<Base> operator+(const Base& left, const CG<Base>& right) {
150 return CG<Base>(left) + right;
151}
152
153template<class Base>
154inline CG<Base> operator+(const CG<Base>& left, const Base& right) {
155 return left + CG<Base>(right);
156}
157
158template<class Base>
159inline CG<Base> operator-(const Base& left, const CG<Base>& right) {
160 return CG<Base>(left) - right;
161}
162
163template<class Base>
164inline CG<Base> operator-(const CG<Base>& left, const Base& right) {
165 return left - CG<Base>(right);
166}
167
168template<class Base>
169inline CG<Base> operator/(const Base& left, const CG<Base>& right) {
170 return CG<Base>(left) / right;
171}
172
173template<class Base>
174inline CG<Base> operator/(const CG<Base>& left, const Base& right) {
175 return left / CG<Base>(right);
176}
177
178template<class Base>
179inline CG<Base> operator*(const Base& left, const CG<Base>& right) {
180 return CG<Base>(left) * right;
181}
182
183template<class Base>
184inline CG<Base> operator*(const CG<Base>& left, const Base& right) {
185 return left * CG<Base>(right);
186}
187
188/*******************************************************************************
189 * Operations with other types
190 ******************************************************************************/
191
192template<class Base, class T>
193inline
194typename std::enable_if<std::is_constructible<Base, const T&>::value, CG<Base> >::type
195operator+(const T& left, const CG<Base>& right) {
196 return CG<Base>(Base(left)) + right;
197}
198
199template<class Base, class T>
200inline
201typename std::enable_if<std::is_constructible<Base, const T&>::value, CG<Base> >::type
202operator+(const CG<Base>& left, const T& right) {
203 return left + CG<Base>(Base(right));
204}
205
206template<class Base, class T>
207inline
208typename std::enable_if<std::is_constructible<Base, const T&>::value, CG<Base> >::type
209operator-(const T& left, const CG<Base>& right) {
210 return CG<Base>(Base(left)) - right;
211}
212
213template<class Base, class T>
214inline
215typename std::enable_if<std::is_constructible<Base, const T&>::value, CG<Base> >::type
216operator-(const CG<Base>& left, const T& right) {
217 return left - CG<Base>(Base(right));
218}
219
220template<class Base, class T>
221inline
222typename std::enable_if<std::is_constructible<Base, const T&>::value, CG<Base> >::type
223operator/(const T& left, const CG<Base>& right) {
224 return CG<Base>(Base(left)) / right;
225}
226
227template<class Base, class T>
228inline
229typename std::enable_if<std::is_constructible<Base, const T&>::value, CG<Base> >::type
230operator/(const CG<Base>& left, const T& right) {
231 return left / CG<Base>(Base(right));
232}
233
234template<class Base, class T>
235inline
236typename std::enable_if<std::is_constructible<Base, const T&>::value, CG<Base> >::type
237operator*(const T& left, const CG<Base>& right) {
238 return CG<Base>(Base(left)) * right;
239}
240
241template<class Base, class T>
242inline
243typename std::enable_if<std::is_constructible<Base, const T&>::value, CG<Base> >::type
244operator*(const CG<Base>& left, const T& right) {
245 return left * CG<Base>(Base(right));
246}
247
248} // END cg namespace
249} // END CppAD namespace
250
251#endif
252