1 /********************* */
2 /*! \file transcendental_solver.cpp
4 ** Top contributors (to current version):
5 ** Andrew Reynolds, Tim King, Gereon Kremer
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
8 ** in the top-level source directory and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
12 ** \brief Implementation of solver for handling transcendental functions.
15 #include "theory/arith/nl/transcendental/sine_solver.h"
20 #include "expr/node_algorithm.h"
21 #include "expr/node_builder.h"
22 #include "options/arith_options.h"
23 #include "theory/arith/arith_msum.h"
24 #include "theory/arith/arith_utilities.h"
25 #include "theory/rewriter.h"
31 namespace transcendental
{
33 SineSolver::SineSolver(TranscendentalState
* tstate
) : d_data(tstate
) {}
35 SineSolver::~SineSolver() {}
37 void SineSolver::checkInitialRefine()
39 NodeManager
* nm
= NodeManager::currentNM();
41 << "Get initial refinement lemmas for transcendental functions..."
43 for (std::pair
<const Kind
, std::vector
<Node
> >& tfl
: d_data
->d_funcMap
)
45 if (tfl
.first
!= Kind::SINE
)
49 for (const Node
& t
: tfl
.second
)
51 // initial refinements
52 if (d_tf_initial_refine
.find(t
) == d_tf_initial_refine
.end())
54 d_tf_initial_refine
[t
] = true;
56 Node symn
= nm
->mkNode(Kind::SINE
,
57 nm
->mkNode(Kind::MULT
, d_data
->d_neg_one
, t
[0]));
58 symn
= Rewriter::rewrite(symn
);
59 // Can assume it is its own master since phase is split over 0,
60 // hence -pi <= t[0] <= pi implies -pi <= -t[0] <= pi.
61 d_data
->d_trMaster
[symn
] = symn
;
62 d_data
->d_trSlaves
[symn
].insert(symn
);
63 Assert(d_data
->d_trSlaves
.find(t
) != d_data
->d_trSlaves
.end());
64 std::vector
<Node
> children
;
70 nm
->mkNode(Kind::LEQ
, t
, d_data
->d_one
),
71 nm
->mkNode(Kind::GEQ
, t
, d_data
->d_neg_one
)),
73 nm
->mkNode(Kind::PLUS
, t
, symn
).eqNode(d_data
->d_zero
),
75 nm
->mkNode(Kind::EQUAL
,
76 nm
->mkNode(Kind::LT
, t
[0], d_data
->d_zero
),
77 nm
->mkNode(Kind::LT
, t
, d_data
->d_zero
)),
79 nm
->mkNode(Kind::EQUAL
,
80 nm
->mkNode(Kind::GT
, t
[0], d_data
->d_zero
),
81 nm
->mkNode(Kind::GT
, t
, d_data
->d_zero
)));
87 nm
->mkNode(Kind::IMPLIES
,
88 nm
->mkNode(Kind::GT
, t
[0], d_data
->d_zero
),
89 nm
->mkNode(Kind::LT
, t
, t
[0])),
90 nm
->mkNode(Kind::IMPLIES
,
91 nm
->mkNode(Kind::LT
, t
[0], d_data
->d_zero
),
92 nm
->mkNode(Kind::GT
, t
, t
[0]))),
98 nm
->mkNode(Kind::LT
, t
[0], d_data
->d_pi
),
101 nm
->mkNode(Kind::MINUS
, d_data
->d_pi
, t
[0]))),
104 nm
->mkNode(Kind::GT
, t
[0], d_data
->d_pi_neg
),
108 nm
->mkNode(Kind::MINUS
, d_data
->d_pi_neg
, t
[0])))));
111 d_data
->d_im
.addPendingArithLemma(lem
, InferenceId::NL_T_INIT_REFINE
);
118 void SineSolver::checkMonotonic()
120 Trace("nl-ext") << "Get monotonicity lemmas for transcendental functions..."
123 auto it
= d_data
->d_funcMap
.find(Kind::SINE
);
124 if (it
== d_data
->d_funcMap
.end())
126 Trace("nl-ext-exp") << "No sine terms" << std::endl
;
130 // sort arguments of all transcendentals
131 std::vector
<Node
> tf_args
;
132 std::map
<Node
, Node
> tf_arg_to_term
;
134 for (const Node
& tf
: it
->second
)
137 Node mvaa
= d_data
->d_model
.computeAbstractModelValue(a
);
140 Trace("nl-ext-tf-mono-debug") << "...tf term : " << a
<< std::endl
;
141 tf_args
.push_back(a
);
142 tf_arg_to_term
[a
] = tf
;
152 tf_args
.begin(), tf_args
.end(), &d_data
->d_model
, true, false, true);
154 std::vector
<Node
> mpoints
= {d_data
->d_pi
,
159 std::vector
<Node
> mpoints_vals
;
161 // get model values for points
162 for (const auto& point
: mpoints
)
164 mpoints_vals
.emplace_back(d_data
->d_model
.computeAbstractModelValue(point
));
165 Assert(mpoints_vals
.back().isConst());
168 unsigned mdir_index
= 0;
169 int monotonic_dir
= -1;
171 Node targ
, targval
, t
, tval
;
172 for (const auto& sarg
: tf_args
)
174 Node sargval
= d_data
->d_model
.computeAbstractModelValue(sarg
);
175 Assert(sargval
.isConst());
176 Node s
= tf_arg_to_term
[sarg
];
177 Node sval
= d_data
->d_model
.computeAbstractModelValue(s
);
178 Assert(sval
.isConst());
180 // increment to the proper monotonicity region
181 bool increment
= true;
182 while (increment
&& mdir_index
< mpoints
.size())
185 Node pval
= mpoints_vals
[mdir_index
];
186 Assert(pval
.isConst());
187 if (sargval
.getConst
<Rational
>() < pval
.getConst
<Rational
>())
190 Trace("nl-ext-tf-mono")
191 << "...increment at " << sarg
<< " since model value is less than "
192 << mpoints
[mdir_index
] << std::endl
;
197 mono_bounds
[1] = mpoints
[mdir_index
];
199 monotonic_dir
= regionToMonotonicityDir(mdir_index
);
200 if (mdir_index
< mpoints
.size())
202 mono_bounds
[0] = mpoints
[mdir_index
];
206 mono_bounds
[0] = Node::null();
210 // store the concavity region
211 d_data
->d_tf_region
[s
] = mdir_index
;
212 Trace("nl-ext-concavity")
213 << "Transcendental function " << s
<< " is in region #" << mdir_index
;
214 Trace("nl-ext-concavity") << ", arg model value = " << sargval
<< std::endl
;
218 NodeManager
* nm
= NodeManager::currentNM();
220 if (monotonic_dir
== 1
221 && sval
.getConst
<Rational
>() > tval
.getConst
<Rational
>())
223 mono_lem
= nm
->mkNode(Kind::IMPLIES
,
224 nm
->mkNode(Kind::GEQ
, targ
, sarg
),
225 nm
->mkNode(Kind::GEQ
, t
, s
));
227 else if (monotonic_dir
== -1
228 && sval
.getConst
<Rational
>() < tval
.getConst
<Rational
>())
230 mono_lem
= nm
->mkNode(Kind::IMPLIES
,
231 nm
->mkNode(Kind::LEQ
, targ
, sarg
),
232 nm
->mkNode(Kind::LEQ
, t
, s
));
234 if (!mono_lem
.isNull())
236 if (!mono_bounds
[0].isNull())
238 Assert(!mono_bounds
[1].isNull());
239 mono_lem
= nm
->mkNode(
241 nm
->mkNode(Kind::AND
,
242 mkBounded(mono_bounds
[0], targ
, mono_bounds
[1]),
243 mkBounded(mono_bounds
[0], sarg
, mono_bounds
[1])),
246 Trace("nl-ext-tf-mono")
247 << "Monotonicity lemma : " << mono_lem
<< std::endl
;
249 d_data
->d_im
.addPendingArithLemma(mono_lem
,
250 InferenceId::NL_T_MONOTONICITY
);
253 // store the previous values
261 void SineSolver::doTangentLemma(TNode e
, TNode c
, TNode poly_approx
, int region
)
263 NodeManager
* nm
= NodeManager::currentNM();
265 // compute tangent plane
267 // We use zero slope tangent planes, since the concavity of the Taylor
268 // approximation cannot be easily established.
269 Convexity convexity
= regionToConvexity(region
);
270 int mdir
= regionToMonotonicityDir(region
);
271 bool usec
= (mdir
== 1) == (convexity
== Convexity::CONCAVE
);
272 Node lem
= nm
->mkNode(
277 Kind::GEQ
, e
[0], usec
? Node(c
) : regionToLowerBound(region
)),
279 Kind::LEQ
, e
[0], usec
? Node(c
) : regionToUpperBound(region
))),
280 nm
->mkNode(convexity
== Convexity::CONVEX
? Kind::GEQ
: Kind::LEQ
,
284 Trace("nl-ext-sine") << "*** Tangent plane lemma (pre-rewrite): " << lem
286 lem
= Rewriter::rewrite(lem
);
287 Trace("nl-ext-sine") << "*** Tangent plane lemma : " << lem
<< std::endl
;
288 Assert(d_data
->d_model
.computeAbstractModelValue(lem
) == d_data
->d_false
);
290 d_data
->d_im
.addPendingArithLemma(lem
, InferenceId::NL_T_TANGENT
, nullptr, true);
293 void SineSolver::doSecantLemmas(TNode e
,
301 d_data
->doSecantLemmas(getSecantBounds(e
, c
, d
, region
),
306 regionToConvexity(region
),
311 std::pair
<Node
, Node
> SineSolver::getSecantBounds(TNode e
,
316 std::pair
<Node
, Node
> bounds
= d_data
->getClosestSecantPoints(e
, c
, d
);
318 // Check if we already have neighboring secant points
319 if (bounds
.first
.isNull())
321 // lower boundary point for this concavity region
322 bounds
.first
= regionToLowerBound(region
);
324 if (bounds
.second
.isNull())
326 // upper boundary point for this concavity region
327 bounds
.second
= regionToUpperBound(region
);
332 } // namespace transcendental
335 } // namespace theory