Analysis: add classes to manage constraints on symbolic dimensions
[scilab.git] / scilab / modules / ast / src / cpp / analysis / InferenceConstraints.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2015 - Scilab Enterprises - Calixte DENIZET
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 #include "gvn/InferenceConstraint.hxx"
14
15 namespace analysis
16 {
17 InferenceConstraint::Result SameDimsConstraint::check(const std::vector<GVN::Value *> & values) const
18 {
19     const GVN::Value & R1 = *values[0];
20     const GVN::Value & C1 = *values[1];
21     const GVN::Value & R2 = *values[2];
22     const GVN::Value & C2 = *values[3];
23
24     if (R1.value == R2.value)
25     {
26         if (C1.value == C2.value)
27         {
28             return Result::TRUE;
29         }
30
31         MultivariatePolynomial mp = *C1.poly - *C2.poly;
32         if (mp.constant != 0 && mp.isCoeffPositive(false))
33         {
34             return Result::FALSE;
35         }
36     }
37     else
38     {
39         MultivariatePolynomial mp = *R1.poly - *R2.poly;
40         if (mp.constant > 0 && mp.isCoeffPositive(false))
41         {
42             return Result::FALSE;
43         }
44     }
45     return Result::DUNNO;
46 }
47
48 MPolyConstraintSet SameDimsConstraint::getMPConstraints(const std::vector<GVN::Value *> & values) const
49 {
50     MPolyConstraintSet set(2);
51     const GVN::Value & R1 = *values[0];
52     const GVN::Value & C1 = *values[1];
53     const GVN::Value & R2 = *values[2];
54     const GVN::Value & C2 = *values[3];
55
56     set.add(*R1.poly - *R2.poly, MPolyConstraint::Kind::EQ0);
57     set.add(*C1.poly - *C2.poly, MPolyConstraint::Kind::EQ0);
58
59     return set;
60 }
61
62 void SameDimsConstraint::applyConstraints(const std::vector<GVN::Value *> & values) const
63 {
64     GVN::Value & R1 = *values[0];
65     GVN::Value & C1 = *values[1];
66     GVN::Value & R2 = *values[2];
67     GVN::Value & C2 = *values[3];
68
69     applyEquality(R1, R2);
70     applyEquality(C1, C2);
71 }
72
73 InferenceConstraint::Result EqualConstraint::check(const std::vector<GVN::Value *> & values) const
74 {
75     const GVN::Value & x = *values[0];
76     const GVN::Value & y = *values[1];
77
78     if (x.value == y.value)
79     {
80         return Result::TRUE;
81     }
82     else
83     {
84         MultivariatePolynomial mp = *x.poly - *y.poly;
85         if (mp.constant > 0 && mp.isCoeffPositive(false))
86         {
87             return Result::FALSE;
88         }
89     }
90     return Result::DUNNO;
91 }
92
93 void EqualConstraint::applyConstraints(const std::vector<GVN::Value *> & values) const
94 {
95     GVN::Value & x = *values[0];
96     GVN::Value & y = *values[1];
97
98     applyEquality(x, y);
99 }
100
101 MPolyConstraintSet EqualConstraint::getMPConstraints(const std::vector<GVN::Value *> & values) const
102 {
103     MPolyConstraintSet set(1);
104     const GVN::Value & x = *values[0];
105     const GVN::Value & y = *values[1];
106
107     set.add(*x.poly - *y.poly, MPolyConstraint::Kind::EQ0);
108
109     return set;
110 }
111
112 InferenceConstraint::Result MPolyConstraint::check(const std::vector<GVN::Value *> & values) const
113 {
114     MultivariatePolynomial mp = poly.eval(InferenceConstraint::getArgs(values));
115     //std::wcerr << "MPolyConstraint=" << poly << "::" << mp << std::endl;
116     switch (kind)
117     {
118         case EQ0 :
119         {
120             if (mp.isConstant(0))
121             {
122                 // for all X, P(X) == 0
123                 return Result::TRUE;
124             }
125             else if (mp.constant != 0 && mp.isCoeffPositive(false))
126             {
127                 // P(X) = Q(X) + K where K != 0 and Q with positive coeffs
128                 return Result::FALSE;
129             }
130             else
131             {
132                 return Result::DUNNO;
133             }
134         }
135         case NEQ0 :
136             if (mp.constant != 0 && mp.isCoeffPositive(false))
137             {
138                 return Result::TRUE;
139             }
140             else if (mp.isConstant(0))
141             {
142                 return Result::FALSE;
143             }
144             else
145             {
146                 return Result::DUNNO;
147             }
148         case GT0 :
149             if (mp.isCoeffStrictPositive())
150             {
151                 return Result::TRUE;
152             }
153             else if (mp.constant < 0 && mp.isCoeffNegative(false))
154             {
155                 return Result::FALSE;
156             }
157             else
158             {
159                 return Result::DUNNO;
160             }
161         case GEQ0 :
162         {
163             if (mp.isCoeffPositive())
164             {
165                 return Result::TRUE;
166             }
167             else if (mp.isConstant() && mp.constant < 0)
168             {
169                 return Result::FALSE;
170             }
171             else
172             {
173                 return Result::DUNNO;
174             }
175         }
176     }
177 }
178
179 MPolyConstraintSet MPolyConstraint::getMPConstraints(const std::vector<GVN::Value *> & values) const
180 {
181     MPolyConstraintSet set(1);
182     set.add(poly.eval(InferenceConstraint::getArgs(values)), kind);
183
184     return set;
185 }
186
187 void MPolyConstraint::applyConstraints(const std::vector<GVN::Value *> & values) const
188 {
189     if (kind == EQ0)
190     {
191         if (poly.constant == 0 && poly.polynomial.size() == 2)
192         {
193             const MultivariateMonomial & m1 = *poly.polynomial.begin();
194             const MultivariateMonomial & m2 = *std::next(poly.polynomial.begin());
195
196             if ((m1.coeff == 1 && m2.coeff == -1) || (m1.coeff == -1 && m2.coeff == 1) && (m1.monomial.size() == 1 && m2.monomial.size() == 1))
197             {
198                 // We have a polynomial P such as P(X,Y)=X-Y
199                 GVN::Value & x = *values[m1.monomial.begin()->var];
200                 GVN::Value & y = *values[m2.monomial.begin()->var];
201
202                 applyEquality(x, y);
203             }
204         }
205     }
206 }
207
208 InferenceConstraint::Result MPolyConstraintSet::check(const std::vector<GVN::Value *> & values) const
209 {
210     for (const auto & constraint : constraints)
211     {
212         Result res = constraint.check(values);
213         if (res != Result::TRUE)
214         {
215             return res;
216         }
217     }
218     return Result::TRUE;
219 }
220
221 MPolyConstraintSet MPolyConstraintSet::getMPConstraints(const std::vector<GVN::Value *> & values) const
222 {
223     MPolyConstraintSet set(constraints.size());
224     const std::vector<const MultivariatePolynomial *> args = InferenceConstraint::getArgs(values);
225     for (const auto & constraint : constraints)
226     {
227         set.add(constraint.poly.eval(args), constraint.kind);
228     }
229     return set;
230 }
231
232 void MPolyConstraintSet::applyConstraints(const std::vector<GVN::Value *> & values) const
233 {
234     for (const auto & mpc : constraints)
235     {
236         mpc.applyConstraints(values);
237     }
238 }
239
240 InferenceConstraint::Result PositiveConstraint::check(const std::vector<GVN::Value *> & values) const
241 {
242     const GVN::Value & x = *values[0];
243
244     if (x.poly->isCoeffPositive())
245     {
246         return Result::TRUE;
247     }
248     else if (x.poly->isConstant() && x.poly->constant < 0)
249     {
250         return Result::FALSE;
251     }
252
253     return Result::DUNNO;
254 }
255
256 void PositiveConstraint::applyConstraints(const std::vector<GVN::Value *> & values) const { }
257
258 MPolyConstraintSet PositiveConstraint::getMPConstraints(const std::vector<GVN::Value *> & values) const
259 {
260     MPolyConstraintSet set(1);
261     const GVN::Value & x = *values[0];
262
263     set.add(*x.poly, MPolyConstraint::Kind::GEQ0);
264
265     return set;
266 }
267
268 InferenceConstraint::Result GreaterConstraint::check(const std::vector<GVN::Value *> & values) const
269 {
270     const GVN::Value & x = *values[0];
271     const GVN::Value & y = *values[1];
272
273     if (x.value == y.value)
274     {
275         return Result::FALSE;
276     }
277
278     MultivariatePolynomial mp = *x.poly - *y.poly;
279     if (mp.constant > 0 && mp.isCoeffPositive(false))
280     {
281         return Result::TRUE;
282     }
283     else if (mp.constant < 0 && mp.isCoeffNegative(false))
284     {
285         return Result::FALSE;
286     }
287
288     return Result::DUNNO;
289 }
290
291 void GreaterConstraint::applyConstraints(const std::vector<GVN::Value *> & values) const { }
292
293 MPolyConstraintSet GreaterConstraint::getMPConstraints(const std::vector<GVN::Value *> & values) const
294 {
295     MPolyConstraintSet set(1);
296     const GVN::Value & x = *values[0];
297     const GVN::Value & y = *values[1];
298
299     set.add(*x.poly - *y.poly, MPolyConstraint::Kind::GT0);
300
301     return set;
302 }
303 }