expression.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*-----------------------------------------------------------------------------
  2. | Copyright (c) 2013-2019, Nucleic Development Team.
  3. |
  4. | Distributed under the terms of the Modified BSD License.
  5. |
  6. | The full license is in the file LICENSE, distributed with this software.
  7. |----------------------------------------------------------------------------*/
  8. #include <sstream>
  9. #include <cppy/cppy.h>
  10. #include "symbolics.h"
  11. #include "types.h"
  12. #include "util.h"
  13. namespace kiwisolver
  14. {
  15. namespace
  16. {
  17. PyObject*
  18. Expression_new( PyTypeObject* type, PyObject* args, PyObject* kwargs )
  19. {
  20. static const char *kwlist[] = { "terms", "constant", 0 };
  21. PyObject* pyterms;
  22. PyObject* pyconstant = 0;
  23. if( !PyArg_ParseTupleAndKeywords(
  24. args, kwargs, "O|O:__new__", const_cast<char**>( kwlist ),
  25. &pyterms, &pyconstant ) )
  26. return 0;
  27. cppy::ptr terms( PySequence_Tuple( pyterms ) );
  28. if( !terms )
  29. return 0;
  30. Py_ssize_t end = PyTuple_GET_SIZE( terms.get() );
  31. for( Py_ssize_t i = 0; i < end; ++i )
  32. {
  33. PyObject* item = PyTuple_GET_ITEM( terms.get(), i );
  34. if( !Term::TypeCheck( item ) )
  35. return cppy::type_error( item, "Term" );
  36. }
  37. double constant = 0.0;
  38. if( pyconstant && !convert_to_double( pyconstant, constant ) )
  39. return 0;
  40. PyObject* pyexpr = PyType_GenericNew( type, args, kwargs );
  41. if( !pyexpr )
  42. return 0;
  43. Expression* self = reinterpret_cast<Expression*>( pyexpr );
  44. self->terms = terms.release();
  45. self->constant = constant;
  46. return pyexpr;
  47. }
  48. void
  49. Expression_clear( Expression* self )
  50. {
  51. Py_CLEAR( self->terms );
  52. }
  53. int
  54. Expression_traverse( Expression* self, visitproc visit, void* arg )
  55. {
  56. Py_VISIT( self->terms );
  57. #if PY_VERSION_HEX >= 0x03090000
  58. // This was not needed before Python 3.9 (Python issue 35810 and 40217)
  59. Py_VISIT(Py_TYPE(self));
  60. #endif
  61. return 0;
  62. }
  63. void
  64. Expression_dealloc( Expression* self )
  65. {
  66. PyObject_GC_UnTrack( self );
  67. Expression_clear( self );
  68. Py_TYPE( self )->tp_free( pyobject_cast( self ) );
  69. }
  70. PyObject*
  71. Expression_repr( Expression* self )
  72. {
  73. std::stringstream stream;
  74. Py_ssize_t end = PyTuple_GET_SIZE( self->terms );
  75. for( Py_ssize_t i = 0; i < end; ++i )
  76. {
  77. PyObject* item = PyTuple_GET_ITEM( self->terms, i );
  78. Term* term = reinterpret_cast<Term*>( item );
  79. stream << term->coefficient << " * ";
  80. stream << reinterpret_cast<Variable*>( term->variable )->variable.name();
  81. stream << " + ";
  82. }
  83. stream << self->constant;
  84. return PyUnicode_FromString( stream.str().c_str() );
  85. }
  86. PyObject*
  87. Expression_terms( Expression* self )
  88. {
  89. return cppy::incref( self->terms );
  90. }
  91. PyObject*
  92. Expression_constant( Expression* self )
  93. {
  94. return PyFloat_FromDouble( self->constant );
  95. }
  96. PyObject*
  97. Expression_value( Expression* self )
  98. {
  99. double result = self->constant;
  100. Py_ssize_t size = PyTuple_GET_SIZE( self->terms );
  101. for( Py_ssize_t i = 0; i < size; ++i )
  102. {
  103. PyObject* item = PyTuple_GET_ITEM( self->terms, i );
  104. Term* term = reinterpret_cast<Term*>( item );
  105. Variable* pyvar = reinterpret_cast<Variable*>( term->variable );
  106. result += term->coefficient * pyvar->variable.value();
  107. }
  108. return PyFloat_FromDouble( result );
  109. }
  110. PyObject*
  111. Expression_add( PyObject* first, PyObject* second )
  112. {
  113. return BinaryInvoke<BinaryAdd, Expression>()( first, second );
  114. }
  115. PyObject*
  116. Expression_sub( PyObject* first, PyObject* second )
  117. {
  118. return BinaryInvoke<BinarySub, Expression>()( first, second );
  119. }
  120. PyObject*
  121. Expression_mul( PyObject* first, PyObject* second )
  122. {
  123. return BinaryInvoke<BinaryMul, Expression>()( first, second );
  124. }
  125. PyObject*
  126. Expression_div( PyObject* first, PyObject* second )
  127. {
  128. return BinaryInvoke<BinaryDiv, Expression>()( first, second );
  129. }
  130. PyObject*
  131. Expression_neg( PyObject* value )
  132. {
  133. return UnaryInvoke<UnaryNeg, Expression>()( value );
  134. }
  135. PyObject*
  136. Expression_richcmp( PyObject* first, PyObject* second, int op )
  137. {
  138. switch( op )
  139. {
  140. case Py_EQ:
  141. return BinaryInvoke<CmpEQ, Expression>()( first, second );
  142. case Py_LE:
  143. return BinaryInvoke<CmpLE, Expression>()( first, second );
  144. case Py_GE:
  145. return BinaryInvoke<CmpGE, Expression>()( first, second );
  146. default:
  147. break;
  148. }
  149. PyErr_Format(
  150. PyExc_TypeError,
  151. "unsupported operand type(s) for %s: "
  152. "'%.100s' and '%.100s'",
  153. pyop_str( op ),
  154. Py_TYPE( first )->tp_name,
  155. Py_TYPE( second )->tp_name
  156. );
  157. return 0;
  158. }
  159. static PyMethodDef
  160. Expression_methods[] = {
  161. { "terms", ( PyCFunction )Expression_terms, METH_NOARGS,
  162. "Get the tuple of terms for the expression." },
  163. { "constant", ( PyCFunction )Expression_constant, METH_NOARGS,
  164. "Get the constant for the expression." },
  165. { "value", ( PyCFunction )Expression_value, METH_NOARGS,
  166. "Get the value for the expression." },
  167. { 0 } // sentinel
  168. };
  169. static PyType_Slot Expression_Type_slots[] = {
  170. { Py_tp_dealloc, void_cast( Expression_dealloc ) }, /* tp_dealloc */
  171. { Py_tp_traverse, void_cast( Expression_traverse ) }, /* tp_traverse */
  172. { Py_tp_clear, void_cast( Expression_clear ) }, /* tp_clear */
  173. { Py_tp_repr, void_cast( Expression_repr ) }, /* tp_repr */
  174. { Py_tp_richcompare, void_cast( Expression_richcmp ) }, /* tp_richcompare */
  175. { Py_tp_methods, void_cast( Expression_methods ) }, /* tp_methods */
  176. { Py_tp_new, void_cast( Expression_new ) }, /* tp_new */
  177. { Py_tp_alloc, void_cast( PyType_GenericAlloc ) }, /* tp_alloc */
  178. { Py_tp_free, void_cast( PyObject_GC_Del ) }, /* tp_free */
  179. { Py_nb_add, void_cast( Expression_add ) }, /* nb_add */
  180. { Py_nb_subtract, void_cast( Expression_sub ) }, /* nb_sub */
  181. { Py_nb_multiply, void_cast( Expression_mul ) }, /* nb_mul */
  182. { Py_nb_negative, void_cast( Expression_neg ) }, /* nb_neg */
  183. { Py_nb_true_divide, void_cast( Expression_div ) }, /* nb_div */
  184. { 0, 0 },
  185. };
  186. } // namespace
  187. // Initialize static variables (otherwise the compiler eliminates them)
  188. PyTypeObject* Expression::TypeObject = NULL;
  189. PyType_Spec Expression::TypeObject_Spec = {
  190. "kiwisolver.Expression", /* tp_name */
  191. sizeof( Expression ), /* tp_basicsize */
  192. 0, /* tp_itemsize */
  193. Py_TPFLAGS_DEFAULT|
  194. Py_TPFLAGS_HAVE_GC|
  195. Py_TPFLAGS_BASETYPE, /* tp_flags */
  196. Expression_Type_slots /* slots */
  197. };
  198. bool Expression::Ready()
  199. {
  200. // The reference will be handled by the module to which we will add the type
  201. TypeObject = pytype_cast( PyType_FromSpec( &TypeObject_Spec ) );
  202. if( !TypeObject )
  203. {
  204. return false;
  205. }
  206. return true;
  207. }
  208. } // namesapce kiwisolver