PySCIPOpt 5.3.0__tar.gz → 5.4.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/PKG-INFO +15 -4
  2. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/PySCIPOpt.egg-info/PKG-INFO +15 -4
  3. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/PySCIPOpt.egg-info/SOURCES.txt +4 -0
  4. pyscipopt-5.4.1/PySCIPOpt.egg-info/requires.txt +1 -0
  5. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/README.md +13 -3
  6. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/pyproject.toml +1 -1
  7. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/setup.cfg +0 -3
  8. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/setup.py +2 -2
  9. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/__init__.py +5 -0
  10. pyscipopt-5.4.1/src/pyscipopt/_version.py +1 -0
  11. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/expr.pxi +59 -9
  12. pyscipopt-5.4.1/src/pyscipopt/matrix.pxi +139 -0
  13. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/scip.c +123219 -91453
  14. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/scip.pxd +4 -0
  15. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/scip.pxi +750 -17
  16. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_heur.py +1 -1
  17. pyscipopt-5.4.1/tests/test_matrix_variable.py +322 -0
  18. pyscipopt-5.4.1/tests/test_node.py +21 -0
  19. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_nogil.py +1 -1
  20. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_nonlinear.py +11 -0
  21. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_solution.py +3 -3
  22. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_strong_branching.py +3 -3
  23. pyscipopt-5.3.0/src/pyscipopt/_version.py +0 -1
  24. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/LICENSE +0 -0
  25. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/PySCIPOpt.egg-info/dependency_links.txt +0 -0
  26. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/PySCIPOpt.egg-info/top_level.txt +0 -0
  27. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/Multidict.py +0 -0
  28. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/benders.pxi +0 -0
  29. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/benderscut.pxi +0 -0
  30. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/branchrule.pxi +0 -0
  31. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/conshdlr.pxi +0 -0
  32. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/cutsel.pxi +0 -0
  33. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/event.pxi +0 -0
  34. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/heuristic.pxi +0 -0
  35. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/lp.pxi +0 -0
  36. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/nodesel.pxi +0 -0
  37. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/presol.pxi +0 -0
  38. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/pricer.pxi +0 -0
  39. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/propagator.pxi +0 -0
  40. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/reader.pxi +0 -0
  41. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/recipes/__init__.py +0 -0
  42. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/recipes/infeasibilities.py +0 -0
  43. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/recipes/nonlinear.py +0 -0
  44. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/recipes/piecewise.py +0 -0
  45. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/recipes/primal_dual_evolution.py +0 -0
  46. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/relax.pxi +0 -0
  47. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/scip.pyx +0 -0
  48. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/src/pyscipopt/sepa.pxi +0 -0
  49. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_alldiff.py +0 -0
  50. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_benders.py +0 -0
  51. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_bipartite.py +0 -0
  52. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_branch_mostinfeas.py +0 -0
  53. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_branch_probing_lp.py +0 -0
  54. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_cons.py +0 -0
  55. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_conshdlr.py +0 -0
  56. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_copy.py +0 -0
  57. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_customizedbenders.py +0 -0
  58. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_cutsel.py +0 -0
  59. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_event.py +0 -0
  60. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_expr.py +0 -0
  61. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_gomory.py +0 -0
  62. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_knapsack.py +0 -0
  63. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_linexpr.py +0 -0
  64. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_logical.py +0 -0
  65. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_lp.py +0 -0
  66. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_memory.py +0 -0
  67. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_model.py +0 -0
  68. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_nlrow.py +0 -0
  69. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_nodesel.py +0 -0
  70. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_pricer.py +0 -0
  71. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_quadcons.py +0 -0
  72. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_quickprod.py +0 -0
  73. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_quicksum.py +0 -0
  74. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_reader.py +0 -0
  75. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_recipe_infeasibilities.py +0 -0
  76. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_recipe_nonlinear.py +0 -0
  77. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_recipe_piecewise.py +0 -0
  78. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_recipe_primal_dual_evolution.py +0 -0
  79. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_relax.py +0 -0
  80. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_reopt.py +0 -0
  81. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_short.py +0 -0
  82. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_sub_sol.py +0 -0
  83. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_tree.py +0 -0
  84. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_tsp.py +0 -0
  85. {pyscipopt-5.3.0 → pyscipopt-5.4.1}/tests/test_vars.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PySCIPOpt
