1 /*-----------------------------------------------------------------------------
2 | Copyright (c) 2013-2017, Nucleic Development Team.
3 |
4 | Distributed under the terms of the Modified BSD License.
5 |
6 | The full license is in the file COPYING.txt, distributed with this software.
7 |----------------------------------------------------------------------------*/
8 #pragma once
9 #include <Python.h>
10 #include "pythonhelpers.h"
11 #include "types.h"
12 #include "util.h"
13
14
15 template<typename Op, typename T>
16 struct UnaryInvoke
17 {
operatorUnaryInvoke18 PyObject* operator()( PyObject* value )
19 {
20 return Op()( reinterpret_cast<T*>( value ) );
21 }
22 };
23
24
25 template<typename Op, typename T>
26 struct BinaryInvoke
27 {
operatorBinaryInvoke28 PyObject* operator()( PyObject* first, PyObject* second )
29 {
30 if( T::TypeCheck( first ) )
31 return invoke<Normal>( reinterpret_cast<T*>( first ), second );
32 return invoke<Reverse>( reinterpret_cast<T*>( second ), first );
33 }
34
35 struct Normal
36 {
37 template<typename U>
operatorBinaryInvoke::Normal38 PyObject* operator()( T* primary, U secondary )
39 {
40 return Op()( primary, secondary );
41 }
42 };
43
44 struct Reverse
45 {
46 template<typename U>
operatorBinaryInvoke::Reverse47 PyObject* operator()( T* primary, U secondary )
48 {
49 return Op()( secondary, primary );
50 }
51 };
52
53 template<typename Invk>
invokeBinaryInvoke54 PyObject* invoke( T* primary, PyObject* secondary )
55 {
56 if( Expression::TypeCheck( secondary ) )
57 return Invk()( primary, reinterpret_cast<Expression*>( secondary ) );
58 if( Term::TypeCheck( secondary ) )
59 return Invk()( primary, reinterpret_cast<Term*>( secondary ) );
60 if( Variable::TypeCheck( secondary ) )
61 return Invk()( primary, reinterpret_cast<Variable*>( secondary ) );
62 if( PyFloat_Check( secondary ) )
63 return Invk()( primary, PyFloat_AS_DOUBLE( secondary ) );
64 #if PY_MAJOR_VERSION < 3
65 if( PyInt_Check( secondary ) )
66 return Invk()( primary, double( PyInt_AS_LONG( secondary ) ) );
67 #endif
68 if( PyLong_Check( secondary ) )
69 {
70 double v = PyLong_AsDouble( secondary );
71 if( v == -1 && PyErr_Occurred() )
72 return 0;
73 return Invk()( primary, v );
74 }
75 Py_RETURN_NOTIMPLEMENTED;
76 }
77 };
78
79
80 struct BinaryMul
81 {
82 template<typename T, typename U>
operatorBinaryMul83 PyObject* operator()( T first, U second )
84 {
85 Py_RETURN_NOTIMPLEMENTED;
86 }
87 };
88
89
90 template<> inline
operator()91 PyObject* BinaryMul::operator()( Variable* first, double second )
92 {
93 PyObject* pyterm = PyType_GenericNew( &Term_Type, 0, 0 );
94 if( !pyterm )
95 return 0;
96 Term* term = reinterpret_cast<Term*>( pyterm );
97 term->variable = PythonHelpers::newref( pyobject_cast( first ) );
98 term->coefficient = second;
99 return pyterm;
100 }
101
102
103 template<> inline
operator()104 PyObject* BinaryMul::operator()( Term* first, double second )
105 {
106 PyObject* pyterm = PyType_GenericNew( &Term_Type, 0, 0 );
107 if( !pyterm )
108 return 0;
109 Term* term = reinterpret_cast<Term*>( pyterm );
110 term->variable = PythonHelpers::newref( first->variable );
111 term->coefficient = first->coefficient * second;
112 return pyterm;
113 }
114
115
116 template<> inline
operator()117 PyObject* BinaryMul::operator()( Expression* first, double second )
118 {
119 using namespace PythonHelpers;
120 PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
121 if( !pyexpr )
122 return 0;
123 Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
124 PyObjectPtr terms( PyTuple_New( PyTuple_GET_SIZE( first->terms ) ) );
125 if( !terms )
126 return 0;
127 Py_ssize_t end = PyTuple_GET_SIZE( first->terms );
128 for( Py_ssize_t i = 0; i < end; ++i ) // memset 0 for safe error return
129 PyTuple_SET_ITEM( terms.get(), i, 0 );
130 for( Py_ssize_t i = 0; i < end; ++i )
131 {
132 PyObject* item = PyTuple_GET_ITEM( first->terms, i );
133 PyObject* term = BinaryMul()( reinterpret_cast<Term*>( item ), second );
134 if( !term )
135 return 0;
136 PyTuple_SET_ITEM( terms.get(), i, term );
137 }
138 expr->terms = terms.release();
139 expr->constant = first->constant * second;
140 return pyexpr.release();
141 }
142
143
144 template<> inline
operator()145 PyObject* BinaryMul::operator()( double first, Variable* second )
146 {
147 return operator()( second, first );
148 }
149
150
151 template<> inline
operator()152 PyObject* BinaryMul::operator()( double first, Term* second )
153 {
154 return operator()( second, first );
155 }
156
157
158 template<> inline
operator()159 PyObject* BinaryMul::operator()( double first, Expression* second )
160 {
161 return operator()( second, first );
162 }
163
164
165 struct BinaryDiv
166 {
167 template<typename T, typename U>
operatorBinaryDiv168 PyObject* operator()( T first, U second )
169 {
170 Py_RETURN_NOTIMPLEMENTED;
171 }
172 };
173
174
175 template<> inline
operator()176 PyObject* BinaryDiv::operator()( Variable* first, double second )
177 {
178 if( second == 0.0 )
179 {
180 PyErr_SetString( PyExc_ZeroDivisionError, "float division by zero" );
181 return 0;
182 }
183 return BinaryMul()( first, 1.0 / second );
184 }
185
186
187 template<> inline
operator()188 PyObject* BinaryDiv::operator()( Term* first, double second )
189 {
190 if( second == 0.0 )
191 {
192 PyErr_SetString( PyExc_ZeroDivisionError, "float division by zero" );
193 return 0;
194 }
195 return BinaryMul()( first, 1.0 / second );
196 }
197
198
199 template<> inline
operator()200 PyObject* BinaryDiv::operator()( Expression* first, double second )
201 {
202 if( second == 0.0 )
203 {
204 PyErr_SetString( PyExc_ZeroDivisionError, "float division by zero" );
205 return 0;
206 }
207 return BinaryMul()( first, 1.0 / second );
208 }
209
210
211 struct UnaryNeg
212 {
213 template<typename T>
operatorUnaryNeg214 PyObject* operator()( T value )
215 {
216 Py_RETURN_NOTIMPLEMENTED;
217 }
218 };
219
220
221 template<> inline
operator()222 PyObject* UnaryNeg::operator()( Variable* value )
223 {
224 return BinaryMul()( value, -1.0 );
225 }
226
227
228 template<> inline
operator()229 PyObject* UnaryNeg::operator()( Term* value )
230 {
231 return BinaryMul()( value, -1.0 );
232 }
233
234
235 template<> inline
operator()236 PyObject* UnaryNeg::operator()( Expression* value )
237 {
238 return BinaryMul()( value, -1.0 );
239 }
240
241
242 struct BinaryAdd
243 {
244 template<typename T, typename U>
operatorBinaryAdd245 PyObject* operator()( T first, U second )
246 {
247 Py_RETURN_NOTIMPLEMENTED;
248 }
249 };
250
251
252 template<> inline
operator()253 PyObject* BinaryAdd::operator()( Expression* first, Expression* second )
254 {
255 PythonHelpers::PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
256 if( !pyexpr )
257 return 0;
258 Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
259 expr->constant = first->constant + second->constant;
260 expr->terms = PySequence_Concat( first->terms, second->terms );
261 if( !expr->terms )
262 return 0;
263 return pyexpr.release();
264 }
265
266
267 template<> inline
operator()268 PyObject* BinaryAdd::operator()( Expression* first, Term* second )
269 {
270 using namespace PythonHelpers;
271 PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
272 if( !pyexpr )
273 return 0;
274 PyObject* terms = PyTuple_New( PyTuple_GET_SIZE( first->terms ) + 1 );
275 if( !terms )
276 return 0;
277 Py_ssize_t end = PyTuple_GET_SIZE( first->terms );
278 for( Py_ssize_t i = 0; i < end; ++i )
279 {
280 PyObject* item = PyTuple_GET_ITEM( first->terms, i );
281 PyTuple_SET_ITEM( terms, i, newref( item ) );
282 }
283 PyTuple_SET_ITEM( terms, end, newref( pyobject_cast( second ) ) );
284 Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
285 expr->terms = terms;
286 expr->constant = first->constant;
287 return pyexpr.release();
288 }
289
290
291 template<> inline
operator()292 PyObject* BinaryAdd::operator()( Expression* first, Variable* second )
293 {
294 PythonHelpers::PyObjectPtr temp( BinaryMul()( second, 1.0 ) );
295 if( !temp )
296 return 0;
297 return operator()( first, reinterpret_cast<Term*>( temp.get() ) );
298 }
299
300
301 template<> inline
operator()302 PyObject* BinaryAdd::operator()( Expression* first, double second )
303 {
304 using namespace PythonHelpers;
305 PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
306 if( !pyexpr )
307 return 0;
308 Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
309 expr->terms = newref( first->terms );
310 expr->constant = first->constant + second;
311 return pyexpr.release();
312 }
313
314
315 template<> inline
operator()316 PyObject* BinaryAdd::operator()( Term* first, double second )
317 {
318 PythonHelpers::PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
319 if( !pyexpr )
320 return 0;
321 Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
322 expr->constant = second;
323 expr->terms = PyTuple_Pack( 1, first );
324 if( !expr->terms )
325 return 0;
326 return pyexpr.release();
327 }
328
329
330 template<> inline
operator()331 PyObject* BinaryAdd::operator()( Term* first, Expression* second )
332 {
333 return operator()( second, first );
334 }
335
336
337 template<> inline
operator()338 PyObject* BinaryAdd::operator()( Term* first, Term* second )
339 {
340 PythonHelpers::PyObjectPtr pyexpr( PyType_GenericNew( &Expression_Type, 0, 0 ) );
341 if( !pyexpr )
342 return 0;
343 Expression* expr = reinterpret_cast<Expression*>( pyexpr.get() );
344 expr->constant = 0.0;
345 expr->terms = PyTuple_Pack( 2, first, second );
346 if( !expr->terms )
347 return 0;
348 return pyexpr.release();
349 }
350
351
352 template<> inline
operator()353 PyObject* BinaryAdd::operator()( Term* first, Variable* second )
354 {
355 PythonHelpers::PyObjectPtr temp( BinaryMul()( second, 1.0 ) );
356 if( !temp )
357 return 0;
358 return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
359 }
360
361
362 template<> inline
operator()363 PyObject* BinaryAdd::operator()( Variable* first, double second )
364 {
365 PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
366 if( !temp )
367 return 0;
368 return operator()( reinterpret_cast<Term*>( temp.get() ), second );
369 }
370
371
372 template<> inline
operator()373 PyObject* BinaryAdd::operator()( Variable* first, Variable* second )
374 {
375 PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
376 if( !temp )
377 return 0;
378 return operator()( reinterpret_cast<Term*>( temp.get() ), second );
379 }
380
381
382 template<> inline
operator()383 PyObject* BinaryAdd::operator()( Variable* first, Term* second )
384 {
385 PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
386 if( !temp )
387 return 0;
388 return operator()( reinterpret_cast<Term*>( temp.get() ), second );
389 }
390
391
392 template<> inline
operator()393 PyObject* BinaryAdd::operator()( Variable* first, Expression* second )
394 {
395 PythonHelpers::PyObjectPtr temp( BinaryMul()( first, 1.0 ) );
396 if( !temp )
397 return 0;
398 return operator()( reinterpret_cast<Term*>( temp.get() ), second );
399 }
400
401
402 template<> inline
operator()403 PyObject* BinaryAdd::operator()( double first, Variable* second )
404 {
405 return operator()( second, first );
406 }
407
408
409 template<> inline
operator()410 PyObject* BinaryAdd::operator()( double first, Term* second )
411 {
412 return operator()( second, first );
413 }
414
415
416 template<> inline
operator()417 PyObject* BinaryAdd::operator()( double first, Expression* second )
418 {
419 return operator()( second, first );
420 }
421
422
423 struct BinarySub
424 {
425 template<typename T, typename U>
operatorBinarySub426 PyObject* operator()( T first, U second )
427 {
428 Py_RETURN_NOTIMPLEMENTED;
429 }
430 };
431
432
433 template<> inline
operator()434 PyObject* BinarySub::operator()( Variable* first, double second )
435 {
436 return BinaryAdd()( first, -second );
437 }
438
439
440 template<> inline
operator()441 PyObject* BinarySub::operator()( Variable* first, Variable* second )
442 {
443 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
444 if( !temp )
445 return 0;
446 return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
447 }
448
449
450 template<> inline
operator()451 PyObject* BinarySub::operator()( Variable* first, Term* second )
452 {
453 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
454 if( !temp )
455 return 0;
456 return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
457 }
458
459
460 template<> inline
operator()461 PyObject* BinarySub::operator()( Variable* first, Expression* second )
462 {
463 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
464 if( !temp )
465 return 0;
466 return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
467 }
468
469
470 template<> inline
operator()471 PyObject* BinarySub::operator()( Term* first, double second )
472 {
473 return BinaryAdd()( first, -second );
474 }
475
476
477 template<> inline
operator()478 PyObject* BinarySub::operator()( Term* first, Variable* second )
479 {
480 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
481 if( !temp )
482 return 0;
483 return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
484 }
485
486
487 template<> inline
operator()488 PyObject* BinarySub::operator()( Term* first, Term* second )
489 {
490 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
491 if( !temp )
492 return 0;
493 return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
494 }
495
496
497 template<> inline
operator()498 PyObject* BinarySub::operator()( Term* first, Expression* second )
499 {
500 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
501 if( !temp )
502 return 0;
503 return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
504 }
505
506
507 template<> inline
operator()508 PyObject* BinarySub::operator()( Expression* first, double second )
509 {
510 return BinaryAdd()( first, -second );
511 }
512
513
514 template<> inline
operator()515 PyObject* BinarySub::operator()( Expression* first, Variable* second )
516 {
517 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
518 if( !temp )
519 return 0;
520 return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
521 }
522
523
524 template<> inline
operator()525 PyObject* BinarySub::operator()( Expression* first, Term* second )
526 {
527 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
528 if( !temp )
529 return 0;
530 return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
531 }
532
533
534 template<> inline
operator()535 PyObject* BinarySub::operator()( Expression* first, Expression* second )
536 {
537 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
538 if( !temp )
539 return 0;
540 return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
541 }
542
543
544 template<> inline
operator()545 PyObject* BinarySub::operator()( double first, Variable* second )
546 {
547 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
548 if( !temp )
549 return 0;
550 return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
551 }
552
553
554 template<> inline
operator()555 PyObject* BinarySub::operator()( double first, Term* second )
556 {
557 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
558 if( !temp )
559 return 0;
560 return BinaryAdd()( first, reinterpret_cast<Term*>( temp.get() ) );
561 }
562
563
564 template<> inline
operator()565 PyObject* BinarySub::operator()( double first, Expression* second )
566 {
567 PythonHelpers::PyObjectPtr temp( UnaryNeg()( second ) );
568 if( !temp )
569 return 0;
570 return BinaryAdd()( first, reinterpret_cast<Expression*>( temp.get() ) );
571 }
572
573
574 template<typename T, typename U>
makecn(T first,U second,kiwi::RelationalOperator op)575 PyObject* makecn( T first, U second, kiwi::RelationalOperator op )
576 {
577 PythonHelpers::PyObjectPtr pyexpr( BinarySub()( first, second ) );
578 if( !pyexpr )
579 return 0;
580 PythonHelpers::PyObjectPtr pycn( PyType_GenericNew( &Constraint_Type, 0, 0 ) );
581 if( !pycn )
582 return 0;
583 Constraint* cn = reinterpret_cast<Constraint*>( pycn.get() );
584 cn->expression = reduce_expression( pyexpr.get() );
585 if( !cn->expression )
586 return 0;
587 kiwi::Expression expr( convert_to_kiwi_expression( cn->expression ) );
588 new( &cn->constraint ) kiwi::Constraint( expr, op, kiwi::strength::required );
589 return pycn.release();
590 }
591
592
593 struct CmpEQ
594 {
595 template<typename T, typename U>
operatorCmpEQ596 PyObject* operator()( T first, U second )
597 {
598 return makecn( first, second, kiwi::OP_EQ );
599 }
600 };
601
602
603 struct CmpLE
604 {
605 template<typename T, typename U>
operatorCmpLE606 PyObject* operator()( T first, U second )
607 {
608 return makecn( first, second, kiwi::OP_LE );
609 }
610 };
611
612
613 struct CmpGE
614 {
615 template<typename T, typename U>
operatorCmpGE616 PyObject* operator()( T first, U second )
617 {
618 return makecn( first, second, kiwi::OP_GE );
619 }
620 };
621