1 # ifndef CPPAD_CORE_SUB_HPP
2 # define CPPAD_CORE_SUB_HPP
3 /* --------------------------------------------------------------------------
4 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
5 
6 CppAD is distributed under the terms of the
7              Eclipse Public License Version 2.0.
8 
9 This Source Code may also be made available under the following
10 Secondary License when the conditions for such availability set forth
11 in the Eclipse Public License, Version 2.0 are satisfied:
12       GNU General Public License, Version 2.0 or later.
13 ---------------------------------------------------------------------------- */
14 
15 //  BEGIN CppAD namespace
16 namespace CppAD {
17 
18 template <class Base>
operator -(const AD<Base> & left,const AD<Base> & right)19 AD<Base> operator - (const AD<Base> &left , const AD<Base> &right)
20 {
21     // compute the Base part
22     AD<Base> result;
23     result.value_  = left.value_ - right.value_;
24     CPPAD_ASSERT_UNKNOWN( Parameter(result) );
25 
26     // check if there is a recording in progress
27     local::ADTape<Base>* tape = AD<Base>::tape_ptr();
28     if( tape == nullptr )
29         return result;
30     tape_id_t tape_id = tape->id_;
31     // tape_id cannot match the default value for tape_id_; i.e., 0
32     CPPAD_ASSERT_UNKNOWN( tape_id > 0 );
33 
34     // check if left and right tapes match
35     bool match_left  = left.tape_id_  == tape_id;
36     bool match_right = right.tape_id_ == tape_id;
37 
38     // check if left and right are dynamic parameters
39     bool dyn_left  = match_left  & (left.ad_type_ == dynamic_enum);
40     bool dyn_right = match_right & (right.ad_type_ == dynamic_enum);
41 
42     // check if left and right are variables
43     bool var_left  = match_left  & (left.ad_type_ != dynamic_enum);
44     bool var_right = match_right & (right.ad_type_ != dynamic_enum);
45 
46 
47     CPPAD_ASSERT_KNOWN(
48         left.tape_id_ == right.tape_id_ || ! match_left || ! match_right ,
49         "Subtract: AD variables or dynamic parameters on different threads."
50     );
51     if( var_left )
52     {   if( var_right )
53         {   // result = variable - variable
54             CPPAD_ASSERT_UNKNOWN( local::NumRes(local::SubvvOp) == 1 );
55             CPPAD_ASSERT_UNKNOWN( local::NumArg(local::SubvvOp) == 2 );
56 
57             // put operand addresses in tape
58             tape->Rec_.PutArg(left.taddr_, right.taddr_);
59             // put operator in the tape
60             result.taddr_ = tape->Rec_.PutOp(local::SubvvOp);
61             // make result a variable
62             result.tape_id_ = tape_id;
63             result.ad_type_ = variable_enum;
64         }
65         else if( (! dyn_right) & IdenticalZero(right.value_) )
66         {   // result = variable - 0
67             result.make_variable(left.tape_id_, left.taddr_);
68         }
69         else
70         {   // result = variable - parameter
71             CPPAD_ASSERT_UNKNOWN( local::NumRes(local::SubvpOp) == 1 );
72             CPPAD_ASSERT_UNKNOWN( local::NumArg(local::SubvpOp) == 2 );
73 
74             // put operand addresses in tape
75             addr_t p = right.taddr_;
76             if( ! dyn_right )
77                 p = tape->Rec_.put_con_par(right.value_);
78             tape->Rec_.PutArg(left.taddr_, p);
79             // put operator in the tape
80             result.taddr_ = tape->Rec_.PutOp(local::SubvpOp);
81             // make result a variable
82             result.tape_id_ = tape_id;
83             result.ad_type_ = variable_enum;
84         }
85     }
86     else if( var_right )
87     {   // result = parameter - variable
88         CPPAD_ASSERT_UNKNOWN( local::NumRes(local::SubpvOp) == 1 );
89         CPPAD_ASSERT_UNKNOWN( local::NumArg(local::SubpvOp) == 2 );
90 
91         // put operand addresses in tape
92         addr_t p = left.taddr_;
93         if( ! dyn_left )
94             p = tape->Rec_.put_con_par(left.value_);
95         tape->Rec_.PutArg(p, right.taddr_);
96         // put operator in the tape
97         result.taddr_ = tape->Rec_.PutOp(local::SubpvOp);
98         // make result a variable
99         result.tape_id_ = tape_id;
100         result.ad_type_ = variable_enum;
101     }
102     else if( dyn_left | dyn_right )
103     {   addr_t arg0 = left.taddr_;
104         addr_t arg1 = right.taddr_;
105         if( ! dyn_left )
106             arg0 = tape->Rec_.put_con_par(left.value_);
107         if( ! dyn_right )
108             arg1 = tape->Rec_.put_con_par(right.value_);
109         //
110         // parameters with a dynamic parameter result
111         result.taddr_   = tape->Rec_.put_dyn_par(
112             result.value_, local::sub_dyn,   arg0, arg1
113         );
114         result.tape_id_ = tape_id;
115         result.ad_type_ = dynamic_enum;
116     }
117     return result;
118 }
119 
120 // convert other cases into the case above
121 CPPAD_FOLD_AD_VALUED_BINARY_OPERATOR(-)
122 
123 } // END CppAD namespace
124 
125 # endif
126