3
- Version: 5.3.0
3
+ Version: 5.4.1
4
4
  Summary: Python interface and modeling environment for SCIP
5
5
  Home-page: https://github.com/SCIP-Interfaces/PySCIPOpt
6
6
  Author: Zuse Institute Berlin
@@ -17,6 +17,7 @@ Classifier: Topic :: Scientific/Engineering :: Mathematics
17
17
  Requires-Python: >=3.8
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
+ Requires-Dist: numpy>=1.16.0
20
21
  Dynamic: author
21
22
  Dynamic: home-page
22
23
 
@@ -66,20 +67,20 @@ following steps are always required when using the interface:
66
67
  1) It is necessary to import python-scip in your code. This is achieved
67
68
  by including the line
68
69
 
69
- ``` {.sourceCode .python}
70
+ ```python
70
71
  from pyscipopt import Model
71
72
  ```
72
73
 
73
74
  2) Create a solver instance.
74
75
 
75
- ``` {.sourceCode .python}
76
+ ```python
76
77
  model = Model("Example") # model name is optional
77
78
  ```
78
79
 
79
80
  3) Access the methods in the `scip.pxi` file using the solver/model
80
81
  instance `model`, e.g.:
81
82
 
82
- ``` {.sourceCode .python}
83
+ ```python
83
84
  x = model.addVar("x")
84
85
  y = model.addVar("y", vtype="INTEGER")
85
86
  model.setObjective(x + y)
@@ -104,6 +105,16 @@ examples.
104
105
  Please notice that in most cases one needs to use a `dictionary` to
105
106
  specify the return values needed by SCIP.
106
107
 
108
+ Using PySCIPOpt?
109
+ ----------------
110
+
111
+ If your project or company is using PySCIPOpt, consider letting us know at scip@zib.de. We are always interested
112
+ in knowing how PySCIPOpt is being used, and, given permission, would also appreciate adding your company's logo
113
+ to our website.
114
+
115
+ If you are creating models with some degree of complexity which don't take too long to solve, also consider
116
+ sharing them with us. We might want to add them to [`tests/helpers/utils.py`](tests/helpers/utils.py) to help make our tests more robust, or add them to our examples.
117
+
107
118
  Citing PySCIPOpt
108
119
  ----------------
109
120
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PySCIPOpt
3
- Version: 5.3.0
3
+ Version: 5.4.1
4
4
  Summary: Python interface and modeling environment for SCIP
5
5
  Home-page: https://github.com/SCIP-Interfaces/PySCIPOpt
6
6
  Author: Zuse Institute Berlin
@@ -17,6 +17,7 @@ Classifier: Topic :: Scientific/Engineering :: Mathematics
17
17
  Requires-Python: >=3.8
18
18
  Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
+ Requires-Dist: numpy>=1.16.0
20
21
  Dynamic: author
21
22
  Dynamic: home-page
22
23
 
@@ -66,20 +67,20 @@ following steps are always required when using the interface:
66
67
  1) It is necessary to import python-scip in your code. This is achieved
67
68
  by including the line
68
69
 
69
- ``` {.sourceCode .python}
70
+ ```python
70
71
  from pyscipopt import Model
71
72
  ```
72
73
 
73
74
  2) Create a solver instance.
74
75
 
75
- ``` {.sourceCode .python}
76
+ ```python
76
77
  model = Model("Example") # model name is optional
77
78
  ```
78
79
 
79
80
  3) Access the methods in the `scip.pxi` file using the solver/model
80
81
  instance `model`, e.g.:
81
82
 
82
- ``` {.sourceCode .python}
83
+ ```python
83
84
  x = model.addVar("x")
84
85
  y = model.addVar("y", vtype="INTEGER")
85
86
  model.setObjective(x + y)
