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