@@ -104,6 +105,16 @@ examples.
104
105
  Please notice that in most cases one needs to use a `dictionary` to
105
106
  specify the return values needed by SCIP.
106
107
 
108
+ Using PySCIPOpt?
109
+ ----------------
110
+
111
+ If your project or company is using PySCIPOpt, consider letting us know at scip@zib.de. We are always interested
112
+ in knowing how PySCIPOpt is being used, and, given permission, would also appreciate adding your company's logo
113
+ to our website.
114
+
115
+ If you are creating models with some degree of complexity which don't take too long to solve, also consider
116
+ sharing them with us. We might want to add them to [`tests/helpers/utils.py`](tests/helpers/utils.py) to help make our tests more robust, or add them to our examples.
117
+
107
118
  Citing PySCIPOpt
108
119
  ----------------
109
120
 
@@ -6,6 +6,7 @@ setup.py
6
6
  PySCIPOpt.egg-info/PKG-INFO
7
7
  PySCIPOpt.egg-info/SOURCES.txt
8
8
  PySCIPOpt.egg-info/dependency_links.txt
9
+ PySCIPOpt.egg-info/requires.txt
9
10
  PySCIPOpt.egg-info/top_level.txt
10
11
  src/pyscipopt/Multidict.py
11
12
  src/pyscipopt/__init__.py
@@ -19,6 +20,7 @@ src/pyscipopt/event.pxi
19
20
  src/pyscipopt/expr.pxi
20
21
  src/pyscipopt/heuristic.pxi
21
22
  src/pyscipopt/lp.pxi
23
+ src/pyscipopt/matrix.pxi
22
24
  src/pyscipopt/nodesel.pxi
23
25
  src/pyscipopt/presol.pxi
24
26
  src/pyscipopt/pricer.pxi
@@ -53,9 +55,11 @@ tests/test_knapsack.py
53
55
  tests/test_linexpr.py
54
56
  tests/test_logical.py
55
57
  tests/test_lp.py
58
+ tests/test_matrix_variable.py
56
59
  tests/test_memory.py
57
60
  tests/test_model.py
58
61
  tests/test_nlrow.py
62
+ tests/test_node.py
59
63
  tests/test_nodesel.py
60
64
  tests/test_nogil.py
61
65
  tests/test_nonlinear.py
@@ -0,0 +1 @@
1
+ numpy>=1.16.0
@@ -44,20 +44,20 @@ following steps are always required when using the interface:
44
44
  1) It is necessary to import python-scip in your code. This is achieved
45
45
  by including the line
46
46
 
47
- ``` {.sourceCode .python}
47
+ ```python
48
48
  from pyscipopt import Model
49
49
  ```
50
50
 
51
51
  2) Create a solver instance.
52
52
 
53
- ``` {.sourceCode .python}
53
+ ```python
54
54
  model = Model("Example") # model name is optional
55
55
  ```
56
56
 
57
57
  3) Access the methods in the `scip.pxi` file using the solver/model
58
58
  instance `model`, e.g.:
59
59
 
60
- ``` {.sourceCode .python}
60
+ ```python
61
61
  x = model.addVar("x")
62
62
  y = model.addVar("y", vtype="INTEGER")
63
63
  model.setObjective(x + y)
@@ -82,6 +82,16 @@ examples.
82
82
  Please notice that in most cases one needs to use a `dictionary` to
83
83
  specify the return values needed by SCIP.
84
84
 
85
+ Using PySCIPOpt?
86
+ ----------------
87
+
88
+ If your project or company is using PySCIPOpt, consider letting us know at scip@zib.de. We are always interested
89
+ in knowing how PySCIPOpt is being used, and, given permission, would also appreciate adding your company's logo
90
+ to our website.
91
+
92
+ If you are creating models with some degree of complexity which don't take too long to solve, also consider
93
+ sharing them with us. We might want to add them to [`tests/helpers/utils.py`](tests/helpers/utils.py) to help make our tests more robust, or add them to our examples.
94
+
85
95
  Citing PySCIPOpt
86
96
  ----------------
87
97
 
@@ -8,7 +8,7 @@ description = "Python interface and modeling environment for SCIP"
8
8
  authors = [
9
9
  {name = "Zuse Institute Berlin", email = "scip@zib.de"},
10
10
  ]
11
- dependencies = []
11
+ dependencies = ['numpy >=1.16.0']
12
12
  requires-python = ">=3.8"
13
13
  readme = "README.md"
14
14
  license = {text = "MIT"}
@@ -1,6 +1,3 @@
1
- [bdist_wheel]
2
- universal = 1
3
-
4
1
  [egg_info]
5
2
  tag_build =
6
3
  tag_date = 0
@@ -1,5 +1,5 @@
1
1
  from setuptools import find_packages, setup, Extension
2
- import os, platform, sys, re
2
+ import os, platform, sys
3
3
 
4
4
  # look for environment variable that specifies path to SCIP
5
5
  scipoptdir = os.environ.get("SCIPOPTDIR", "").strip('"')
@@ -109,7 +109,7 @@ with open("README.md") as f:
109
109
 
110
110
  setup(
111
111
  name="PySCIPOpt",
112
- version="5.3.0",
112
+ version="5.4.1",
113
113
  description="Python interface and modeling environment for SCIP",
114
114
  long_description=long_description,
115
115
  long_description_content_type="text/markdown",
@@ -10,7 +10,9 @@ if hasattr(os, 'add_dll_directory'):
10
10
  from pyscipopt.Multidict import multidict
11
11
  from pyscipopt.scip import Model
12
12
  from pyscipopt.scip import Variable
13
+ from pyscipopt.scip import MatrixVariable
13
14
  from pyscipopt.scip import Constraint
15
+ from pyscipopt.scip import MatrixConstraint
14
16
  from pyscipopt.scip import Benders
15
17
  from pyscipopt.scip import Benderscut
16
18
  from pyscipopt.scip import Branchrule
@@ -26,6 +28,9 @@ from pyscipopt.scip import Sepa
26
28
  from pyscipopt.scip import LP
27
29
  from pyscipopt.scip import readStatistics
28
30
  from pyscipopt.scip import Expr
31
+ from pyscipopt.scip import MatrixExpr
32
+ from pyscipopt.scip import MatrixExprCons
33
+ from pyscipopt.scip import ExprCons
29
34
  from pyscipopt.scip import quicksum
30
35
  from pyscipopt.scip import quickprod
31
36
  from pyscipopt.scip import exp
@@ -0,0 +1 @@
1
+ __version__ = '5.4.1'
@@ -42,7 +42,7 @@
42
42
  # which should, in princple, modify the expr. However, since we do not implement __isub__, __sub__
43
43
  # gets called (I guess) and so a copy is returned.
44
44
  # Modifying the expression directly would be a bug, given that the expression might be re-used by the user. </pre>
45
-
45
+ include "matrix.pxi"
46
46
 
47
47
  def _is_number(e):
48
48
  try:
@@ -52,14 +52,15 @@ def _is_number(e):
52
52
  return False
53
53
  except TypeError: # for other types (Variable, Expr)
54
54
  return False
55
-
56
-
55
+
57
56
  def _expr_richcmp(self, other, op):
58
57
  if op == 1: # <=
59
58
  if isinstance(other, Expr) or isinstance(other, GenExpr):
60
59
  return (self - other) <= 0.0
61
60
  elif _is_number(other):
62
61
  return ExprCons(self, rhs=float(other))
62
+ elif isinstance(other, MatrixExpr):
63
+ return _expr_richcmp(other, self, 5)
63
64
  else:
64
65
  raise NotImplementedError
65
66
  elif op == 5: # >=
@@ -67,6 +68,8 @@ def _expr_richcmp(self, other, op):
67
68
  return (self - other) >= 0.0
68
69
  elif _is_number(other):
69
70
  return ExprCons(self, lhs=float(other))
71
+ elif isinstance(other, MatrixExpr):
72
+ return _expr_richcmp(other, self, 1)
70
73
  else:
71
74
  raise NotImplementedError
72
75
  elif op == 2: # ==
@@ -74,6 +77,8 @@ def _expr_richcmp(self, other, op):
74
77
  return (self - other) == 0.0
75
78
  elif _is_number(other):
76
79
  return ExprCons(self, lhs=float(other), rhs=float(other))
80
+ elif isinstance(other, MatrixExpr):
81
+ return _expr_richcmp(other, self, 2)
77
82
  else:
78
83
  raise NotImplementedError
79
84
  else:
@@ -117,6 +122,7 @@ def buildGenExprObj(expr):
117
122
  """helper function to generate an object of type GenExpr"""
118
123
  if _is_number(expr):
119
124
  return Constant(expr)
125
+
120
126
  elif isinstance(expr, Expr):
121
127
  # loop over terms and create a sumexpr with the sum of each term
122
128
  # each term is either a variable (which gets transformed into varexpr)
@@ -135,6 +141,13 @@ def buildGenExprObj(expr):
135
141
  prodexpr *= varexpr
136
142
  sumexpr += coef * prodexpr
137
143
  return sumexpr
144
+
145
+ elif isinstance(expr, MatrixExpr):
146
+ GenExprs = np.empty(expr.shape, dtype=object)
147
+ for idx in np.ndindex(expr.shape):
148
+ GenExprs[idx] = buildGenExprObj(expr[idx])
149
+ return GenExprs
150
+
138
151
  else:
139
152
  assert isinstance(expr, GenExpr)
140
153
  return expr
@@ -185,8 +198,11 @@ cdef class Expr:
185
198
  terms[CONST] = terms.get(CONST, 0.0) + c
186
199
  elif isinstance(right, GenExpr):
187
200
  return buildGenExprObj(left) + right
201
+ elif isinstance(right, MatrixExpr):
202
+ return right + left
188
203
  else:
189
204
  raise NotImplementedError
205
+
190
206
  return Expr(terms)
191
207
 
192
208
  def __iadd__(self, other):
@@ -203,6 +219,7 @@ cdef class Expr:
203
219
  return buildGenExprObj(self) + other
204
220
  else:
205
221
  raise NotImplementedError
222
+
206
223
  return self
207
224
 
208
225
  def __mul__(self, other):
@@ -319,7 +336,6 @@ cdef class ExprCons:
319
336
  if op == 1: # <=
320
337
  if not self._rhs is None:
321
338
  raise TypeError('ExprCons already has upper bound')
322
- assert self._rhs is None
323
339
  assert not self._lhs is None
324
340
 
325
341
  if not _is_number(other):
@@ -622,19 +638,53 @@ cdef class Constant(GenExpr):
622
638
 
623
639
  def exp(expr):
624
640
  """returns expression with exp-function"""
625
- return UnaryExpr(Operator.exp, buildGenExprObj(expr))
641
+ if isinstance(expr, MatrixExpr):
642
+ unary_exprs = np.empty(shape=expr.shape, dtype=object)
643
+ for idx in np.ndindex(expr.shape):
644
+ unary_exprs[idx] = UnaryExpr(Operator.exp, buildGenExprObj(expr[idx]))
645
+ return unary_exprs.view(MatrixGenExpr)
646
+ else:
647
+ return UnaryExpr(Operator.exp, buildGenExprObj(expr))
648
+
626
649
  def log(expr):
627
650
  """returns expression with log-function"""
628
- return UnaryExpr(Operator.log, buildGenExprObj(expr))
651
+ if isinstance(expr, MatrixExpr):
652
+ unary_exprs = np.empty(shape=expr.shape, dtype=object)
653
+ for idx in np.ndindex(expr.shape):
654
+ unary_exprs[idx] = UnaryExpr(Operator.log, buildGenExprObj(expr[idx]))
655
+ return unary_exprs.view(MatrixGenExpr)
656
+ else:
657
+ return UnaryExpr(Operator.log, buildGenExprObj(expr))
658
+
629
659
  def sqrt(expr):
630
660
  """returns expression with sqrt-function"""
631
- return UnaryExpr(Operator.sqrt, buildGenExprObj(expr))
661
+ if isinstance(expr, MatrixExpr):
662
+ unary_exprs = np.empty(shape=expr.shape, dtype=object)
663
+ for idx in np.ndindex(expr.shape):
664
+ unary_exprs[idx] = UnaryExpr(Operator.sqrt, buildGenExprObj(expr[idx]))
665
+ return unary_exprs.view(MatrixGenExpr)
666
+ else:
667
+ return UnaryExpr(Operator.sqrt, buildGenExprObj(expr))
668
+
632
669
  def sin(expr):
633
670
  """returns expression with sin-function"""
634
- return UnaryExpr(Operator.sin, buildGenExprObj(expr))
671
+ if isinstance(expr, MatrixExpr):
672
+ unary_exprs = np.empty(shape=expr.shape, dtype=object)
673
+ for idx in np.ndindex(expr.shape):
674
+ unary_exprs[idx] = UnaryExpr(Operator.sin, buildGenExprObj(expr[idx]))
675
+ return unary_exprs.view(MatrixGenExpr)
676
+ else:
677
+ return UnaryExpr(Operator.sin, buildGenExprObj(expr))
678
+
635
679
  def cos(expr):
636
680
  """returns expression with cos-function"""
637
- return UnaryExpr(Operator.cos, buildGenExprObj(expr))
681
+ if isinstance(expr, MatrixExpr):
682
+ unary_exprs = np.empty(shape=expr.shape, dtype=object)
683
+ for idx in np.ndindex(expr.shape):
684
+ unary_exprs[idx] = UnaryExpr(Operator.cos, buildGenExprObj(expr[idx]))
685
+ return unary_exprs.view(MatrixGenExpr)
686
+ else:
687
+ return UnaryExpr(Operator.cos, buildGenExprObj(expr))
638
688
 
639
689
  def expr_to_nodes(expr):
640
690
  '''transforms tree to an array of nodes. each node is an operator and the position of the
@@ -0,0 +1,139 @@
1
+ """
2
+ # TODO Cythonize things. Improve performance.
3
+ # TODO Add tests
4
+ """
5
+
6
+ import numpy as np
7
+ from typing import Union
8
+
9
+ def _is_number(e):
10
+ try:
11
+ f = float(e)
12
+ return True
13
+ except ValueError: # for malformed strings
14
+ return False
15
+ except TypeError: # for other types (Variable, Expr)
16
+ return False
17
+
18
+ class MatrixExpr(np.ndarray):
19
+ def sum(self, **kwargs):
20
+ return super().sum(**kwargs).item()
21
+
22
+ def __le__(self, other: Union[float, int, Variable, np.ndarray, 'MatrixExpr']) -> np.ndarray:
23
+
24
+ expr_cons_matrix = np.empty(self.shape, dtype=object)
25
+ if _is_number(other) or isinstance(other, Variable):
26
+ for idx in np.ndindex(self.shape):
27
+ expr_cons_matrix[idx] = self[idx] <= other
28
+
29
+ elif isinstance(other, np.ndarray):
30
+ for idx in np.ndindex(self.shape):
31
+ expr_cons_matrix[idx] = self[idx] <= other[idx]
32
+ else:
33
+ raise TypeError(f"Unsupported type {type(other)}")
34
+
35
+ return expr_cons_matrix.view(MatrixExprCons)
36
+
37
+ def __ge__(self, other: Union[float, int, Variable, np.ndarray, 'MatrixExpr']) -> np.ndarray:
38
+
39
+ expr_cons_matrix = np.empty(self.shape, dtype=object)
40
+ if _is_number(other) or isinstance(other, Variable):
41
+ for idx in np.ndindex(self.shape):
42
+ expr_cons_matrix[idx] = self[idx] >= other
43
+
44
+ elif isinstance(other, np.ndarray):
45
+ for idx in np.ndindex(self.shape):
46
+ expr_cons_matrix[idx] = self[idx] >= other[idx]
47
+ else:
48
+ raise TypeError(f"Unsupported type {type(other)}")
49
+
50
+ return expr_cons_matrix.view(MatrixExprCons)
51
+
52
+ def __eq__(self, other: Union[float, int, Variable, np.ndarray, 'MatrixExpr']) -> np.ndarray:
53
+
54
+ expr_cons_matrix = np.empty(self.shape, dtype=object)
55
+ if _is_number(other) or isinstance(other, Variable):
56
+ for idx in np.ndindex(self.shape):
57
+ expr_cons_matrix[idx] = self[idx] == other
58
+
59
+ elif isinstance(other, np.ndarray):
60
+ for idx in np.ndindex(self.shape):
61
+ expr_cons_matrix[idx] = self[idx] == other[idx]
62
+ else:
63
+ raise TypeError(f"Unsupported type {type(other)}")
64
+
65
+ return expr_cons_matrix.view(MatrixExprCons)
66
+
67
+ def __add__(self, other):
68
+ return super().__add__(other).view(MatrixExpr)
69
+
70
+ def __iadd__(self, other):
71
+ return super().__iadd__(other).view(MatrixExpr)
72
+
73
+ def __mul__(self, other):
74
+ return super().__mul__(other).view(MatrixExpr)
75
+
76
+ def __truediv__(self, other):
77
+ return super().__truediv__(other).view(MatrixExpr)
78
+
79
+ def __rtruediv__(self, other):
80
+ return super().__rtruediv__(other).view(MatrixExpr)
81
+
82
+ def __pow__(self, other):
83
+ return super().__pow__(other).view(MatrixExpr)
84
+
85
+ def __sub__(self, other):
86
+ return super().__sub__(other).view(MatrixExpr)
87
+
88
+ def __radd__(self, other):
89
+ return super().__radd__(other).view(MatrixExpr)
90
+
91
+ def __rmul__(self, other):
92
+ return super().__rmul__(other).view(MatrixExpr)
93
+
94
+ def __rsub__(self, other):
95
+ return super().__rsub__(other).view(MatrixExpr)
96
+
97
+ class MatrixGenExpr(MatrixExpr):
98
+ pass
99
+
100
+ class MatrixExprCons(np.ndarray):
101
+
102
+ def __le__(self, other: Union[float, int, Variable, MatrixExpr]) -> np.ndarray:
103
+
104
+ if not _is_number(other) or not isinstance(other, MatrixExpr):
105
+ raise TypeError('Ranged MatrixExprCons is not well defined!')
106
+
107
+ expr_cons_matrix = np.empty(self.shape, dtype=object)
108
+ if _is_number(other) or isinstance(other, Variable):
109
+ for idx in np.ndindex(self.shape):
110
+ expr_cons_matrix[idx] = self[idx] <= other
111
+
112
+ elif isinstance(other, np.ndarray):
113
+ for idx in np.ndindex(self.shape):
114
+ expr_cons_matrix[idx] = self[idx] <= other[idx]
115
+ else:
116
+ raise TypeError(f"Unsupported type {type(other)}")
117
+
118
+ return expr_cons_matrix.view(MatrixExprCons)
119
+
120
+ def __ge__(self, other: Union[float, int, Variable, MatrixExpr]) -> np.ndarray:
121
+
122
+ if not _is_number(other) or not isinstance(other, MatrixExpr):
123
+ raise TypeError('Ranged MatrixExprCons is not well defined!')
124
+
125
+ expr_cons_matrix = np.empty(self.shape, dtype=object)
126
+ if _is_number(other) or isinstance(other, Variable):
127
+ for idx in np.ndindex(self.shape):
128
+ expr_cons_matrix[idx] = self[idx] >= other
129
+
130
+ elif isinstance(other, np.ndarray):
131
+ for idx in np.ndindex(self.shape):
132
+ expr_cons_matrix[idx] = self[idx] >= other[idx]
133
+ else:
134
+ raise TypeError(f"Unsupported type {type(other)}")
135
+
136
+ return expr_cons_matrix.view(MatrixExprCons)
137
+
138
+ def __eq__(self, other):
139
+ raise TypeError