ayousanz commited on
Commit
6c98a85
·
verified ·
1 Parent(s): a9a4bd0

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .venv/Lib/site-packages/sklearn/datasets/tests/data/openml/id_561/api-v1-jdl-dn-cpu-l-2-dv-1.json.gz +3 -0
  2. .venv/Lib/site-packages/sklearn/datasets/tests/data/openml/id_61/data-v1-dl-61.arff.gz +3 -0
  3. .venv/Lib/site-packages/sympy/plotting/__pycache__/__init__.cpython-39.pyc +0 -0
  4. .venv/Lib/site-packages/sympy/plotting/__pycache__/plot.cpython-39.pyc +0 -0
  5. .venv/Lib/site-packages/sympy/plotting/__pycache__/plot_implicit.cpython-39.pyc +0 -0
  6. .venv/Lib/site-packages/sympy/plotting/__pycache__/plotgrid.cpython-39.pyc +0 -0
  7. .venv/Lib/site-packages/sympy/plotting/__pycache__/series.cpython-39.pyc +0 -0
  8. .venv/Lib/site-packages/sympy/plotting/__pycache__/textplot.cpython-39.pyc +0 -0
  9. .venv/Lib/site-packages/sympy/plotting/__pycache__/utils.cpython-39.pyc +0 -0
  10. .venv/Lib/site-packages/sympy/plotting/backends/__pycache__/__init__.cpython-39.pyc +0 -0
  11. .venv/Lib/site-packages/sympy/plotting/backends/__pycache__/base_backend.cpython-39.pyc +0 -0
  12. .venv/Lib/site-packages/sympy/plotting/backends/matplotlibbackend/__init__.py +5 -0
  13. .venv/Lib/site-packages/sympy/plotting/backends/matplotlibbackend/__pycache__/__init__.cpython-39.pyc +0 -0
  14. .venv/Lib/site-packages/sympy/plotting/backends/matplotlibbackend/__pycache__/matplotlib.cpython-39.pyc +0 -0
  15. .venv/Lib/site-packages/sympy/plotting/backends/textbackend/__init__.py +3 -0
  16. .venv/Lib/site-packages/sympy/plotting/backends/textbackend/__pycache__/__init__.cpython-39.pyc +0 -0
  17. .venv/Lib/site-packages/sympy/plotting/backends/textbackend/__pycache__/text.cpython-39.pyc +0 -0
  18. .venv/Lib/site-packages/sympy/plotting/backends/textbackend/text.py +24 -0
  19. .venv/Lib/site-packages/sympy/plotting/intervalmath/__init__.py +12 -0
  20. .venv/Lib/site-packages/sympy/plotting/intervalmath/__pycache__/__init__.cpython-39.pyc +0 -0
  21. .venv/Lib/site-packages/sympy/plotting/intervalmath/__pycache__/interval_arithmetic.cpython-39.pyc +0 -0
  22. .venv/Lib/site-packages/sympy/plotting/intervalmath/__pycache__/interval_membership.cpython-39.pyc +0 -0
  23. .venv/Lib/site-packages/sympy/plotting/intervalmath/__pycache__/lib_interval.cpython-39.pyc +0 -0
  24. .venv/Lib/site-packages/sympy/plotting/intervalmath/interval_arithmetic.py +413 -0
  25. .venv/Lib/site-packages/sympy/plotting/intervalmath/interval_membership.py +78 -0
  26. .venv/Lib/site-packages/sympy/plotting/intervalmath/lib_interval.py +452 -0
  27. .venv/Lib/site-packages/sympy/plotting/intervalmath/tests/__init__.py +0 -0
  28. .venv/Lib/site-packages/sympy/plotting/intervalmath/tests/test_interval_functions.py +415 -0
  29. .venv/Lib/site-packages/sympy/plotting/intervalmath/tests/test_interval_membership.py +150 -0
  30. .venv/Lib/site-packages/sympy/plotting/intervalmath/tests/test_intervalmath.py +213 -0
  31. .venv/Lib/site-packages/sympy/plotting/pygletplot/__init__.py +138 -0
  32. .venv/Lib/site-packages/sympy/plotting/pygletplot/__pycache__/__init__.cpython-39.pyc +0 -0
  33. .venv/Lib/site-packages/sympy/plotting/pygletplot/color_scheme.py +336 -0
  34. .venv/Lib/site-packages/sympy/plotting/pygletplot/managed_window.py +106 -0
  35. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot.py +464 -0
  36. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_axes.py +251 -0
  37. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_camera.py +124 -0
  38. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_controller.py +218 -0
  39. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_curve.py +82 -0
  40. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_interval.py +181 -0
  41. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_mode.py +400 -0
  42. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_mode_base.py +378 -0
  43. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_modes.py +209 -0
  44. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_object.py +17 -0
  45. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_rotation.py +68 -0
  46. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_surface.py +102 -0
  47. .venv/Lib/site-packages/sympy/plotting/pygletplot/plot_window.py +144 -0
  48. .venv/Lib/site-packages/sympy/plotting/pygletplot/tests/__init__.py +0 -0
  49. .venv/Lib/site-packages/sympy/plotting/pygletplot/tests/test_plotting.py +88 -0
  50. .venv/Lib/site-packages/sympy/plotting/pygletplot/util.py +188 -0
.venv/Lib/site-packages/sklearn/datasets/tests/data/openml/id_561/api-v1-jdl-dn-cpu-l-2-dv-1.json.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0703b0ae20b9ff75087dc601640ee58f1c2ad6768858ea21a245151da9ba8e4c
3
+ size 301
.venv/Lib/site-packages/sklearn/datasets/tests/data/openml/id_61/data-v1-dl-61.arff.gz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:afe4736924606638984e573235191025d419c545d31dc8874c96b72f5ec5db73
3
+ size 2342
.venv/Lib/site-packages/sympy/plotting/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (603 Bytes). View file
 
.venv/Lib/site-packages/sympy/plotting/__pycache__/plot.cpython-39.pyc ADDED
Binary file (37.1 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/__pycache__/plot_implicit.cpython-39.pyc ADDED
Binary file (7.45 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/__pycache__/plotgrid.cpython-39.pyc ADDED
Binary file (6.6 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/__pycache__/series.cpython-39.pyc ADDED
Binary file (78.1 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/__pycache__/textplot.cpython-39.pyc ADDED
Binary file (4.75 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/__pycache__/utils.cpython-39.pyc ADDED
Binary file (11.3 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/backends/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (195 Bytes). View file
 
.venv/Lib/site-packages/sympy/plotting/backends/__pycache__/base_backend.cpython-39.pyc ADDED
Binary file (15.1 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/backends/matplotlibbackend/__init__.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from sympy.plotting.backends.matplotlibbackend.matplotlib import (
2
+ MatplotlibBackend, _matplotlib_list
3
+ )
4
+
5
+ __all__ = ["MatplotlibBackend", "_matplotlib_list"]
.venv/Lib/site-packages/sympy/plotting/backends/matplotlibbackend/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (363 Bytes). View file
 
.venv/Lib/site-packages/sympy/plotting/backends/matplotlibbackend/__pycache__/matplotlib.cpython-39.pyc ADDED
Binary file (8.53 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/backends/textbackend/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ from sympy.plotting.backends.textbackend.text import TextBackend
2
+
3
+ __all__ = ["TextBackend"]
.venv/Lib/site-packages/sympy/plotting/backends/textbackend/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (305 Bytes). View file
 
.venv/Lib/site-packages/sympy/plotting/backends/textbackend/__pycache__/text.cpython-39.pyc ADDED
Binary file (1.33 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/backends/textbackend/text.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sympy.plotting.backends.base_backend as base_backend
2
+ from sympy.plotting.series import LineOver1DRangeSeries
3
+ from sympy.plotting.textplot import textplot
4
+
5
+
6
+ class TextBackend(base_backend.Plot):
7
+ def __init__(self, *args, **kwargs):
8
+ super().__init__(*args, **kwargs)
9
+
10
+ def show(self):
11
+ if not base_backend._show:
12
+ return
13
+ if len(self._series) != 1:
14
+ raise ValueError(
15
+ 'The TextBackend supports only one graph per Plot.')
16
+ elif not isinstance(self._series[0], LineOver1DRangeSeries):
17
+ raise ValueError(
18
+ 'The TextBackend supports only expressions over a 1D range')
19
+ else:
20
+ ser = self._series[0]
21
+ textplot(ser.expr, ser.start, ser.end)
22
+
23
+ def close(self):
24
+ pass
.venv/Lib/site-packages/sympy/plotting/intervalmath/__init__.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .interval_arithmetic import interval
2
+ from .lib_interval import (Abs, exp, log, log10, sin, cos, tan, sqrt,
3
+ imin, imax, sinh, cosh, tanh, acosh, asinh, atanh,
4
+ asin, acos, atan, ceil, floor, And, Or)
5
+
6
+ __all__ = [
7
+ 'interval',
8
+
9
+ 'Abs', 'exp', 'log', 'log10', 'sin', 'cos', 'tan', 'sqrt', 'imin', 'imax',
10
+ 'sinh', 'cosh', 'tanh', 'acosh', 'asinh', 'atanh', 'asin', 'acos', 'atan',
11
+ 'ceil', 'floor', 'And', 'Or',
12
+ ]
.venv/Lib/site-packages/sympy/plotting/intervalmath/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (759 Bytes). View file
 
.venv/Lib/site-packages/sympy/plotting/intervalmath/__pycache__/interval_arithmetic.cpython-39.pyc ADDED
Binary file (9.58 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/intervalmath/__pycache__/interval_membership.cpython-39.pyc ADDED
Binary file (3.18 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/intervalmath/__pycache__/lib_interval.cpython-39.pyc ADDED
Binary file (11 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/intervalmath/interval_arithmetic.py ADDED
@@ -0,0 +1,413 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Interval Arithmetic for plotting.
3
+ This module does not implement interval arithmetic accurately and
4
+ hence cannot be used for purposes other than plotting. If you want
5
+ to use interval arithmetic, use mpmath's interval arithmetic.
6
+
7
+ The module implements interval arithmetic using numpy and
8
+ python floating points. The rounding up and down is not handled
9
+ and hence this is not an accurate implementation of interval
10
+ arithmetic.
11
+
12
+ The module uses numpy for speed which cannot be achieved with mpmath.
13
+ """
14
+
15
+ # Q: Why use numpy? Why not simply use mpmath's interval arithmetic?
16
+ # A: mpmath's interval arithmetic simulates a floating point unit
17
+ # and hence is slow, while numpy evaluations are orders of magnitude
18
+ # faster.
19
+
20
+ # Q: Why create a separate class for intervals? Why not use SymPy's
21
+ # Interval Sets?
22
+ # A: The functionalities that will be required for plotting is quite
23
+ # different from what Interval Sets implement.
24
+
25
+ # Q: Why is rounding up and down according to IEEE754 not handled?
26
+ # A: It is not possible to do it in both numpy and python. An external
27
+ # library has to used, which defeats the whole purpose i.e., speed. Also
28
+ # rounding is handled for very few functions in those libraries.
29
+
30
+ # Q Will my plots be affected?
31
+ # A It will not affect most of the plots. The interval arithmetic
32
+ # module based suffers the same problems as that of floating point
33
+ # arithmetic.
34
+
35
+ from sympy.core.numbers import int_valued
36
+ from sympy.core.logic import fuzzy_and
37
+ from sympy.simplify.simplify import nsimplify
38
+
39
+ from .interval_membership import intervalMembership
40
+
41
+
42
+ class interval:
43
+ """ Represents an interval containing floating points as start and
44
+ end of the interval
45
+ The is_valid variable tracks whether the interval obtained as the
46
+ result of the function is in the domain and is continuous.
47
+ - True: Represents the interval result of a function is continuous and
48
+ in the domain of the function.
49
+ - False: The interval argument of the function was not in the domain of
50
+ the function, hence the is_valid of the result interval is False
51
+ - None: The function was not continuous over the interval or
52
+ the function's argument interval is partly in the domain of the
53
+ function
54
+
55
+ A comparison between an interval and a real number, or a
56
+ comparison between two intervals may return ``intervalMembership``
57
+ of two 3-valued logic values.
58
+ """
59
+
60
+ def __init__(self, *args, is_valid=True, **kwargs):
61
+ self.is_valid = is_valid
62
+ if len(args) == 1:
63
+ if isinstance(args[0], interval):
64
+ self.start, self.end = args[0].start, args[0].end
65
+ else:
66
+ self.start = float(args[0])
67
+ self.end = float(args[0])
68
+ elif len(args) == 2:
69
+ if args[0] < args[1]:
70
+ self.start = float(args[0])
71
+ self.end = float(args[1])
72
+ else:
73
+ self.start = float(args[1])
74
+ self.end = float(args[0])
75
+
76
+ else:
77
+ raise ValueError("interval takes a maximum of two float values "
78
+ "as arguments")
79
+
80
+ @property
81
+ def mid(self):
82
+ return (self.start + self.end) / 2.0
83
+
84
+ @property
85
+ def width(self):
86
+ return self.end - self.start
87
+
88
+ def __repr__(self):
89
+ return "interval(%f, %f)" % (self.start, self.end)
90
+
91
+ def __str__(self):
92
+ return "[%f, %f]" % (self.start, self.end)
93
+
94
+ def __lt__(self, other):
95
+ if isinstance(other, (int, float)):
96
+ if self.end < other:
97
+ return intervalMembership(True, self.is_valid)
98
+ elif self.start > other:
99
+ return intervalMembership(False, self.is_valid)
100
+ else:
101
+ return intervalMembership(None, self.is_valid)
102
+
103
+ elif isinstance(other, interval):
104
+ valid = fuzzy_and([self.is_valid, other.is_valid])
105
+ if self.end < other. start:
106
+ return intervalMembership(True, valid)
107
+ if self.start > other.end:
108
+ return intervalMembership(False, valid)
109
+ return intervalMembership(None, valid)
110
+ else:
111
+ return NotImplemented
112
+
113
+ def __gt__(self, other):
114
+ if isinstance(other, (int, float)):
115
+ if self.start > other:
116
+ return intervalMembership(True, self.is_valid)
117
+ elif self.end < other:
118
+ return intervalMembership(False, self.is_valid)
119
+ else:
120
+ return intervalMembership(None, self.is_valid)
121
+ elif isinstance(other, interval):
122
+ return other.__lt__(self)
123
+ else:
124
+ return NotImplemented
125
+
126
+ def __eq__(self, other):
127
+ if isinstance(other, (int, float)):
128
+ if self.start == other and self.end == other:
129
+ return intervalMembership(True, self.is_valid)
130
+ if other in self:
131
+ return intervalMembership(None, self.is_valid)
132
+ else:
133
+ return intervalMembership(False, self.is_valid)
134
+
135
+ if isinstance(other, interval):
136
+ valid = fuzzy_and([self.is_valid, other.is_valid])
137
+ if self.start == other.start and self.end == other.end:
138
+ return intervalMembership(True, valid)
139
+ elif self.__lt__(other)[0] is not None:
140
+ return intervalMembership(False, valid)
141
+ else:
142
+ return intervalMembership(None, valid)
143
+ else:
144
+ return NotImplemented
145
+
146
+ def __ne__(self, other):
147
+ if isinstance(other, (int, float)):
148
+ if self.start == other and self.end == other:
149
+ return intervalMembership(False, self.is_valid)
150
+ if other in self:
151
+ return intervalMembership(None, self.is_valid)
152
+ else:
153
+ return intervalMembership(True, self.is_valid)
154
+
155
+ if isinstance(other, interval):
156
+ valid = fuzzy_and([self.is_valid, other.is_valid])
157
+ if self.start == other.start and self.end == other.end:
158
+ return intervalMembership(False, valid)
159
+ if not self.__lt__(other)[0] is None:
160
+ return intervalMembership(True, valid)
161
+ return intervalMembership(None, valid)
162
+ else:
163
+ return NotImplemented
164
+
165
+ def __le__(self, other):
166
+ if isinstance(other, (int, float)):
167
+ if self.end <= other:
168
+ return intervalMembership(True, self.is_valid)
169
+ if self.start > other:
170
+ return intervalMembership(False, self.is_valid)
171
+ else:
172
+ return intervalMembership(None, self.is_valid)
173
+
174
+ if isinstance(other, interval):
175
+ valid = fuzzy_and([self.is_valid, other.is_valid])
176
+ if self.end <= other.start:
177
+ return intervalMembership(True, valid)
178
+ if self.start > other.end:
179
+ return intervalMembership(False, valid)
180
+ return intervalMembership(None, valid)
181
+ else:
182
+ return NotImplemented
183
+
184
+ def __ge__(self, other):
185
+ if isinstance(other, (int, float)):
186
+ if self.start >= other:
187
+ return intervalMembership(True, self.is_valid)
188
+ elif self.end < other:
189
+ return intervalMembership(False, self.is_valid)
190
+ else:
191
+ return intervalMembership(None, self.is_valid)
192
+ elif isinstance(other, interval):
193
+ return other.__le__(self)
194
+
195
+ def __add__(self, other):
196
+ if isinstance(other, (int, float)):
197
+ if self.is_valid:
198
+ return interval(self.start + other, self.end + other)
199
+ else:
200
+ start = self.start + other
201
+ end = self.end + other
202
+ return interval(start, end, is_valid=self.is_valid)
203
+
204
+ elif isinstance(other, interval):
205
+ start = self.start + other.start
206
+ end = self.end + other.end
207
+ valid = fuzzy_and([self.is_valid, other.is_valid])
208
+ return interval(start, end, is_valid=valid)
209
+ else:
210
+ return NotImplemented
211
+
212
+ __radd__ = __add__
213
+
214
+ def __sub__(self, other):
215
+ if isinstance(other, (int, float)):
216
+ start = self.start - other
217
+ end = self.end - other
218
+ return interval(start, end, is_valid=self.is_valid)
219
+
220
+ elif isinstance(other, interval):
221
+ start = self.start - other.end
222
+ end = self.end - other.start
223
+ valid = fuzzy_and([self.is_valid, other.is_valid])
224
+ return interval(start, end, is_valid=valid)
225
+ else:
226
+ return NotImplemented
227
+
228
+ def __rsub__(self, other):
229
+ if isinstance(other, (int, float)):
230
+ start = other - self.end
231
+ end = other - self.start
232
+ return interval(start, end, is_valid=self.is_valid)
233
+ elif isinstance(other, interval):
234
+ return other.__sub__(self)
235
+ else:
236
+ return NotImplemented
237
+
238
+ def __neg__(self):
239
+ if self.is_valid:
240
+ return interval(-self.end, -self.start)
241
+ else:
242
+ return interval(-self.end, -self.start, is_valid=self.is_valid)
243
+
244
+ def __mul__(self, other):
245
+ if isinstance(other, interval):
246
+ if self.is_valid is False or other.is_valid is False:
247
+ return interval(-float('inf'), float('inf'), is_valid=False)
248
+ elif self.is_valid is None or other.is_valid is None:
249
+ return interval(-float('inf'), float('inf'), is_valid=None)
250
+ else:
251
+ inters = []
252
+ inters.append(self.start * other.start)
253
+ inters.append(self.end * other.start)
254
+ inters.append(self.start * other.end)
255
+ inters.append(self.end * other.end)
256
+ start = min(inters)
257
+ end = max(inters)
258
+ return interval(start, end)
259
+ elif isinstance(other, (int, float)):
260
+ return interval(self.start*other, self.end*other, is_valid=self.is_valid)
261
+ else:
262
+ return NotImplemented
263
+
264
+ __rmul__ = __mul__
265
+
266
+ def __contains__(self, other):
267
+ if isinstance(other, (int, float)):
268
+ return self.start <= other and self.end >= other
269
+ else:
270
+ return self.start <= other.start and other.end <= self.end
271
+
272
+ def __rtruediv__(self, other):
273
+ if isinstance(other, (int, float)):
274
+ other = interval(other)
275
+ return other.__truediv__(self)
276
+ elif isinstance(other, interval):
277
+ return other.__truediv__(self)
278
+ else:
279
+ return NotImplemented
280
+
281
+ def __truediv__(self, other):
282
+ # Both None and False are handled
283
+ if not self.is_valid:
284
+ # Don't divide as the value is not valid
285
+ return interval(-float('inf'), float('inf'), is_valid=self.is_valid)
286
+ if isinstance(other, (int, float)):
287
+ if other == 0:
288
+ # Divide by zero encountered. valid nowhere
289
+ return interval(-float('inf'), float('inf'), is_valid=False)
290
+ else:
291
+ return interval(self.start / other, self.end / other)
292
+
293
+ elif isinstance(other, interval):
294
+ if other.is_valid is False or self.is_valid is False:
295
+ return interval(-float('inf'), float('inf'), is_valid=False)
296
+ elif other.is_valid is None or self.is_valid is None:
297
+ return interval(-float('inf'), float('inf'), is_valid=None)
298
+ else:
299
+ # denominator contains both signs, i.e. being divided by zero
300
+ # return the whole real line with is_valid = None
301
+ if 0 in other:
302
+ return interval(-float('inf'), float('inf'), is_valid=None)
303
+
304
+ # denominator negative
305
+ this = self
306
+ if other.end < 0:
307
+ this = -this
308
+ other = -other
309
+
310
+ # denominator positive
311
+ inters = []
312
+ inters.append(this.start / other.start)
313
+ inters.append(this.end / other.start)
314
+ inters.append(this.start / other.end)
315
+ inters.append(this.end / other.end)
316
+ start = max(inters)
317
+ end = min(inters)
318
+ return interval(start, end)
319
+ else:
320
+ return NotImplemented
321
+
322
+ def __pow__(self, other):
323
+ # Implements only power to an integer.
324
+ from .lib_interval import exp, log
325
+ if not self.is_valid:
326
+ return self
327
+ if isinstance(other, interval):
328
+ return exp(other * log(self))
329
+ elif isinstance(other, (float, int)):
330
+ if other < 0:
331
+ return 1 / self.__pow__(abs(other))
332
+ else:
333
+ if int_valued(other):
334
+ return _pow_int(self, other)
335
+ else:
336
+ return _pow_float(self, other)
337
+ else:
338
+ return NotImplemented
339
+
340
+ def __rpow__(self, other):
341
+ if isinstance(other, (float, int)):
342
+ if not self.is_valid:
343
+ #Don't do anything
344
+ return self
345
+ elif other < 0:
346
+ if self.width > 0:
347
+ return interval(-float('inf'), float('inf'), is_valid=False)
348
+ else:
349
+ power_rational = nsimplify(self.start)
350
+ num, denom = power_rational.as_numer_denom()
351
+ if denom % 2 == 0:
352
+ return interval(-float('inf'), float('inf'),
353
+ is_valid=False)
354
+ else:
355
+ start = -abs(other)**self.start
356
+ end = start
357
+ return interval(start, end)
358
+ else:
359
+ return interval(other**self.start, other**self.end)
360
+ elif isinstance(other, interval):
361
+ return other.__pow__(self)
362
+ else:
363
+ return NotImplemented
364
+
365
+ def __hash__(self):
366
+ return hash((self.is_valid, self.start, self.end))
367
+
368
+
369
+ def _pow_float(inter, power):
370
+ """Evaluates an interval raised to a floating point."""
371
+ power_rational = nsimplify(power)
372
+ num, denom = power_rational.as_numer_denom()
373
+ if num % 2 == 0:
374
+ start = abs(inter.start)**power
375
+ end = abs(inter.end)**power
376
+ if start < 0:
377
+ ret = interval(0, max(start, end))
378
+ else:
379
+ ret = interval(start, end)
380
+ return ret
381
+ elif denom % 2 == 0:
382
+ if inter.end < 0:
383
+ return interval(-float('inf'), float('inf'), is_valid=False)
384
+ elif inter.start < 0:
385
+ return interval(0, inter.end**power, is_valid=None)
386
+ else:
387
+ return interval(inter.start**power, inter.end**power)
388
+ else:
389
+ if inter.start < 0:
390
+ start = -abs(inter.start)**power
391
+ else:
392
+ start = inter.start**power
393
+
394
+ if inter.end < 0:
395
+ end = -abs(inter.end)**power
396
+ else:
397
+ end = inter.end**power
398
+
399
+ return interval(start, end, is_valid=inter.is_valid)
400
+
401
+
402
+ def _pow_int(inter, power):
403
+ """Evaluates an interval raised to an integer power"""
404
+ power = int(power)
405
+ if power & 1:
406
+ return interval(inter.start**power, inter.end**power)
407
+ else:
408
+ if inter.start < 0 and inter.end > 0:
409
+ start = 0
410
+ end = max(inter.start**power, inter.end**power)
411
+ return interval(start, end)
412
+ else:
413
+ return interval(inter.start**power, inter.end**power)
.venv/Lib/site-packages/sympy/plotting/intervalmath/interval_membership.py ADDED
@@ -0,0 +1,78 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.logic import fuzzy_and, fuzzy_or, fuzzy_not, fuzzy_xor
2
+
3
+
4
+ class intervalMembership:
5
+ """Represents a boolean expression returned by the comparison of
6
+ the interval object.
7
+
8
+ Parameters
9
+ ==========
10
+
11
+ (a, b) : (bool, bool)
12
+ The first value determines the comparison as follows:
13
+ - True: If the comparison is True throughout the intervals.
14
+ - False: If the comparison is False throughout the intervals.
15
+ - None: If the comparison is True for some part of the intervals.
16
+
17
+ The second value is determined as follows:
18
+ - True: If both the intervals in comparison are valid.
19
+ - False: If at least one of the intervals is False, else
20
+ - None
21
+ """
22
+ def __init__(self, a, b):
23
+ self._wrapped = (a, b)
24
+
25
+ def __getitem__(self, i):
26
+ try:
27
+ return self._wrapped[i]
28
+ except IndexError:
29
+ raise IndexError(
30
+ "{} must be a valid indexing for the 2-tuple."
31
+ .format(i))
32
+
33
+ def __len__(self):
34
+ return 2
35
+
36
+ def __iter__(self):
37
+ return iter(self._wrapped)
38
+
39
+ def __str__(self):
40
+ return "intervalMembership({}, {})".format(*self)
41
+ __repr__ = __str__
42
+
43
+ def __and__(self, other):
44
+ if not isinstance(other, intervalMembership):
45
+ raise ValueError(
46
+ "The comparison is not supported for {}.".format(other))
47
+
48
+ a1, b1 = self
49
+ a2, b2 = other
50
+ return intervalMembership(fuzzy_and([a1, a2]), fuzzy_and([b1, b2]))
51
+
52
+ def __or__(self, other):
53
+ if not isinstance(other, intervalMembership):
54
+ raise ValueError(
55
+ "The comparison is not supported for {}.".format(other))
56
+
57
+ a1, b1 = self
58
+ a2, b2 = other
59
+ return intervalMembership(fuzzy_or([a1, a2]), fuzzy_and([b1, b2]))
60
+
61
+ def __invert__(self):
62
+ a, b = self
63
+ return intervalMembership(fuzzy_not(a), b)
64
+
65
+ def __xor__(self, other):
66
+ if not isinstance(other, intervalMembership):
67
+ raise ValueError(
68
+ "The comparison is not supported for {}.".format(other))
69
+
70
+ a1, b1 = self
71
+ a2, b2 = other
72
+ return intervalMembership(fuzzy_xor([a1, a2]), fuzzy_and([b1, b2]))
73
+
74
+ def __eq__(self, other):
75
+ return self._wrapped == other
76
+
77
+ def __ne__(self, other):
78
+ return self._wrapped != other
.venv/Lib/site-packages/sympy/plotting/intervalmath/lib_interval.py ADDED
@@ -0,0 +1,452 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ The module contains implemented functions for interval arithmetic."""
2
+ from functools import reduce
3
+
4
+ from sympy.plotting.intervalmath import interval
5
+ from sympy.external import import_module
6
+
7
+
8
+ def Abs(x):
9
+ if isinstance(x, (int, float)):
10
+ return interval(abs(x))
11
+ elif isinstance(x, interval):
12
+ if x.start < 0 and x.end > 0:
13
+ return interval(0, max(abs(x.start), abs(x.end)), is_valid=x.is_valid)
14
+ else:
15
+ return interval(abs(x.start), abs(x.end))
16
+ else:
17
+ raise NotImplementedError
18
+
19
+ #Monotonic
20
+
21
+
22
+ def exp(x):
23
+ """evaluates the exponential of an interval"""
24
+ np = import_module('numpy')
25
+ if isinstance(x, (int, float)):
26
+ return interval(np.exp(x), np.exp(x))
27
+ elif isinstance(x, interval):
28
+ return interval(np.exp(x.start), np.exp(x.end), is_valid=x.is_valid)
29
+ else:
30
+ raise NotImplementedError
31
+
32
+
33
+ #Monotonic
34
+ def log(x):
35
+ """evaluates the natural logarithm of an interval"""
36
+ np = import_module('numpy')
37
+ if isinstance(x, (int, float)):
38
+ if x <= 0:
39
+ return interval(-np.inf, np.inf, is_valid=False)
40
+ else:
41
+ return interval(np.log(x))
42
+ elif isinstance(x, interval):
43
+ if not x.is_valid:
44
+ return interval(-np.inf, np.inf, is_valid=x.is_valid)
45
+ elif x.end <= 0:
46
+ return interval(-np.inf, np.inf, is_valid=False)
47
+ elif x.start <= 0:
48
+ return interval(-np.inf, np.inf, is_valid=None)
49
+
50
+ return interval(np.log(x.start), np.log(x.end))
51
+ else:
52
+ raise NotImplementedError
53
+
54
+
55
+ #Monotonic
56
+ def log10(x):
57
+ """evaluates the logarithm to the base 10 of an interval"""
58
+ np = import_module('numpy')
59
+ if isinstance(x, (int, float)):
60
+ if x <= 0:
61
+ return interval(-np.inf, np.inf, is_valid=False)
62
+ else:
63
+ return interval(np.log10(x))
64
+ elif isinstance(x, interval):
65
+ if not x.is_valid:
66
+ return interval(-np.inf, np.inf, is_valid=x.is_valid)
67
+ elif x.end <= 0:
68
+ return interval(-np.inf, np.inf, is_valid=False)
69
+ elif x.start <= 0:
70
+ return interval(-np.inf, np.inf, is_valid=None)
71
+ return interval(np.log10(x.start), np.log10(x.end))
72
+ else:
73
+ raise NotImplementedError
74
+
75
+
76
+ #Monotonic
77
+ def atan(x):
78
+ """evaluates the tan inverse of an interval"""
79
+ np = import_module('numpy')
80
+ if isinstance(x, (int, float)):
81
+ return interval(np.arctan(x))
82
+ elif isinstance(x, interval):
83
+ start = np.arctan(x.start)
84
+ end = np.arctan(x.end)
85
+ return interval(start, end, is_valid=x.is_valid)
86
+ else:
87
+ raise NotImplementedError
88
+
89
+
90
+ #periodic
91
+ def sin(x):
92
+ """evaluates the sine of an interval"""
93
+ np = import_module('numpy')
94
+ if isinstance(x, (int, float)):
95
+ return interval(np.sin(x))
96
+ elif isinstance(x, interval):
97
+ if not x.is_valid:
98
+ return interval(-1, 1, is_valid=x.is_valid)
99
+ na, __ = divmod(x.start, np.pi / 2.0)
100
+ nb, __ = divmod(x.end, np.pi / 2.0)
101
+ start = min(np.sin(x.start), np.sin(x.end))
102
+ end = max(np.sin(x.start), np.sin(x.end))
103
+ if nb - na > 4:
104
+ return interval(-1, 1, is_valid=x.is_valid)
105
+ elif na == nb:
106
+ return interval(start, end, is_valid=x.is_valid)
107
+ else:
108
+ if (na - 1) // 4 != (nb - 1) // 4:
109
+ #sin has max
110
+ end = 1
111
+ if (na - 3) // 4 != (nb - 3) // 4:
112
+ #sin has min
113
+ start = -1
114
+ return interval(start, end)
115
+ else:
116
+ raise NotImplementedError
117
+
118
+
119
+ #periodic
120
+ def cos(x):
121
+ """Evaluates the cos of an interval"""
122
+ np = import_module('numpy')
123
+ if isinstance(x, (int, float)):
124
+ return interval(np.sin(x))
125
+ elif isinstance(x, interval):
126
+ if not (np.isfinite(x.start) and np.isfinite(x.end)):
127
+ return interval(-1, 1, is_valid=x.is_valid)
128
+ na, __ = divmod(x.start, np.pi / 2.0)
129
+ nb, __ = divmod(x.end, np.pi / 2.0)
130
+ start = min(np.cos(x.start), np.cos(x.end))
131
+ end = max(np.cos(x.start), np.cos(x.end))
132
+ if nb - na > 4:
133
+ #differ more than 2*pi
134
+ return interval(-1, 1, is_valid=x.is_valid)
135
+ elif na == nb:
136
+ #in the same quadarant
137
+ return interval(start, end, is_valid=x.is_valid)
138
+ else:
139
+ if (na) // 4 != (nb) // 4:
140
+ #cos has max
141
+ end = 1
142
+ if (na - 2) // 4 != (nb - 2) // 4:
143
+ #cos has min
144
+ start = -1
145
+ return interval(start, end, is_valid=x.is_valid)
146
+ else:
147
+ raise NotImplementedError
148
+
149
+
150
+ def tan(x):
151
+ """Evaluates the tan of an interval"""
152
+ return sin(x) / cos(x)
153
+
154
+
155
+ #Monotonic
156
+ def sqrt(x):
157
+ """Evaluates the square root of an interval"""
158
+ np = import_module('numpy')
159
+ if isinstance(x, (int, float)):
160
+ if x > 0:
161
+ return interval(np.sqrt(x))
162
+ else:
163
+ return interval(-np.inf, np.inf, is_valid=False)
164
+ elif isinstance(x, interval):
165
+ #Outside the domain
166
+ if x.end < 0:
167
+ return interval(-np.inf, np.inf, is_valid=False)
168
+ #Partially outside the domain
169
+ elif x.start < 0:
170
+ return interval(-np.inf, np.inf, is_valid=None)
171
+ else:
172
+ return interval(np.sqrt(x.start), np.sqrt(x.end),
173
+ is_valid=x.is_valid)
174
+ else:
175
+ raise NotImplementedError
176
+
177
+
178
+ def imin(*args):
179
+ """Evaluates the minimum of a list of intervals"""
180
+ np = import_module('numpy')
181
+ if not all(isinstance(arg, (int, float, interval)) for arg in args):
182
+ return NotImplementedError
183
+ else:
184
+ new_args = [a for a in args if isinstance(a, (int, float))
185
+ or a.is_valid]
186
+ if len(new_args) == 0:
187
+ if all(a.is_valid is False for a in args):
188
+ return interval(-np.inf, np.inf, is_valid=False)
189
+ else:
190
+ return interval(-np.inf, np.inf, is_valid=None)
191
+ start_array = [a if isinstance(a, (int, float)) else a.start
192
+ for a in new_args]
193
+
194
+ end_array = [a if isinstance(a, (int, float)) else a.end
195
+ for a in new_args]
196
+ return interval(min(start_array), min(end_array))
197
+
198
+
199
+ def imax(*args):
200
+ """Evaluates the maximum of a list of intervals"""
201
+ np = import_module('numpy')
202
+ if not all(isinstance(arg, (int, float, interval)) for arg in args):
203
+ return NotImplementedError
204
+ else:
205
+ new_args = [a for a in args if isinstance(a, (int, float))
206
+ or a.is_valid]
207
+ if len(new_args) == 0:
208
+ if all(a.is_valid is False for a in args):
209
+ return interval(-np.inf, np.inf, is_valid=False)
210
+ else:
211
+ return interval(-np.inf, np.inf, is_valid=None)
212
+ start_array = [a if isinstance(a, (int, float)) else a.start
213
+ for a in new_args]
214
+
215
+ end_array = [a if isinstance(a, (int, float)) else a.end
216
+ for a in new_args]
217
+
218
+ return interval(max(start_array), max(end_array))
219
+
220
+
221
+ #Monotonic
222
+ def sinh(x):
223
+ """Evaluates the hyperbolic sine of an interval"""
224
+ np = import_module('numpy')
225
+ if isinstance(x, (int, float)):
226
+ return interval(np.sinh(x), np.sinh(x))
227
+ elif isinstance(x, interval):
228
+ return interval(np.sinh(x.start), np.sinh(x.end), is_valid=x.is_valid)
229
+ else:
230
+ raise NotImplementedError
231
+
232
+
233
+ def cosh(x):
234
+ """Evaluates the hyperbolic cos of an interval"""
235
+ np = import_module('numpy')
236
+ if isinstance(x, (int, float)):
237
+ return interval(np.cosh(x), np.cosh(x))
238
+ elif isinstance(x, interval):
239
+ #both signs
240
+ if x.start < 0 and x.end > 0:
241
+ end = max(np.cosh(x.start), np.cosh(x.end))
242
+ return interval(1, end, is_valid=x.is_valid)
243
+ else:
244
+ #Monotonic
245
+ start = np.cosh(x.start)
246
+ end = np.cosh(x.end)
247
+ return interval(start, end, is_valid=x.is_valid)
248
+ else:
249
+ raise NotImplementedError
250
+
251
+
252
+ #Monotonic
253
+ def tanh(x):
254
+ """Evaluates the hyperbolic tan of an interval"""
255
+ np = import_module('numpy')
256
+ if isinstance(x, (int, float)):
257
+ return interval(np.tanh(x), np.tanh(x))
258
+ elif isinstance(x, interval):
259
+ return interval(np.tanh(x.start), np.tanh(x.end), is_valid=x.is_valid)
260
+ else:
261
+ raise NotImplementedError
262
+
263
+
264
+ def asin(x):
265
+ """Evaluates the inverse sine of an interval"""
266
+ np = import_module('numpy')
267
+ if isinstance(x, (int, float)):
268
+ #Outside the domain
269
+ if abs(x) > 1:
270
+ return interval(-np.inf, np.inf, is_valid=False)
271
+ else:
272
+ return interval(np.arcsin(x), np.arcsin(x))
273
+ elif isinstance(x, interval):
274
+ #Outside the domain
275
+ if x.is_valid is False or x.start > 1 or x.end < -1:
276
+ return interval(-np.inf, np.inf, is_valid=False)
277
+ #Partially outside the domain
278
+ elif x.start < -1 or x.end > 1:
279
+ return interval(-np.inf, np.inf, is_valid=None)
280
+ else:
281
+ start = np.arcsin(x.start)
282
+ end = np.arcsin(x.end)
283
+ return interval(start, end, is_valid=x.is_valid)
284
+
285
+
286
+ def acos(x):
287
+ """Evaluates the inverse cos of an interval"""
288
+ np = import_module('numpy')
289
+ if isinstance(x, (int, float)):
290
+ if abs(x) > 1:
291
+ #Outside the domain
292
+ return interval(-np.inf, np.inf, is_valid=False)
293
+ else:
294
+ return interval(np.arccos(x), np.arccos(x))
295
+ elif isinstance(x, interval):
296
+ #Outside the domain
297
+ if x.is_valid is False or x.start > 1 or x.end < -1:
298
+ return interval(-np.inf, np.inf, is_valid=False)
299
+ #Partially outside the domain
300
+ elif x.start < -1 or x.end > 1:
301
+ return interval(-np.inf, np.inf, is_valid=None)
302
+ else:
303
+ start = np.arccos(x.start)
304
+ end = np.arccos(x.end)
305
+ return interval(start, end, is_valid=x.is_valid)
306
+
307
+
308
+ def ceil(x):
309
+ """Evaluates the ceiling of an interval"""
310
+ np = import_module('numpy')
311
+ if isinstance(x, (int, float)):
312
+ return interval(np.ceil(x))
313
+ elif isinstance(x, interval):
314
+ if x.is_valid is False:
315
+ return interval(-np.inf, np.inf, is_valid=False)
316
+ else:
317
+ start = np.ceil(x.start)
318
+ end = np.ceil(x.end)
319
+ #Continuous over the interval
320
+ if start == end:
321
+ return interval(start, end, is_valid=x.is_valid)
322
+ else:
323
+ #Not continuous over the interval
324
+ return interval(start, end, is_valid=None)
325
+ else:
326
+ return NotImplementedError
327
+
328
+
329
+ def floor(x):
330
+ """Evaluates the floor of an interval"""
331
+ np = import_module('numpy')
332
+ if isinstance(x, (int, float)):
333
+ return interval(np.floor(x))
334
+ elif isinstance(x, interval):
335
+ if x.is_valid is False:
336
+ return interval(-np.inf, np.inf, is_valid=False)
337
+ else:
338
+ start = np.floor(x.start)
339
+ end = np.floor(x.end)
340
+ #continuous over the argument
341
+ if start == end:
342
+ return interval(start, end, is_valid=x.is_valid)
343
+ else:
344
+ #not continuous over the interval
345
+ return interval(start, end, is_valid=None)
346
+ else:
347
+ return NotImplementedError
348
+
349
+
350
+ def acosh(x):
351
+ """Evaluates the inverse hyperbolic cosine of an interval"""
352
+ np = import_module('numpy')
353
+ if isinstance(x, (int, float)):
354
+ #Outside the domain
355
+ if x < 1:
356
+ return interval(-np.inf, np.inf, is_valid=False)
357
+ else:
358
+ return interval(np.arccosh(x))
359
+ elif isinstance(x, interval):
360
+ #Outside the domain
361
+ if x.end < 1:
362
+ return interval(-np.inf, np.inf, is_valid=False)
363
+ #Partly outside the domain
364
+ elif x.start < 1:
365
+ return interval(-np.inf, np.inf, is_valid=None)
366
+ else:
367
+ start = np.arccosh(x.start)
368
+ end = np.arccosh(x.end)
369
+ return interval(start, end, is_valid=x.is_valid)
370
+ else:
371
+ return NotImplementedError
372
+
373
+
374
+ #Monotonic
375
+ def asinh(x):
376
+ """Evaluates the inverse hyperbolic sine of an interval"""
377
+ np = import_module('numpy')
378
+ if isinstance(x, (int, float)):
379
+ return interval(np.arcsinh(x))
380
+ elif isinstance(x, interval):
381
+ start = np.arcsinh(x.start)
382
+ end = np.arcsinh(x.end)
383
+ return interval(start, end, is_valid=x.is_valid)
384
+ else:
385
+ return NotImplementedError
386
+
387
+
388
+ def atanh(x):
389
+ """Evaluates the inverse hyperbolic tangent of an interval"""
390
+ np = import_module('numpy')
391
+ if isinstance(x, (int, float)):
392
+ #Outside the domain
393
+ if abs(x) >= 1:
394
+ return interval(-np.inf, np.inf, is_valid=False)
395
+ else:
396
+ return interval(np.arctanh(x))
397
+ elif isinstance(x, interval):
398
+ #outside the domain
399
+ if x.is_valid is False or x.start >= 1 or x.end <= -1:
400
+ return interval(-np.inf, np.inf, is_valid=False)
401
+ #partly outside the domain
402
+ elif x.start <= -1 or x.end >= 1:
403
+ return interval(-np.inf, np.inf, is_valid=None)
404
+ else:
405
+ start = np.arctanh(x.start)
406
+ end = np.arctanh(x.end)
407
+ return interval(start, end, is_valid=x.is_valid)
408
+ else:
409
+ return NotImplementedError
410
+
411
+
412
+ #Three valued logic for interval plotting.
413
+
414
+ def And(*args):
415
+ """Defines the three valued ``And`` behaviour for a 2-tuple of
416
+ three valued logic values"""
417
+ def reduce_and(cmp_intervala, cmp_intervalb):
418
+ if cmp_intervala[0] is False or cmp_intervalb[0] is False:
419
+ first = False
420
+ elif cmp_intervala[0] is None or cmp_intervalb[0] is None:
421
+ first = None
422
+ else:
423
+ first = True
424
+ if cmp_intervala[1] is False or cmp_intervalb[1] is False:
425
+ second = False
426
+ elif cmp_intervala[1] is None or cmp_intervalb[1] is None:
427
+ second = None
428
+ else:
429
+ second = True
430
+ return (first, second)
431
+ return reduce(reduce_and, args)
432
+
433
+
434
+ def Or(*args):
435
+ """Defines the three valued ``Or`` behaviour for a 2-tuple of
436
+ three valued logic values"""
437
+ def reduce_or(cmp_intervala, cmp_intervalb):
438
+ if cmp_intervala[0] is True or cmp_intervalb[0] is True:
439
+ first = True
440
+ elif cmp_intervala[0] is None or cmp_intervalb[0] is None:
441
+ first = None
442
+ else:
443
+ first = False
444
+
445
+ if cmp_intervala[1] is True or cmp_intervalb[1] is True:
446
+ second = True
447
+ elif cmp_intervala[1] is None or cmp_intervalb[1] is None:
448
+ second = None
449
+ else:
450
+ second = False
451
+ return (first, second)
452
+ return reduce(reduce_or, args)
.venv/Lib/site-packages/sympy/plotting/intervalmath/tests/__init__.py ADDED
File without changes
.venv/Lib/site-packages/sympy/plotting/intervalmath/tests/test_interval_functions.py ADDED
@@ -0,0 +1,415 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.external import import_module
2
+ from sympy.plotting.intervalmath import (
3
+ Abs, acos, acosh, And, asin, asinh, atan, atanh, ceil, cos, cosh,
4
+ exp, floor, imax, imin, interval, log, log10, Or, sin, sinh, sqrt,
5
+ tan, tanh,
6
+ )
7
+
8
+ np = import_module('numpy')
9
+ if not np:
10
+ disabled = True
11
+
12
+
13
+ #requires Numpy. Hence included in interval_functions
14
+
15
+
16
+ def test_interval_pow():
17
+ a = 2**interval(1, 2) == interval(2, 4)
18
+ assert a == (True, True)
19
+ a = interval(1, 2)**interval(1, 2) == interval(1, 4)
20
+ assert a == (True, True)
21
+ a = interval(-1, 1)**interval(0.5, 2)
22
+ assert a.is_valid is None
23
+ a = interval(-2, -1) ** interval(1, 2)
24
+ assert a.is_valid is False
25
+ a = interval(-2, -1) ** (1.0 / 2)
26
+ assert a.is_valid is False
27
+ a = interval(-1, 1)**(1.0 / 2)
28
+ assert a.is_valid is None
29
+ a = interval(-1, 1)**(1.0 / 3) == interval(-1, 1)
30
+ assert a == (True, True)
31
+ a = interval(-1, 1)**2 == interval(0, 1)
32
+ assert a == (True, True)
33
+ a = interval(-1, 1) ** (1.0 / 29) == interval(-1, 1)
34
+ assert a == (True, True)
35
+ a = -2**interval(1, 1) == interval(-2, -2)
36
+ assert a == (True, True)
37
+
38
+ a = interval(1, 2, is_valid=False)**2
39
+ assert a.is_valid is False
40
+
41
+ a = (-3)**interval(1, 2)
42
+ assert a.is_valid is False
43
+ a = (-4)**interval(0.5, 0.5)
44
+ assert a.is_valid is False
45
+ assert ((-3)**interval(1, 1) == interval(-3, -3)) == (True, True)
46
+
47
+ a = interval(8, 64)**(2.0 / 3)
48
+ assert abs(a.start - 4) < 1e-10 # eps
49
+ assert abs(a.end - 16) < 1e-10
50
+ a = interval(-8, 64)**(2.0 / 3)
51
+ assert abs(a.start - 4) < 1e-10 # eps
52
+ assert abs(a.end - 16) < 1e-10
53
+
54
+
55
+ def test_exp():
56
+ a = exp(interval(-np.inf, 0))
57
+ assert a.start == np.exp(-np.inf)
58
+ assert a.end == np.exp(0)
59
+ a = exp(interval(1, 2))
60
+ assert a.start == np.exp(1)
61
+ assert a.end == np.exp(2)
62
+ a = exp(1)
63
+ assert a.start == np.exp(1)
64
+ assert a.end == np.exp(1)
65
+
66
+
67
+ def test_log():
68
+ a = log(interval(1, 2))
69
+ assert a.start == 0
70
+ assert a.end == np.log(2)
71
+ a = log(interval(-1, 1))
72
+ assert a.is_valid is None
73
+ a = log(interval(-3, -1))
74
+ assert a.is_valid is False
75
+ a = log(-3)
76
+ assert a.is_valid is False
77
+ a = log(2)
78
+ assert a.start == np.log(2)
79
+ assert a.end == np.log(2)
80
+
81
+
82
+ def test_log10():
83
+ a = log10(interval(1, 2))
84
+ assert a.start == 0
85
+ assert a.end == np.log10(2)
86
+ a = log10(interval(-1, 1))
87
+ assert a.is_valid is None
88
+ a = log10(interval(-3, -1))
89
+ assert a.is_valid is False
90
+ a = log10(-3)
91
+ assert a.is_valid is False
92
+ a = log10(2)
93
+ assert a.start == np.log10(2)
94
+ assert a.end == np.log10(2)
95
+
96
+
97
+ def test_atan():
98
+ a = atan(interval(0, 1))
99
+ assert a.start == np.arctan(0)
100
+ assert a.end == np.arctan(1)
101
+ a = atan(1)
102
+ assert a.start == np.arctan(1)
103
+ assert a.end == np.arctan(1)
104
+
105
+
106
+ def test_sin():
107
+ a = sin(interval(0, np.pi / 4))
108
+ assert a.start == np.sin(0)
109
+ assert a.end == np.sin(np.pi / 4)
110
+
111
+ a = sin(interval(-np.pi / 4, np.pi / 4))
112
+ assert a.start == np.sin(-np.pi / 4)
113
+ assert a.end == np.sin(np.pi / 4)
114
+
115
+ a = sin(interval(np.pi / 4, 3 * np.pi / 4))
116
+ assert a.start == np.sin(np.pi / 4)
117
+ assert a.end == 1
118
+
119
+ a = sin(interval(7 * np.pi / 6, 7 * np.pi / 4))
120
+ assert a.start == -1
121
+ assert a.end == np.sin(7 * np.pi / 6)
122
+
123
+ a = sin(interval(0, 3 * np.pi))
124
+ assert a.start == -1
125
+ assert a.end == 1
126
+
127
+ a = sin(interval(np.pi / 3, 7 * np.pi / 4))
128
+ assert a.start == -1
129
+ assert a.end == 1
130
+
131
+ a = sin(np.pi / 4)
132
+ assert a.start == np.sin(np.pi / 4)
133
+ assert a.end == np.sin(np.pi / 4)
134
+
135
+ a = sin(interval(1, 2, is_valid=False))
136
+ assert a.is_valid is False
137
+
138
+
139
+ def test_cos():
140
+ a = cos(interval(0, np.pi / 4))
141
+ assert a.start == np.cos(np.pi / 4)
142
+ assert a.end == 1
143
+
144
+ a = cos(interval(-np.pi / 4, np.pi / 4))
145
+ assert a.start == np.cos(-np.pi / 4)
146
+ assert a.end == 1
147
+
148
+ a = cos(interval(np.pi / 4, 3 * np.pi / 4))
149
+ assert a.start == np.cos(3 * np.pi / 4)
150
+ assert a.end == np.cos(np.pi / 4)
151
+
152
+ a = cos(interval(3 * np.pi / 4, 5 * np.pi / 4))
153
+ assert a.start == -1
154
+ assert a.end == np.cos(3 * np.pi / 4)
155
+
156
+ a = cos(interval(0, 3 * np.pi))
157
+ assert a.start == -1
158
+ assert a.end == 1
159
+
160
+ a = cos(interval(- np.pi / 3, 5 * np.pi / 4))
161
+ assert a.start == -1
162
+ assert a.end == 1
163
+
164
+ a = cos(interval(1, 2, is_valid=False))
165
+ assert a.is_valid is False
166
+
167
+
168
+ def test_tan():
169
+ a = tan(interval(0, np.pi / 4))
170
+ assert a.start == 0
171
+ # must match lib_interval definition of tan:
172
+ assert a.end == np.sin(np.pi / 4)/np.cos(np.pi / 4)
173
+
174
+ a = tan(interval(np.pi / 4, 3 * np.pi / 4))
175
+ #discontinuity
176
+ assert a.is_valid is None
177
+
178
+
179
+ def test_sqrt():
180
+ a = sqrt(interval(1, 4))
181
+ assert a.start == 1
182
+ assert a.end == 2
183
+
184
+ a = sqrt(interval(0.01, 1))
185
+ assert a.start == np.sqrt(0.01)
186
+ assert a.end == 1
187
+
188
+ a = sqrt(interval(-1, 1))
189
+ assert a.is_valid is None
190
+
191
+ a = sqrt(interval(-3, -1))
192
+ assert a.is_valid is False
193
+
194
+ a = sqrt(4)
195
+ assert (a == interval(2, 2)) == (True, True)
196
+
197
+ a = sqrt(-3)
198
+ assert a.is_valid is False
199
+
200
+
201
+ def test_imin():
202
+ a = imin(interval(1, 3), interval(2, 5), interval(-1, 3))
203
+ assert a.start == -1
204
+ assert a.end == 3
205
+
206
+ a = imin(-2, interval(1, 4))
207
+ assert a.start == -2
208
+ assert a.end == -2
209
+
210
+ a = imin(5, interval(3, 4), interval(-2, 2, is_valid=False))
211
+ assert a.start == 3
212
+ assert a.end == 4
213
+
214
+
215
+ def test_imax():
216
+ a = imax(interval(-2, 2), interval(2, 7), interval(-3, 9))
217
+ assert a.start == 2
218
+ assert a.end == 9
219
+
220
+ a = imax(8, interval(1, 4))
221
+ assert a.start == 8
222
+ assert a.end == 8
223
+
224
+ a = imax(interval(1, 2), interval(3, 4), interval(-2, 2, is_valid=False))
225
+ assert a.start == 3
226
+ assert a.end == 4
227
+
228
+
229
+ def test_sinh():
230
+ a = sinh(interval(-1, 1))
231
+ assert a.start == np.sinh(-1)
232
+ assert a.end == np.sinh(1)
233
+
234
+ a = sinh(1)
235
+ assert a.start == np.sinh(1)
236
+ assert a.end == np.sinh(1)
237
+
238
+
239
+ def test_cosh():
240
+ a = cosh(interval(1, 2))
241
+ assert a.start == np.cosh(1)
242
+ assert a.end == np.cosh(2)
243
+ a = cosh(interval(-2, -1))
244
+ assert a.start == np.cosh(-1)
245
+ assert a.end == np.cosh(-2)
246
+
247
+ a = cosh(interval(-2, 1))
248
+ assert a.start == 1
249
+ assert a.end == np.cosh(-2)
250
+
251
+ a = cosh(1)
252
+ assert a.start == np.cosh(1)
253
+ assert a.end == np.cosh(1)
254
+
255
+
256
+ def test_tanh():
257
+ a = tanh(interval(-3, 3))
258
+ assert a.start == np.tanh(-3)
259
+ assert a.end == np.tanh(3)
260
+
261
+ a = tanh(3)
262
+ assert a.start == np.tanh(3)
263
+ assert a.end == np.tanh(3)
264
+
265
+
266
+ def test_asin():
267
+ a = asin(interval(-0.5, 0.5))
268
+ assert a.start == np.arcsin(-0.5)
269
+ assert a.end == np.arcsin(0.5)
270
+
271
+ a = asin(interval(-1.5, 1.5))
272
+ assert a.is_valid is None
273
+ a = asin(interval(-2, -1.5))
274
+ assert a.is_valid is False
275
+
276
+ a = asin(interval(0, 2))
277
+ assert a.is_valid is None
278
+
279
+ a = asin(interval(2, 5))
280
+ assert a.is_valid is False
281
+
282
+ a = asin(0.5)
283
+ assert a.start == np.arcsin(0.5)
284
+ assert a.end == np.arcsin(0.5)
285
+
286
+ a = asin(1.5)
287
+ assert a.is_valid is False
288
+
289
+
290
+ def test_acos():
291
+ a = acos(interval(-0.5, 0.5))
292
+ assert a.start == np.arccos(0.5)
293
+ assert a.end == np.arccos(-0.5)
294
+
295
+ a = acos(interval(-1.5, 1.5))
296
+ assert a.is_valid is None
297
+ a = acos(interval(-2, -1.5))
298
+ assert a.is_valid is False
299
+
300
+ a = acos(interval(0, 2))
301
+ assert a.is_valid is None
302
+
303
+ a = acos(interval(2, 5))
304
+ assert a.is_valid is False
305
+
306
+ a = acos(0.5)
307
+ assert a.start == np.arccos(0.5)
308
+ assert a.end == np.arccos(0.5)
309
+
310
+ a = acos(1.5)
311
+ assert a.is_valid is False
312
+
313
+
314
+ def test_ceil():
315
+ a = ceil(interval(0.2, 0.5))
316
+ assert a.start == 1
317
+ assert a.end == 1
318
+
319
+ a = ceil(interval(0.5, 1.5))
320
+ assert a.start == 1
321
+ assert a.end == 2
322
+ assert a.is_valid is None
323
+
324
+ a = ceil(interval(-5, 5))
325
+ assert a.is_valid is None
326
+
327
+ a = ceil(5.4)
328
+ assert a.start == 6
329
+ assert a.end == 6
330
+
331
+
332
+ def test_floor():
333
+ a = floor(interval(0.2, 0.5))
334
+ assert a.start == 0
335
+ assert a.end == 0
336
+
337
+ a = floor(interval(0.5, 1.5))
338
+ assert a.start == 0
339
+ assert a.end == 1
340
+ assert a.is_valid is None
341
+
342
+ a = floor(interval(-5, 5))
343
+ assert a.is_valid is None
344
+
345
+ a = floor(5.4)
346
+ assert a.start == 5
347
+ assert a.end == 5
348
+
349
+
350
+ def test_asinh():
351
+ a = asinh(interval(1, 2))
352
+ assert a.start == np.arcsinh(1)
353
+ assert a.end == np.arcsinh(2)
354
+
355
+ a = asinh(0.5)
356
+ assert a.start == np.arcsinh(0.5)
357
+ assert a.end == np.arcsinh(0.5)
358
+
359
+
360
+ def test_acosh():
361
+ a = acosh(interval(3, 5))
362
+ assert a.start == np.arccosh(3)
363
+ assert a.end == np.arccosh(5)
364
+
365
+ a = acosh(interval(0, 3))
366
+ assert a.is_valid is None
367
+ a = acosh(interval(-3, 0.5))
368
+ assert a.is_valid is False
369
+
370
+ a = acosh(0.5)
371
+ assert a.is_valid is False
372
+
373
+ a = acosh(2)
374
+ assert a.start == np.arccosh(2)
375
+ assert a.end == np.arccosh(2)
376
+
377
+
378
+ def test_atanh():
379
+ a = atanh(interval(-0.5, 0.5))
380
+ assert a.start == np.arctanh(-0.5)
381
+ assert a.end == np.arctanh(0.5)
382
+
383
+ a = atanh(interval(0, 3))
384
+ assert a.is_valid is None
385
+
386
+ a = atanh(interval(-3, -2))
387
+ assert a.is_valid is False
388
+
389
+ a = atanh(0.5)
390
+ assert a.start == np.arctanh(0.5)
391
+ assert a.end == np.arctanh(0.5)
392
+
393
+ a = atanh(1.5)
394
+ assert a.is_valid is False
395
+
396
+
397
+ def test_Abs():
398
+ assert (Abs(interval(-0.5, 0.5)) == interval(0, 0.5)) == (True, True)
399
+ assert (Abs(interval(-3, -2)) == interval(2, 3)) == (True, True)
400
+ assert (Abs(-3) == interval(3, 3)) == (True, True)
401
+
402
+
403
+ def test_And():
404
+ args = [(True, True), (True, False), (True, None)]
405
+ assert And(*args) == (True, False)
406
+
407
+ args = [(False, True), (None, None), (True, True)]
408
+ assert And(*args) == (False, None)
409
+
410
+
411
+ def test_Or():
412
+ args = [(True, True), (True, False), (False, None)]
413
+ assert Or(*args) == (True, True)
414
+ args = [(None, None), (False, None), (False, False)]
415
+ assert Or(*args) == (None, None)
.venv/Lib/site-packages/sympy/plotting/intervalmath/tests/test_interval_membership.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.symbol import Symbol
2
+ from sympy.plotting.intervalmath import interval
3
+ from sympy.plotting.intervalmath.interval_membership import intervalMembership
4
+ from sympy.plotting.experimental_lambdify import experimental_lambdify
5
+ from sympy.testing.pytest import raises
6
+
7
+
8
+ def test_creation():
9
+ assert intervalMembership(True, True)
10
+ raises(TypeError, lambda: intervalMembership(True))
11
+ raises(TypeError, lambda: intervalMembership(True, True, True))
12
+
13
+
14
+ def test_getitem():
15
+ a = intervalMembership(True, False)
16
+ assert a[0] is True
17
+ assert a[1] is False
18
+ raises(IndexError, lambda: a[2])
19
+
20
+
21
+ def test_str():
22
+ a = intervalMembership(True, False)
23
+ assert str(a) == 'intervalMembership(True, False)'
24
+ assert repr(a) == 'intervalMembership(True, False)'
25
+
26
+
27
+ def test_equivalence():
28
+ a = intervalMembership(True, True)
29
+ b = intervalMembership(True, False)
30
+ assert (a == b) is False
31
+ assert (a != b) is True
32
+
33
+ a = intervalMembership(True, False)
34
+ b = intervalMembership(True, False)
35
+ assert (a == b) is True
36
+ assert (a != b) is False
37
+
38
+
39
+ def test_not():
40
+ x = Symbol('x')
41
+
42
+ r1 = x > -1
43
+ r2 = x <= -1
44
+
45
+ i = interval
46
+
47
+ f1 = experimental_lambdify((x,), r1)
48
+ f2 = experimental_lambdify((x,), r2)
49
+
50
+ tt = i(-0.1, 0.1, is_valid=True)
51
+ tn = i(-0.1, 0.1, is_valid=None)
52
+ tf = i(-0.1, 0.1, is_valid=False)
53
+
54
+ assert f1(tt) == ~f2(tt)
55
+ assert f1(tn) == ~f2(tn)
56
+ assert f1(tf) == ~f2(tf)
57
+
58
+ nt = i(0.9, 1.1, is_valid=True)
59
+ nn = i(0.9, 1.1, is_valid=None)
60
+ nf = i(0.9, 1.1, is_valid=False)
61
+
62
+ assert f1(nt) == ~f2(nt)
63
+ assert f1(nn) == ~f2(nn)
64
+ assert f1(nf) == ~f2(nf)
65
+
66
+ ft = i(1.9, 2.1, is_valid=True)
67
+ fn = i(1.9, 2.1, is_valid=None)
68
+ ff = i(1.9, 2.1, is_valid=False)
69
+
70
+ assert f1(ft) == ~f2(ft)
71
+ assert f1(fn) == ~f2(fn)
72
+ assert f1(ff) == ~f2(ff)
73
+
74
+
75
+ def test_boolean():
76
+ # There can be 9*9 test cases in full mapping of the cartesian product.
77
+ # But we only consider 3*3 cases for simplicity.
78
+ s = [
79
+ intervalMembership(False, False),
80
+ intervalMembership(None, None),
81
+ intervalMembership(True, True)
82
+ ]
83
+
84
+ # Reduced tests for 'And'
85
+ a1 = [
86
+ intervalMembership(False, False),
87
+ intervalMembership(False, False),
88
+ intervalMembership(False, False),
89
+ intervalMembership(False, False),
90
+ intervalMembership(None, None),
91
+ intervalMembership(None, None),
92
+ intervalMembership(False, False),
93
+ intervalMembership(None, None),
94
+ intervalMembership(True, True)
95
+ ]
96
+ a1_iter = iter(a1)
97
+ for i in range(len(s)):
98
+ for j in range(len(s)):
99
+ assert s[i] & s[j] == next(a1_iter)
100
+
101
+ # Reduced tests for 'Or'
102
+ a1 = [
103
+ intervalMembership(False, False),
104
+ intervalMembership(None, False),
105
+ intervalMembership(True, False),
106
+ intervalMembership(None, False),
107
+ intervalMembership(None, None),
108
+ intervalMembership(True, None),
109
+ intervalMembership(True, False),
110
+ intervalMembership(True, None),
111
+ intervalMembership(True, True)
112
+ ]
113
+ a1_iter = iter(a1)
114
+ for i in range(len(s)):
115
+ for j in range(len(s)):
116
+ assert s[i] | s[j] == next(a1_iter)
117
+
118
+ # Reduced tests for 'Xor'
119
+ a1 = [
120
+ intervalMembership(False, False),
121
+ intervalMembership(None, False),
122
+ intervalMembership(True, False),
123
+ intervalMembership(None, False),
124
+ intervalMembership(None, None),
125
+ intervalMembership(None, None),
126
+ intervalMembership(True, False),
127
+ intervalMembership(None, None),
128
+ intervalMembership(False, True)
129
+ ]
130
+ a1_iter = iter(a1)
131
+ for i in range(len(s)):
132
+ for j in range(len(s)):
133
+ assert s[i] ^ s[j] == next(a1_iter)
134
+
135
+ # Reduced tests for 'Not'
136
+ a1 = [
137
+ intervalMembership(True, False),
138
+ intervalMembership(None, None),
139
+ intervalMembership(False, True)
140
+ ]
141
+ a1_iter = iter(a1)
142
+ for i in range(len(s)):
143
+ assert ~s[i] == next(a1_iter)
144
+
145
+
146
+ def test_boolean_errors():
147
+ a = intervalMembership(True, True)
148
+ raises(ValueError, lambda: a & 1)
149
+ raises(ValueError, lambda: a | 1)
150
+ raises(ValueError, lambda: a ^ 1)
.venv/Lib/site-packages/sympy/plotting/intervalmath/tests/test_intervalmath.py ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.plotting.intervalmath import interval
2
+ from sympy.testing.pytest import raises
3
+
4
+
5
+ def test_interval():
6
+ assert (interval(1, 1) == interval(1, 1, is_valid=True)) == (True, True)
7
+ assert (interval(1, 1) == interval(1, 1, is_valid=False)) == (True, False)
8
+ assert (interval(1, 1) == interval(1, 1, is_valid=None)) == (True, None)
9
+ assert (interval(1, 1.5) == interval(1, 2)) == (None, True)
10
+ assert (interval(0, 1) == interval(2, 3)) == (False, True)
11
+ assert (interval(0, 1) == interval(1, 2)) == (None, True)
12
+ assert (interval(1, 2) != interval(1, 2)) == (False, True)
13
+ assert (interval(1, 3) != interval(2, 3)) == (None, True)
14
+ assert (interval(1, 3) != interval(-5, -3)) == (True, True)
15
+ assert (
16
+ interval(1, 3, is_valid=False) != interval(-5, -3)) == (True, False)
17
+ assert (interval(1, 3, is_valid=None) != interval(-5, 3)) == (None, None)
18
+ assert (interval(4, 4) != 4) == (False, True)
19
+ assert (interval(1, 1) == 1) == (True, True)
20
+ assert (interval(1, 3, is_valid=False) == interval(1, 3)) == (True, False)
21
+ assert (interval(1, 3, is_valid=None) == interval(1, 3)) == (True, None)
22
+ inter = interval(-5, 5)
23
+ assert (interval(inter) == interval(-5, 5)) == (True, True)
24
+ assert inter.width == 10
25
+ assert 0 in inter
26
+ assert -5 in inter
27
+ assert 5 in inter
28
+ assert interval(0, 3) in inter
29
+ assert interval(-6, 2) not in inter
30
+ assert -5.05 not in inter
31
+ assert 5.3 not in inter
32
+ interb = interval(-float('inf'), float('inf'))
33
+ assert 0 in inter
34
+ assert inter in interb
35
+ assert interval(0, float('inf')) in interb
36
+ assert interval(-float('inf'), 5) in interb
37
+ assert interval(-1e50, 1e50) in interb
38
+ assert (
39
+ -interval(-1, -2, is_valid=False) == interval(1, 2)) == (True, False)
40
+ raises(ValueError, lambda: interval(1, 2, 3))
41
+
42
+
43
+ def test_interval_add():
44
+ assert (interval(1, 2) + interval(2, 3) == interval(3, 5)) == (True, True)
45
+ assert (1 + interval(1, 2) == interval(2, 3)) == (True, True)
46
+ assert (interval(1, 2) + 1 == interval(2, 3)) == (True, True)
47
+ compare = (1 + interval(0, float('inf')) == interval(1, float('inf')))
48
+ assert compare == (True, True)
49
+ a = 1 + interval(2, 5, is_valid=False)
50
+ assert a.is_valid is False
51
+ a = 1 + interval(2, 5, is_valid=None)
52
+ assert a.is_valid is None
53
+ a = interval(2, 5, is_valid=False) + interval(3, 5, is_valid=None)
54
+ assert a.is_valid is False
55
+ a = interval(3, 5) + interval(-1, 1, is_valid=None)
56
+ assert a.is_valid is None
57
+ a = interval(2, 5, is_valid=False) + 1
58
+ assert a.is_valid is False
59
+
60
+
61
+ def test_interval_sub():
62
+ assert (interval(1, 2) - interval(1, 5) == interval(-4, 1)) == (True, True)
63
+ assert (interval(1, 2) - 1 == interval(0, 1)) == (True, True)
64
+ assert (1 - interval(1, 2) == interval(-1, 0)) == (True, True)
65
+ a = 1 - interval(1, 2, is_valid=False)
66
+ assert a.is_valid is False
67
+ a = interval(1, 4, is_valid=None) - 1
68
+ assert a.is_valid is None
69
+ a = interval(1, 3, is_valid=False) - interval(1, 3)
70
+ assert a.is_valid is False
71
+ a = interval(1, 3, is_valid=None) - interval(1, 3)
72
+ assert a.is_valid is None
73
+
74
+
75
+ def test_interval_inequality():
76
+ assert (interval(1, 2) < interval(3, 4)) == (True, True)
77
+ assert (interval(1, 2) < interval(2, 4)) == (None, True)
78
+ assert (interval(1, 2) < interval(-2, 0)) == (False, True)
79
+ assert (interval(1, 2) <= interval(2, 4)) == (True, True)
80
+ assert (interval(1, 2) <= interval(1.5, 6)) == (None, True)
81
+ assert (interval(2, 3) <= interval(1, 2)) == (None, True)
82
+ assert (interval(2, 3) <= interval(1, 1.5)) == (False, True)
83
+ assert (
84
+ interval(1, 2, is_valid=False) <= interval(-2, 0)) == (False, False)
85
+ assert (interval(1, 2, is_valid=None) <= interval(-2, 0)) == (False, None)
86
+ assert (interval(1, 2) <= 1.5) == (None, True)
87
+ assert (interval(1, 2) <= 3) == (True, True)
88
+ assert (interval(1, 2) <= 0) == (False, True)
89
+ assert (interval(5, 8) > interval(2, 3)) == (True, True)
90
+ assert (interval(2, 5) > interval(1, 3)) == (None, True)
91
+ assert (interval(2, 3) > interval(3.1, 5)) == (False, True)
92
+
93
+ assert (interval(-1, 1) == 0) == (None, True)
94
+ assert (interval(-1, 1) == 2) == (False, True)
95
+ assert (interval(-1, 1) != 0) == (None, True)
96
+ assert (interval(-1, 1) != 2) == (True, True)
97
+
98
+ assert (interval(3, 5) > 2) == (True, True)
99
+ assert (interval(3, 5) < 2) == (False, True)
100
+ assert (interval(1, 5) < 2) == (None, True)
101
+ assert (interval(1, 5) > 2) == (None, True)
102
+ assert (interval(0, 1) > 2) == (False, True)
103
+ assert (interval(1, 2) >= interval(0, 1)) == (True, True)
104
+ assert (interval(1, 2) >= interval(0, 1.5)) == (None, True)
105
+ assert (interval(1, 2) >= interval(3, 4)) == (False, True)
106
+ assert (interval(1, 2) >= 0) == (True, True)
107
+ assert (interval(1, 2) >= 1.2) == (None, True)
108
+ assert (interval(1, 2) >= 3) == (False, True)
109
+ assert (2 > interval(0, 1)) == (True, True)
110
+ a = interval(-1, 1, is_valid=False) < interval(2, 5, is_valid=None)
111
+ assert a == (True, False)
112
+ a = interval(-1, 1, is_valid=None) < interval(2, 5, is_valid=False)
113
+ assert a == (True, False)
114
+ a = interval(-1, 1, is_valid=None) < interval(2, 5, is_valid=None)
115
+ assert a == (True, None)
116
+ a = interval(-1, 1, is_valid=False) > interval(-5, -2, is_valid=None)
117
+ assert a == (True, False)
118
+ a = interval(-1, 1, is_valid=None) > interval(-5, -2, is_valid=False)
119
+ assert a == (True, False)
120
+ a = interval(-1, 1, is_valid=None) > interval(-5, -2, is_valid=None)
121
+ assert a == (True, None)
122
+
123
+
124
+ def test_interval_mul():
125
+ assert (
126
+ interval(1, 5) * interval(2, 10) == interval(2, 50)) == (True, True)
127
+ a = interval(-1, 1) * interval(2, 10) == interval(-10, 10)
128
+ assert a == (True, True)
129
+
130
+ a = interval(-1, 1) * interval(-5, 3) == interval(-5, 5)
131
+ assert a == (True, True)
132
+
133
+ assert (interval(1, 3) * 2 == interval(2, 6)) == (True, True)
134
+ assert (3 * interval(-1, 2) == interval(-3, 6)) == (True, True)
135
+
136
+ a = 3 * interval(1, 2, is_valid=False)
137
+ assert a.is_valid is False
138
+
139
+ a = 3 * interval(1, 2, is_valid=None)
140
+ assert a.is_valid is None
141
+
142
+ a = interval(1, 5, is_valid=False) * interval(1, 2, is_valid=None)
143
+ assert a.is_valid is False
144
+
145
+
146
+ def test_interval_div():
147
+ div = interval(1, 2, is_valid=False) / 3
148
+ assert div == interval(-float('inf'), float('inf'), is_valid=False)
149
+
150
+ div = interval(1, 2, is_valid=None) / 3
151
+ assert div == interval(-float('inf'), float('inf'), is_valid=None)
152
+
153
+ div = 3 / interval(1, 2, is_valid=None)
154
+ assert div == interval(-float('inf'), float('inf'), is_valid=None)
155
+ a = interval(1, 2) / 0
156
+ assert a.is_valid is False
157
+ a = interval(0.5, 1) / interval(-1, 0)
158
+ assert a.is_valid is None
159
+ a = interval(0, 1) / interval(0, 1)
160
+ assert a.is_valid is None
161
+
162
+ a = interval(-1, 1) / interval(-1, 1)
163
+ assert a.is_valid is None
164
+
165
+ a = interval(-1, 2) / interval(0.5, 1) == interval(-2.0, 4.0)
166
+ assert a == (True, True)
167
+ a = interval(0, 1) / interval(0.5, 1) == interval(0.0, 2.0)
168
+ assert a == (True, True)
169
+ a = interval(-1, 0) / interval(0.5, 1) == interval(-2.0, 0.0)
170
+ assert a == (True, True)
171
+ a = interval(-0.5, -0.25) / interval(0.5, 1) == interval(-1.0, -0.25)
172
+ assert a == (True, True)
173
+ a = interval(0.5, 1) / interval(0.5, 1) == interval(0.5, 2.0)
174
+ assert a == (True, True)
175
+ a = interval(0.5, 4) / interval(0.5, 1) == interval(0.5, 8.0)
176
+ assert a == (True, True)
177
+ a = interval(-1, -0.5) / interval(0.5, 1) == interval(-2.0, -0.5)
178
+ assert a == (True, True)
179
+ a = interval(-4, -0.5) / interval(0.5, 1) == interval(-8.0, -0.5)
180
+ assert a == (True, True)
181
+ a = interval(-1, 2) / interval(-2, -0.5) == interval(-4.0, 2.0)
182
+ assert a == (True, True)
183
+ a = interval(0, 1) / interval(-2, -0.5) == interval(-2.0, 0.0)
184
+ assert a == (True, True)
185
+ a = interval(-1, 0) / interval(-2, -0.5) == interval(0.0, 2.0)
186
+ assert a == (True, True)
187
+ a = interval(-0.5, -0.25) / interval(-2, -0.5) == interval(0.125, 1.0)
188
+ assert a == (True, True)
189
+ a = interval(0.5, 1) / interval(-2, -0.5) == interval(-2.0, -0.25)
190
+ assert a == (True, True)
191
+ a = interval(0.5, 4) / interval(-2, -0.5) == interval(-8.0, -0.25)
192
+ assert a == (True, True)
193
+ a = interval(-1, -0.5) / interval(-2, -0.5) == interval(0.25, 2.0)
194
+ assert a == (True, True)
195
+ a = interval(-4, -0.5) / interval(-2, -0.5) == interval(0.25, 8.0)
196
+ assert a == (True, True)
197
+ a = interval(-5, 5, is_valid=False) / 2
198
+ assert a.is_valid is False
199
+
200
+ def test_hashable():
201
+ '''
202
+ test that interval objects are hashable.
203
+ this is required in order to be able to put them into the cache, which
204
+ appears to be necessary for plotting in py3k. For details, see:
205
+
206
+ https://github.com/sympy/sympy/pull/2101
207
+ https://github.com/sympy/sympy/issues/6533
208
+ '''
209
+ hash(interval(1, 1))
210
+ hash(interval(1, 1, is_valid=True))
211
+ hash(interval(-4, -0.5))
212
+ hash(interval(-2, -0.5))
213
+ hash(interval(0.25, 8.0))
.venv/Lib/site-packages/sympy/plotting/pygletplot/__init__.py ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Plotting module that can plot 2D and 3D functions
2
+ """
3
+
4
+ from sympy.utilities.decorator import doctest_depends_on
5
+
6
+ @doctest_depends_on(modules=('pyglet',))
7
+ def PygletPlot(*args, **kwargs):
8
+ """
9
+
10
+ Plot Examples
11
+ =============
12
+
13
+ See examples/advanced/pyglet_plotting.py for many more examples.
14
+
15
+ >>> from sympy.plotting.pygletplot import PygletPlot as Plot
16
+ >>> from sympy.abc import x, y, z
17
+
18
+ >>> Plot(x*y**3-y*x**3)
19
+ [0]: -x**3*y + x*y**3, 'mode=cartesian'
20
+
21
+ >>> p = Plot()
22
+ >>> p[1] = x*y
23
+ >>> p[1].color = z, (0.4,0.4,0.9), (0.9,0.4,0.4)
24
+
25
+ >>> p = Plot()
26
+ >>> p[1] = x**2+y**2
27
+ >>> p[2] = -x**2-y**2
28
+
29
+
30
+ Variable Intervals
31
+ ==================
32
+
33
+ The basic format is [var, min, max, steps], but the
34
+ syntax is flexible and arguments left out are taken
35
+ from the defaults for the current coordinate mode:
36
+
37
+ >>> Plot(x**2) # implies [x,-5,5,100]
38
+ [0]: x**2, 'mode=cartesian'
39
+
40
+ >>> Plot(x**2, [], []) # [x,-1,1,40], [y,-1,1,40]
41
+ [0]: x**2, 'mode=cartesian'
42
+ >>> Plot(x**2-y**2, [100], [100]) # [x,-1,1,100], [y,-1,1,100]
43
+ [0]: x**2 - y**2, 'mode=cartesian'
44
+ >>> Plot(x**2, [x,-13,13,100])
45
+ [0]: x**2, 'mode=cartesian'
46
+ >>> Plot(x**2, [-13,13]) # [x,-13,13,100]
47
+ [0]: x**2, 'mode=cartesian'
48
+ >>> Plot(x**2, [x,-13,13]) # [x,-13,13,100]
49
+ [0]: x**2, 'mode=cartesian'
50
+ >>> Plot(1*x, [], [x], mode='cylindrical')
51
+ ... # [unbound_theta,0,2*Pi,40], [x,-1,1,20]
52
+ [0]: x, 'mode=cartesian'
53
+
54
+
55
+ Coordinate Modes
56
+ ================
57
+
58
+ Plot supports several curvilinear coordinate modes, and
59
+ they independent for each plotted function. You can specify
60
+ a coordinate mode explicitly with the 'mode' named argument,
61
+ but it can be automatically determined for Cartesian or
62
+ parametric plots, and therefore must only be specified for
63
+ polar, cylindrical, and spherical modes.
64
+
65
+ Specifically, Plot(function arguments) and Plot[n] =
66
+ (function arguments) will interpret your arguments as a
67
+ Cartesian plot if you provide one function and a parametric
68
+ plot if you provide two or three functions. Similarly, the
69
+ arguments will be interpreted as a curve if one variable is
70
+ used, and a surface if two are used.
71
+
72
+ Supported mode names by number of variables:
73
+
74
+ 1: parametric, cartesian, polar
75
+ 2: parametric, cartesian, cylindrical = polar, spherical
76
+
77
+ >>> Plot(1, mode='spherical')
78
+
79
+
80
+ Calculator-like Interface
81
+ =========================
82
+
83
+ >>> p = Plot(visible=False)
84
+ >>> f = x**2
85
+ >>> p[1] = f
86
+ >>> p[2] = f.diff(x)
87
+ >>> p[3] = f.diff(x).diff(x)
88
+ >>> p
89
+ [1]: x**2, 'mode=cartesian'
90
+ [2]: 2*x, 'mode=cartesian'
91
+ [3]: 2, 'mode=cartesian'
92
+ >>> p.show()
93
+ >>> p.clear()
94
+ >>> p
95
+ <blank plot>
96
+ >>> p[1] = x**2+y**2
97
+ >>> p[1].style = 'solid'
98
+ >>> p[2] = -x**2-y**2
99
+ >>> p[2].style = 'wireframe'
100
+ >>> p[1].color = z, (0.4,0.4,0.9), (0.9,0.4,0.4)
101
+ >>> p[1].style = 'both'
102
+ >>> p[2].style = 'both'
103
+ >>> p.close()
104
+
105
+
106
+ Plot Window Keyboard Controls
107
+ =============================
108
+
109
+ Screen Rotation:
110
+ X,Y axis Arrow Keys, A,S,D,W, Numpad 4,6,8,2
111
+ Z axis Q,E, Numpad 7,9
112
+
113
+ Model Rotation:
114
+ Z axis Z,C, Numpad 1,3
115
+
116
+ Zoom: R,F, PgUp,PgDn, Numpad +,-
117
+
118
+ Reset Camera: X, Numpad 5
119
+
120
+ Camera Presets:
121
+ XY F1
122
+ XZ F2
123
+ YZ F3
124
+ Perspective F4
125
+
126
+ Sensitivity Modifier: SHIFT
127
+
128
+ Axes Toggle:
129
+ Visible F5
130
+ Colors F6
131
+
132
+ Close Window: ESCAPE
133
+
134
+ =============================
135
+ """
136
+
137
+ from sympy.plotting.pygletplot.plot import PygletPlot
138
+ return PygletPlot(*args, **kwargs)
.venv/Lib/site-packages/sympy/plotting/pygletplot/__pycache__/__init__.cpython-39.pyc ADDED
Binary file (4 kB). View file
 
.venv/Lib/site-packages/sympy/plotting/pygletplot/color_scheme.py ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.basic import Basic
2
+ from sympy.core.symbol import (Symbol, symbols)
3
+ from sympy.utilities.lambdify import lambdify
4
+ from .util import interpolate, rinterpolate, create_bounds, update_bounds
5
+ from sympy.utilities.iterables import sift
6
+
7
+
8
+ class ColorGradient:
9
+ colors = [0.4, 0.4, 0.4], [0.9, 0.9, 0.9]
10
+ intervals = 0.0, 1.0
11
+
12
+ def __init__(self, *args):
13
+ if len(args) == 2:
14
+ self.colors = list(args)
15
+ self.intervals = [0.0, 1.0]
16
+ elif len(args) > 0:
17
+ if len(args) % 2 != 0:
18
+ raise ValueError("len(args) should be even")
19
+ self.colors = [args[i] for i in range(1, len(args), 2)]
20
+ self.intervals = [args[i] for i in range(0, len(args), 2)]
21
+ assert len(self.colors) == len(self.intervals)
22
+
23
+ def copy(self):
24
+ c = ColorGradient()
25
+ c.colors = [e[::] for e in self.colors]
26
+ c.intervals = self.intervals[::]
27
+ return c
28
+
29
+ def _find_interval(self, v):
30
+ m = len(self.intervals)
31
+ i = 0
32
+ while i < m - 1 and self.intervals[i] <= v:
33
+ i += 1
34
+ return i
35
+
36
+ def _interpolate_axis(self, axis, v):
37
+ i = self._find_interval(v)
38
+ v = rinterpolate(self.intervals[i - 1], self.intervals[i], v)
39
+ return interpolate(self.colors[i - 1][axis], self.colors[i][axis], v)
40
+
41
+ def __call__(self, r, g, b):
42
+ c = self._interpolate_axis
43
+ return c(0, r), c(1, g), c(2, b)
44
+
45
+ default_color_schemes = {} # defined at the bottom of this file
46
+
47
+
48
+ class ColorScheme:
49
+
50
+ def __init__(self, *args, **kwargs):
51
+ self.args = args
52
+ self.f, self.gradient = None, ColorGradient()
53
+
54
+ if len(args) == 1 and not isinstance(args[0], Basic) and callable(args[0]):
55
+ self.f = args[0]
56
+ elif len(args) == 1 and isinstance(args[0], str):
57
+ if args[0] in default_color_schemes:
58
+ cs = default_color_schemes[args[0]]
59
+ self.f, self.gradient = cs.f, cs.gradient.copy()
60
+ else:
61
+ self.f = lambdify('x,y,z,u,v', args[0])
62
+ else:
63
+ self.f, self.gradient = self._interpret_args(args)
64
+ self._test_color_function()
65
+ if not isinstance(self.gradient, ColorGradient):
66
+ raise ValueError("Color gradient not properly initialized. "
67
+ "(Not a ColorGradient instance.)")
68
+
69
+ def _interpret_args(self, args):
70
+ f, gradient = None, self.gradient
71
+ atoms, lists = self._sort_args(args)
72
+ s = self._pop_symbol_list(lists)
73
+ s = self._fill_in_vars(s)
74
+
75
+ # prepare the error message for lambdification failure
76
+ f_str = ', '.join(str(fa) for fa in atoms)
77
+ s_str = (str(sa) for sa in s)
78
+ s_str = ', '.join(sa for sa in s_str if sa.find('unbound') < 0)
79
+ f_error = ValueError("Could not interpret arguments "
80
+ "%s as functions of %s." % (f_str, s_str))
81
+
82
+ # try to lambdify args
83
+ if len(atoms) == 1:
84
+ fv = atoms[0]
85
+ try:
86
+ f = lambdify(s, [fv, fv, fv])
87
+ except TypeError:
88
+ raise f_error
89
+
90
+ elif len(atoms) == 3:
91
+ fr, fg, fb = atoms
92
+ try:
93
+ f = lambdify(s, [fr, fg, fb])
94
+ except TypeError:
95
+ raise f_error
96
+
97
+ else:
98
+ raise ValueError("A ColorScheme must provide 1 or 3 "
99
+ "functions in x, y, z, u, and/or v.")
100
+
101
+ # try to intrepret any given color information
102
+ if len(lists) == 0:
103
+ gargs = []
104
+
105
+ elif len(lists) == 1:
106
+ gargs = lists[0]
107
+
108
+ elif len(lists) == 2:
109
+ try:
110
+ (r1, g1, b1), (r2, g2, b2) = lists
111
+ except TypeError:
112
+ raise ValueError("If two color arguments are given, "
113
+ "they must be given in the format "
114
+ "(r1, g1, b1), (r2, g2, b2).")
115
+ gargs = lists
116
+
117
+ elif len(lists) == 3:
118
+ try:
119
+ (r1, r2), (g1, g2), (b1, b2) = lists
120
+ except Exception:
121
+ raise ValueError("If three color arguments are given, "
122
+ "they must be given in the format "
123
+ "(r1, r2), (g1, g2), (b1, b2). To create "
124
+ "a multi-step gradient, use the syntax "
125
+ "[0, colorStart, step1, color1, ..., 1, "
126
+ "colorEnd].")
127
+ gargs = [[r1, g1, b1], [r2, g2, b2]]
128
+
129
+ else:
130
+ raise ValueError("Don't know what to do with collection "
131
+ "arguments %s." % (', '.join(str(l) for l in lists)))
132
+
133
+ if gargs:
134
+ try:
135
+ gradient = ColorGradient(*gargs)
136
+ except Exception as ex:
137
+ raise ValueError(("Could not initialize a gradient "
138
+ "with arguments %s. Inner "
139
+ "exception: %s") % (gargs, str(ex)))
140
+
141
+ return f, gradient
142
+
143
+ def _pop_symbol_list(self, lists):
144
+ symbol_lists = []
145
+ for l in lists:
146
+ mark = True
147
+ for s in l:
148
+ if s is not None and not isinstance(s, Symbol):
149
+ mark = False
150
+ break
151
+ if mark:
152
+ lists.remove(l)
153
+ symbol_lists.append(l)
154
+ if len(symbol_lists) == 1:
155
+ return symbol_lists[0]
156
+ elif len(symbol_lists) == 0:
157
+ return []
158
+ else:
159
+ raise ValueError("Only one list of Symbols "
160
+ "can be given for a color scheme.")
161
+
162
+ def _fill_in_vars(self, args):
163
+ defaults = symbols('x,y,z,u,v')
164
+ v_error = ValueError("Could not find what to plot.")
165
+ if len(args) == 0:
166
+ return defaults
167
+ if not isinstance(args, (tuple, list)):
168
+ raise v_error
169
+ if len(args) == 0:
170
+ return defaults
171
+ for s in args:
172
+ if s is not None and not isinstance(s, Symbol):
173
+ raise v_error
174
+ # when vars are given explicitly, any vars
175
+ # not given are marked 'unbound' as to not
176
+ # be accidentally used in an expression
177
+ vars = [Symbol('unbound%i' % (i)) for i in range(1, 6)]
178
+ # interpret as t
179
+ if len(args) == 1:
180
+ vars[3] = args[0]
181
+ # interpret as u,v
182
+ elif len(args) == 2:
183
+ if args[0] is not None:
184
+ vars[3] = args[0]
185
+ if args[1] is not None:
186
+ vars[4] = args[1]
187
+ # interpret as x,y,z
188
+ elif len(args) >= 3:
189
+ # allow some of x,y,z to be
190
+ # left unbound if not given
191
+ if args[0] is not None:
192
+ vars[0] = args[0]
193
+ if args[1] is not None:
194
+ vars[1] = args[1]
195
+ if args[2] is not None:
196
+ vars[2] = args[2]
197
+ # interpret the rest as t
198
+ if len(args) >= 4:
199
+ vars[3] = args[3]
200
+ # ...or u,v
201
+ if len(args) >= 5:
202
+ vars[4] = args[4]
203
+ return vars
204
+
205
+ def _sort_args(self, args):
206
+ lists, atoms = sift(args,
207
+ lambda a: isinstance(a, (tuple, list)), binary=True)
208
+ return atoms, lists
209
+
210
+ def _test_color_function(self):
211
+ if not callable(self.f):
212
+ raise ValueError("Color function is not callable.")
213
+ try:
214
+ result = self.f(0, 0, 0, 0, 0)
215
+ if len(result) != 3:
216
+ raise ValueError("length should be equal to 3")
217
+ except TypeError:
218
+ raise ValueError("Color function needs to accept x,y,z,u,v, "
219
+ "as arguments even if it doesn't use all of them.")
220
+ except AssertionError:
221
+ raise ValueError("Color function needs to return 3-tuple r,g,b.")
222
+ except Exception:
223
+ pass # color function probably not valid at 0,0,0,0,0
224
+
225
+ def __call__(self, x, y, z, u, v):
226
+ try:
227
+ return self.f(x, y, z, u, v)
228
+ except Exception:
229
+ return None
230
+
231
+ def apply_to_curve(self, verts, u_set, set_len=None, inc_pos=None):
232
+ """
233
+ Apply this color scheme to a
234
+ set of vertices over a single
235
+ independent variable u.
236
+ """
237
+ bounds = create_bounds()
238
+ cverts = []
239
+ if callable(set_len):
240
+ set_len(len(u_set)*2)
241
+ # calculate f() = r,g,b for each vert
242
+ # and find the min and max for r,g,b
243
+ for _u in range(len(u_set)):
244
+ if verts[_u] is None:
245
+ cverts.append(None)
246
+ else:
247
+ x, y, z = verts[_u]
248
+ u, v = u_set[_u], None
249
+ c = self(x, y, z, u, v)
250
+ if c is not None:
251
+ c = list(c)
252
+ update_bounds(bounds, c)
253
+ cverts.append(c)
254
+ if callable(inc_pos):
255
+ inc_pos()
256
+ # scale and apply gradient
257
+ for _u in range(len(u_set)):
258
+ if cverts[_u] is not None:
259
+ for _c in range(3):
260
+ # scale from [f_min, f_max] to [0,1]
261
+ cverts[_u][_c] = rinterpolate(bounds[_c][0], bounds[_c][1],
262
+ cverts[_u][_c])
263
+ # apply gradient
264
+ cverts[_u] = self.gradient(*cverts[_u])
265
+ if callable(inc_pos):
266
+ inc_pos()
267
+ return cverts
268
+
269
+ def apply_to_surface(self, verts, u_set, v_set, set_len=None, inc_pos=None):
270
+ """
271
+ Apply this color scheme to a
272
+ set of vertices over two
273
+ independent variables u and v.
274
+ """
275
+ bounds = create_bounds()
276
+ cverts = []
277
+ if callable(set_len):
278
+ set_len(len(u_set)*len(v_set)*2)
279
+ # calculate f() = r,g,b for each vert
280
+ # and find the min and max for r,g,b
281
+ for _u in range(len(u_set)):
282
+ column = []
283
+ for _v in range(len(v_set)):
284
+ if verts[_u][_v] is None:
285
+ column.append(None)
286
+ else:
287
+ x, y, z = verts[_u][_v]
288
+ u, v = u_set[_u], v_set[_v]
289
+ c = self(x, y, z, u, v)
290
+ if c is not None:
291
+ c = list(c)
292
+ update_bounds(bounds, c)
293
+ column.append(c)
294
+ if callable(inc_pos):
295
+ inc_pos()
296
+ cverts.append(column)
297
+ # scale and apply gradient
298
+ for _u in range(len(u_set)):
299
+ for _v in range(len(v_set)):
300
+ if cverts[_u][_v] is not None:
301
+ # scale from [f_min, f_max] to [0,1]
302
+ for _c in range(3):
303
+ cverts[_u][_v][_c] = rinterpolate(bounds[_c][0],
304
+ bounds[_c][1], cverts[_u][_v][_c])
305
+ # apply gradient
306
+ cverts[_u][_v] = self.gradient(*cverts[_u][_v])
307
+ if callable(inc_pos):
308
+ inc_pos()
309
+ return cverts
310
+
311
+ def str_base(self):
312
+ return ", ".join(str(a) for a in self.args)
313
+
314
+ def __repr__(self):
315
+ return "%s" % (self.str_base())
316
+
317
+
318
+ x, y, z, t, u, v = symbols('x,y,z,t,u,v')
319
+
320
+ default_color_schemes['rainbow'] = ColorScheme(z, y, x)
321
+ default_color_schemes['zfade'] = ColorScheme(z, (0.4, 0.4, 0.97),
322
+ (0.97, 0.4, 0.4), (None, None, z))
323
+ default_color_schemes['zfade3'] = ColorScheme(z, (None, None, z),
324
+ [0.00, (0.2, 0.2, 1.0),
325
+ 0.35, (0.2, 0.8, 0.4),
326
+ 0.50, (0.3, 0.9, 0.3),
327
+ 0.65, (0.4, 0.8, 0.2),
328
+ 1.00, (1.0, 0.2, 0.2)])
329
+
330
+ default_color_schemes['zfade4'] = ColorScheme(z, (None, None, z),
331
+ [0.0, (0.3, 0.3, 1.0),
332
+ 0.30, (0.3, 1.0, 0.3),
333
+ 0.55, (0.95, 1.0, 0.2),
334
+ 0.65, (1.0, 0.95, 0.2),
335
+ 0.85, (1.0, 0.7, 0.2),
336
+ 1.0, (1.0, 0.3, 0.2)])
.venv/Lib/site-packages/sympy/plotting/pygletplot/managed_window.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pyglet.window import Window
2
+ from pyglet.clock import Clock
3
+
4
+ from threading import Thread, Lock
5
+
6
+ gl_lock = Lock()
7
+
8
+
9
+ class ManagedWindow(Window):
10
+ """
11
+ A pyglet window with an event loop which executes automatically
12
+ in a separate thread. Behavior is added by creating a subclass
13
+ which overrides setup, update, and/or draw.
14
+ """
15
+ fps_limit = 30
16
+ default_win_args = {"width": 600,
17
+ "height": 500,
18
+ "vsync": False,
19
+ "resizable": True}
20
+
21
+ def __init__(self, **win_args):
22
+ """
23
+ It is best not to override this function in the child
24
+ class, unless you need to take additional arguments.
25
+ Do any OpenGL initialization calls in setup().
26
+ """
27
+
28
+ # check if this is run from the doctester
29
+ if win_args.get('runfromdoctester', False):
30
+ return
31
+
32
+ self.win_args = dict(self.default_win_args, **win_args)
33
+ self.Thread = Thread(target=self.__event_loop__)
34
+ self.Thread.start()
35
+
36
+ def __event_loop__(self, **win_args):
37
+ """
38
+ The event loop thread function. Do not override or call
39
+ directly (it is called by __init__).
40
+ """
41
+ gl_lock.acquire()
42
+ try:
43
+ try:
44
+ super().__init__(**self.win_args)
45
+ self.switch_to()
46
+ self.setup()
47
+ except Exception as e:
48
+ print("Window initialization failed: %s" % (str(e)))
49
+ self.has_exit = True
50
+ finally:
51
+ gl_lock.release()
52
+
53
+ clock = Clock()
54
+ clock.fps_limit = self.fps_limit
55
+ while not self.has_exit:
56
+ dt = clock.tick()
57
+ gl_lock.acquire()
58
+ try:
59
+ try:
60
+ self.switch_to()
61
+ self.dispatch_events()
62
+ self.clear()
63
+ self.update(dt)
64
+ self.draw()
65
+ self.flip()
66
+ except Exception as e:
67
+ print("Uncaught exception in event loop: %s" % str(e))
68
+ self.has_exit = True
69
+ finally:
70
+ gl_lock.release()
71
+ super().close()
72
+
73
+ def close(self):
74
+ """
75
+ Closes the window.
76
+ """
77
+ self.has_exit = True
78
+
79
+ def setup(self):
80
+ """
81
+ Called once before the event loop begins.
82
+ Override this method in a child class. This
83
+ is the best place to put things like OpenGL
84
+ initialization calls.
85
+ """
86
+ pass
87
+
88
+ def update(self, dt):
89
+ """
90
+ Called before draw during each iteration of
91
+ the event loop. dt is the elapsed time in
92
+ seconds since the last update. OpenGL rendering
93
+ calls are best put in draw() rather than here.
94
+ """
95
+ pass
96
+
97
+ def draw(self):
98
+ """
99
+ Called after update during each iteration of
100
+ the event loop. Put OpenGL rendering calls
101
+ here.
102
+ """
103
+ pass
104
+
105
+ if __name__ == '__main__':
106
+ ManagedWindow()
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot.py ADDED
@@ -0,0 +1,464 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from threading import RLock
2
+
3
+ # it is sufficient to import "pyglet" here once
4
+ try:
5
+ import pyglet.gl as pgl
6
+ except ImportError:
7
+ raise ImportError("pyglet is required for plotting.\n "
8
+ "visit https://pyglet.org/")
9
+
10
+ from sympy.core.numbers import Integer
11
+ from sympy.external.gmpy import SYMPY_INTS
12
+ from sympy.geometry.entity import GeometryEntity
13
+ from sympy.plotting.pygletplot.plot_axes import PlotAxes
14
+ from sympy.plotting.pygletplot.plot_mode import PlotMode
15
+ from sympy.plotting.pygletplot.plot_object import PlotObject
16
+ from sympy.plotting.pygletplot.plot_window import PlotWindow
17
+ from sympy.plotting.pygletplot.util import parse_option_string
18
+ from sympy.utilities.decorator import doctest_depends_on
19
+ from sympy.utilities.iterables import is_sequence
20
+
21
+ from time import sleep
22
+ from os import getcwd, listdir
23
+
24
+ import ctypes
25
+
26
+ @doctest_depends_on(modules=('pyglet',))
27
+ class PygletPlot:
28
+ """
29
+ Plot Examples
30
+ =============
31
+
32
+ See examples/advanced/pyglet_plotting.py for many more examples.
33
+
34
+ >>> from sympy.plotting.pygletplot import PygletPlot as Plot
35
+ >>> from sympy.abc import x, y, z
36
+
37
+ >>> Plot(x*y**3-y*x**3)
38
+ [0]: -x**3*y + x*y**3, 'mode=cartesian'
39
+
40
+ >>> p = Plot()
41
+ >>> p[1] = x*y
42
+ >>> p[1].color = z, (0.4,0.4,0.9), (0.9,0.4,0.4)
43
+
44
+ >>> p = Plot()
45
+ >>> p[1] = x**2+y**2
46
+ >>> p[2] = -x**2-y**2
47
+
48
+
49
+ Variable Intervals
50
+ ==================
51
+
52
+ The basic format is [var, min, max, steps], but the
53
+ syntax is flexible and arguments left out are taken
54
+ from the defaults for the current coordinate mode:
55
+
56
+ >>> Plot(x**2) # implies [x,-5,5,100]
57
+ [0]: x**2, 'mode=cartesian'
58
+ >>> Plot(x**2, [], []) # [x,-1,1,40], [y,-1,1,40]
59
+ [0]: x**2, 'mode=cartesian'
60
+ >>> Plot(x**2-y**2, [100], [100]) # [x,-1,1,100], [y,-1,1,100]
61
+ [0]: x**2 - y**2, 'mode=cartesian'
62
+ >>> Plot(x**2, [x,-13,13,100])
63
+ [0]: x**2, 'mode=cartesian'
64
+ >>> Plot(x**2, [-13,13]) # [x,-13,13,100]
65
+ [0]: x**2, 'mode=cartesian'
66
+ >>> Plot(x**2, [x,-13,13]) # [x,-13,13,10]
67
+ [0]: x**2, 'mode=cartesian'
68
+ >>> Plot(1*x, [], [x], mode='cylindrical')
69
+ ... # [unbound_theta,0,2*Pi,40], [x,-1,1,20]
70
+ [0]: x, 'mode=cartesian'
71
+
72
+
73
+ Coordinate Modes
74
+ ================
75
+
76
+ Plot supports several curvilinear coordinate modes, and
77
+ they independent for each plotted function. You can specify
78
+ a coordinate mode explicitly with the 'mode' named argument,
79
+ but it can be automatically determined for Cartesian or
80
+ parametric plots, and therefore must only be specified for
81
+ polar, cylindrical, and spherical modes.
82
+
83
+ Specifically, Plot(function arguments) and Plot[n] =
84
+ (function arguments) will interpret your arguments as a
85
+ Cartesian plot if you provide one function and a parametric
86
+ plot if you provide two or three functions. Similarly, the
87
+ arguments will be interpreted as a curve if one variable is
88
+ used, and a surface if two are used.
89
+
90
+ Supported mode names by number of variables:
91
+
92
+ 1: parametric, cartesian, polar
93
+ 2: parametric, cartesian, cylindrical = polar, spherical
94
+
95
+ >>> Plot(1, mode='spherical')
96
+
97
+
98
+ Calculator-like Interface
99
+ =========================
100
+
101
+ >>> p = Plot(visible=False)
102
+ >>> f = x**2
103
+ >>> p[1] = f
104
+ >>> p[2] = f.diff(x)
105
+ >>> p[3] = f.diff(x).diff(x)
106
+ >>> p
107
+ [1]: x**2, 'mode=cartesian'
108
+ [2]: 2*x, 'mode=cartesian'
109
+ [3]: 2, 'mode=cartesian'
110
+ >>> p.show()
111
+ >>> p.clear()
112
+ >>> p
113
+ <blank plot>
114
+ >>> p[1] = x**2+y**2
115
+ >>> p[1].style = 'solid'
116
+ >>> p[2] = -x**2-y**2
117
+ >>> p[2].style = 'wireframe'
118
+ >>> p[1].color = z, (0.4,0.4,0.9), (0.9,0.4,0.4)
119
+ >>> p[1].style = 'both'
120
+ >>> p[2].style = 'both'
121
+ >>> p.close()
122
+
123
+
124
+ Plot Window Keyboard Controls
125
+ =============================
126
+
127
+ Screen Rotation:
128
+ X,Y axis Arrow Keys, A,S,D,W, Numpad 4,6,8,2
129
+ Z axis Q,E, Numpad 7,9
130
+
131
+ Model Rotation:
132
+ Z axis Z,C, Numpad 1,3
133
+
134
+ Zoom: R,F, PgUp,PgDn, Numpad +,-
135
+
136
+ Reset Camera: X, Numpad 5
137
+
138
+ Camera Presets:
139
+ XY F1
140
+ XZ F2
141
+ YZ F3
142
+ Perspective F4
143
+
144
+ Sensitivity Modifier: SHIFT
145
+
146
+ Axes Toggle:
147
+ Visible F5
148
+ Colors F6
149
+
150
+ Close Window: ESCAPE
151
+
152
+ =============================
153
+
154
+ """
155
+
156
+ @doctest_depends_on(modules=('pyglet',))
157
+ def __init__(self, *fargs, **win_args):
158
+ """
159
+ Positional Arguments
160
+ ====================
161
+
162
+ Any given positional arguments are used to
163
+ initialize a plot function at index 1. In
164
+ other words...
165
+
166
+ >>> from sympy.plotting.pygletplot import PygletPlot as Plot
167
+ >>> from sympy.abc import x
168
+ >>> p = Plot(x**2, visible=False)
169
+
170
+ ...is equivalent to...
171
+
172
+ >>> p = Plot(visible=False)
173
+ >>> p[1] = x**2
174
+
175
+ Note that in earlier versions of the plotting
176
+ module, you were able to specify multiple
177
+ functions in the initializer. This functionality
178
+ has been dropped in favor of better automatic
179
+ plot plot_mode detection.
180
+
181
+
182
+ Named Arguments
183
+ ===============
184
+
185
+ axes
186
+ An option string of the form
187
+ "key1=value1; key2 = value2" which
188
+ can use the following options:
189
+
190
+ style = ordinate
191
+ none OR frame OR box OR ordinate
192
+
193
+ stride = 0.25
194
+ val OR (val_x, val_y, val_z)
195
+
196
+ overlay = True (draw on top of plot)
197
+ True OR False
198
+
199
+ colored = False (False uses Black,
200
+ True uses colors
201
+ R,G,B = X,Y,Z)
202
+ True OR False
203
+
204
+ label_axes = False (display axis names
205
+ at endpoints)
206
+ True OR False
207
+
208
+ visible = True (show immediately
209
+ True OR False
210
+
211
+
212
+ The following named arguments are passed as
213
+ arguments to window initialization:
214
+
215
+ antialiasing = True
216
+ True OR False
217
+
218
+ ortho = False
219
+ True OR False
220
+
221
+ invert_mouse_zoom = False
222
+ True OR False
223
+
224
+ """
225
+ # Register the plot modes
226
+ from . import plot_modes # noqa
227
+
228
+ self._win_args = win_args
229
+ self._window = None
230
+
231
+ self._render_lock = RLock()
232
+
233
+ self._functions = {}
234
+ self._pobjects = []
235
+ self._screenshot = ScreenShot(self)
236
+
237
+ axe_options = parse_option_string(win_args.pop('axes', ''))
238
+ self.axes = PlotAxes(**axe_options)
239
+ self._pobjects.append(self.axes)
240
+
241
+ self[0] = fargs
242
+ if win_args.get('visible', True):
243
+ self.show()
244
+
245
+ ## Window Interfaces
246
+
247
+ def show(self):
248
+ """
249
+ Creates and displays a plot window, or activates it
250
+ (gives it focus) if it has already been created.
251
+ """
252
+ if self._window and not self._window.has_exit:
253
+ self._window.activate()
254
+ else:
255
+ self._win_args['visible'] = True
256
+ self.axes.reset_resources()
257
+
258
+ #if hasattr(self, '_doctest_depends_on'):
259
+ # self._win_args['runfromdoctester'] = True
260
+
261
+ self._window = PlotWindow(self, **self._win_args)
262
+
263
+ def close(self):
264
+ """
265
+ Closes the plot window.
266
+ """
267
+ if self._window:
268
+ self._window.close()
269
+
270
+ def saveimage(self, outfile=None, format='', size=(600, 500)):
271
+ """
272
+ Saves a screen capture of the plot window to an
273
+ image file.
274
+
275
+ If outfile is given, it can either be a path
276
+ or a file object. Otherwise a png image will
277
+ be saved to the current working directory.
278
+ If the format is omitted, it is determined from
279
+ the filename extension.
280
+ """
281
+ self._screenshot.save(outfile, format, size)
282
+
283
+ ## Function List Interfaces
284
+
285
+ def clear(self):
286
+ """
287
+ Clears the function list of this plot.
288
+ """
289
+ self._render_lock.acquire()
290
+ self._functions = {}
291
+ self.adjust_all_bounds()
292
+ self._render_lock.release()
293
+
294
+ def __getitem__(self, i):
295
+ """
296
+ Returns the function at position i in the
297
+ function list.
298
+ """
299
+ return self._functions[i]
300
+
301
+ def __setitem__(self, i, args):
302
+ """
303
+ Parses and adds a PlotMode to the function
304
+ list.
305
+ """
306
+ if not (isinstance(i, (SYMPY_INTS, Integer)) and i >= 0):
307
+ raise ValueError("Function index must "
308
+ "be an integer >= 0.")
309
+
310
+ if isinstance(args, PlotObject):
311
+ f = args
312
+ else:
313
+ if (not is_sequence(args)) or isinstance(args, GeometryEntity):
314
+ args = [args]
315
+ if len(args) == 0:
316
+ return # no arguments given
317
+ kwargs = {"bounds_callback": self.adjust_all_bounds}
318
+ f = PlotMode(*args, **kwargs)
319
+
320
+ if f:
321
+ self._render_lock.acquire()
322
+ self._functions[i] = f
323
+ self._render_lock.release()
324
+ else:
325
+ raise ValueError("Failed to parse '%s'."
326
+ % ', '.join(str(a) for a in args))
327
+
328
+ def __delitem__(self, i):
329
+ """
330
+ Removes the function in the function list at
331
+ position i.
332
+ """
333
+ self._render_lock.acquire()
334
+ del self._functions[i]
335
+ self.adjust_all_bounds()
336
+ self._render_lock.release()
337
+
338
+ def firstavailableindex(self):
339
+ """
340
+ Returns the first unused index in the function list.
341
+ """
342
+ i = 0
343
+ self._render_lock.acquire()
344
+ while i in self._functions:
345
+ i += 1
346
+ self._render_lock.release()
347
+ return i
348
+
349
+ def append(self, *args):
350
+ """
351
+ Parses and adds a PlotMode to the function
352
+ list at the first available index.
353
+ """
354
+ self.__setitem__(self.firstavailableindex(), args)
355
+
356
+ def __len__(self):
357
+ """
358
+ Returns the number of functions in the function list.
359
+ """
360
+ return len(self._functions)
361
+
362
+ def __iter__(self):
363
+ """
364
+ Allows iteration of the function list.
365
+ """
366
+ return self._functions.itervalues()
367
+
368
+ def __repr__(self):
369
+ return str(self)
370
+
371
+ def __str__(self):
372
+ """
373
+ Returns a string containing a new-line separated
374
+ list of the functions in the function list.
375
+ """
376
+ s = ""
377
+ if len(self._functions) == 0:
378
+ s += "<blank plot>"
379
+ else:
380
+ self._render_lock.acquire()
381
+ s += "\n".join(["%s[%i]: %s" % ("", i, str(self._functions[i]))
382
+ for i in self._functions])
383
+ self._render_lock.release()
384
+ return s
385
+
386
+ def adjust_all_bounds(self):
387
+ self._render_lock.acquire()
388
+ self.axes.reset_bounding_box()
389
+ for f in self._functions:
390
+ self.axes.adjust_bounds(self._functions[f].bounds)
391
+ self._render_lock.release()
392
+
393
+ def wait_for_calculations(self):
394
+ sleep(0)
395
+ self._render_lock.acquire()
396
+ for f in self._functions:
397
+ a = self._functions[f]._get_calculating_verts
398
+ b = self._functions[f]._get_calculating_cverts
399
+ while a() or b():
400
+ sleep(0)
401
+ self._render_lock.release()
402
+
403
+ class ScreenShot:
404
+ def __init__(self, plot):
405
+ self._plot = plot
406
+ self.screenshot_requested = False
407
+ self.outfile = None
408
+ self.format = ''
409
+ self.invisibleMode = False
410
+ self.flag = 0
411
+
412
+ def __bool__(self):
413
+ return self.screenshot_requested
414
+
415
+ def _execute_saving(self):
416
+ if self.flag < 3:
417
+ self.flag += 1
418
+ return
419
+
420
+ size_x, size_y = self._plot._window.get_size()
421
+ size = size_x*size_y*4*ctypes.sizeof(ctypes.c_ubyte)
422
+ image = ctypes.create_string_buffer(size)
423
+ pgl.glReadPixels(0, 0, size_x, size_y, pgl.GL_RGBA, pgl.GL_UNSIGNED_BYTE, image)
424
+ from PIL import Image
425
+ im = Image.frombuffer('RGBA', (size_x, size_y),
426
+ image.raw, 'raw', 'RGBA', 0, 1)
427
+ im.transpose(Image.FLIP_TOP_BOTTOM).save(self.outfile, self.format)
428
+
429
+ self.flag = 0
430
+ self.screenshot_requested = False
431
+ if self.invisibleMode:
432
+ self._plot._window.close()
433
+
434
+ def save(self, outfile=None, format='', size=(600, 500)):
435
+ self.outfile = outfile
436
+ self.format = format
437
+ self.size = size
438
+ self.screenshot_requested = True
439
+
440
+ if not self._plot._window or self._plot._window.has_exit:
441
+ self._plot._win_args['visible'] = False
442
+
443
+ self._plot._win_args['width'] = size[0]
444
+ self._plot._win_args['height'] = size[1]
445
+
446
+ self._plot.axes.reset_resources()
447
+ self._plot._window = PlotWindow(self._plot, **self._plot._win_args)
448
+ self.invisibleMode = True
449
+
450
+ if self.outfile is None:
451
+ self.outfile = self._create_unique_path()
452
+ print(self.outfile)
453
+
454
+ def _create_unique_path(self):
455
+ cwd = getcwd()
456
+ l = listdir(cwd)
457
+ path = ''
458
+ i = 0
459
+ while True:
460
+ if not 'plot_%s.png' % i in l:
461
+ path = cwd + '/plot_%s.png' % i
462
+ break
463
+ i += 1
464
+ return path
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_axes.py ADDED
@@ -0,0 +1,251 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pyglet.gl as pgl
2
+ from pyglet import font
3
+
4
+ from sympy.core import S
5
+ from sympy.plotting.pygletplot.plot_object import PlotObject
6
+ from sympy.plotting.pygletplot.util import billboard_matrix, dot_product, \
7
+ get_direction_vectors, strided_range, vec_mag, vec_sub
8
+ from sympy.utilities.iterables import is_sequence
9
+
10
+
11
+ class PlotAxes(PlotObject):
12
+
13
+ def __init__(self, *args,
14
+ style='', none=None, frame=None, box=None, ordinate=None,
15
+ stride=0.25,
16
+ visible='', overlay='', colored='', label_axes='', label_ticks='',
17
+ tick_length=0.1,
18
+ font_face='Arial', font_size=28,
19
+ **kwargs):
20
+ # initialize style parameter
21
+ style = style.lower()
22
+
23
+ # allow alias kwargs to override style kwarg
24
+ if none is not None:
25
+ style = 'none'
26
+ if frame is not None:
27
+ style = 'frame'
28
+ if box is not None:
29
+ style = 'box'
30
+ if ordinate is not None:
31
+ style = 'ordinate'
32
+
33
+ if style in ['', 'ordinate']:
34
+ self._render_object = PlotAxesOrdinate(self)
35
+ elif style in ['frame', 'box']:
36
+ self._render_object = PlotAxesFrame(self)
37
+ elif style in ['none']:
38
+ self._render_object = None
39
+ else:
40
+ raise ValueError(("Unrecognized axes style %s.") % (style))
41
+
42
+ # initialize stride parameter
43
+ try:
44
+ stride = eval(stride)
45
+ except TypeError:
46
+ pass
47
+ if is_sequence(stride):
48
+ if len(stride) != 3:
49
+ raise ValueError("length should be equal to 3")
50
+ self._stride = stride
51
+ else:
52
+ self._stride = [stride, stride, stride]
53
+ self._tick_length = float(tick_length)
54
+
55
+ # setup bounding box and ticks
56
+ self._origin = [0, 0, 0]
57
+ self.reset_bounding_box()
58
+
59
+ def flexible_boolean(input, default):
60
+ if input in [True, False]:
61
+ return input
62
+ if input in ('f', 'F', 'false', 'False'):
63
+ return False
64
+ if input in ('t', 'T', 'true', 'True'):
65
+ return True
66
+ return default
67
+
68
+ # initialize remaining parameters
69
+ self.visible = flexible_boolean(kwargs, True)
70
+ self._overlay = flexible_boolean(overlay, True)
71
+ self._colored = flexible_boolean(colored, False)
72
+ self._label_axes = flexible_boolean(label_axes, False)
73
+ self._label_ticks = flexible_boolean(label_ticks, True)
74
+
75
+ # setup label font
76
+ self.font_face = font_face
77
+ self.font_size = font_size
78
+
79
+ # this is also used to reinit the
80
+ # font on window close/reopen
81
+ self.reset_resources()
82
+
83
+ def reset_resources(self):
84
+ self.label_font = None
85
+
86
+ def reset_bounding_box(self):
87
+ self._bounding_box = [[None, None], [None, None], [None, None]]
88
+ self._axis_ticks = [[], [], []]
89
+
90
+ def draw(self):
91
+ if self._render_object:
92
+ pgl.glPushAttrib(pgl.GL_ENABLE_BIT | pgl.GL_POLYGON_BIT | pgl.GL_DEPTH_BUFFER_BIT)
93
+ if self._overlay:
94
+ pgl.glDisable(pgl.GL_DEPTH_TEST)
95
+ self._render_object.draw()
96
+ pgl.glPopAttrib()
97
+
98
+ def adjust_bounds(self, child_bounds):
99
+ b = self._bounding_box
100
+ c = child_bounds
101
+ for i in range(3):
102
+ if abs(c[i][0]) is S.Infinity or abs(c[i][1]) is S.Infinity:
103
+ continue
104
+ b[i][0] = c[i][0] if b[i][0] is None else min([b[i][0], c[i][0]])
105
+ b[i][1] = c[i][1] if b[i][1] is None else max([b[i][1], c[i][1]])
106
+ self._bounding_box = b
107
+ self._recalculate_axis_ticks(i)
108
+
109
+ def _recalculate_axis_ticks(self, axis):
110
+ b = self._bounding_box
111
+ if b[axis][0] is None or b[axis][1] is None:
112
+ self._axis_ticks[axis] = []
113
+ else:
114
+ self._axis_ticks[axis] = strided_range(b[axis][0], b[axis][1],
115
+ self._stride[axis])
116
+
117
+ def toggle_visible(self):
118
+ self.visible = not self.visible
119
+
120
+ def toggle_colors(self):
121
+ self._colored = not self._colored
122
+
123
+
124
+ class PlotAxesBase(PlotObject):
125
+
126
+ def __init__(self, parent_axes):
127
+ self._p = parent_axes
128
+
129
+ def draw(self):
130
+ color = [([0.2, 0.1, 0.3], [0.2, 0.1, 0.3], [0.2, 0.1, 0.3]),
131
+ ([0.9, 0.3, 0.5], [0.5, 1.0, 0.5], [0.3, 0.3, 0.9])][self._p._colored]
132
+ self.draw_background(color)
133
+ self.draw_axis(2, color[2])
134
+ self.draw_axis(1, color[1])
135
+ self.draw_axis(0, color[0])
136
+
137
+ def draw_background(self, color):
138
+ pass # optional
139
+
140
+ def draw_axis(self, axis, color):
141
+ raise NotImplementedError()
142
+
143
+ def draw_text(self, text, position, color, scale=1.0):
144
+ if len(color) == 3:
145
+ color = (color[0], color[1], color[2], 1.0)
146
+
147
+ if self._p.label_font is None:
148
+ self._p.label_font = font.load(self._p.font_face,
149
+ self._p.font_size,
150
+ bold=True, italic=False)
151
+
152
+ label = font.Text(self._p.label_font, text,
153
+ color=color,
154
+ valign=font.Text.BASELINE,
155
+ halign=font.Text.CENTER)
156
+
157
+ pgl.glPushMatrix()
158
+ pgl.glTranslatef(*position)
159
+ billboard_matrix()
160
+ scale_factor = 0.005 * scale
161
+ pgl.glScalef(scale_factor, scale_factor, scale_factor)
162
+ pgl.glColor4f(0, 0, 0, 0)
163
+ label.draw()
164
+ pgl.glPopMatrix()
165
+
166
+ def draw_line(self, v, color):
167
+ o = self._p._origin
168
+ pgl.glBegin(pgl.GL_LINES)
169
+ pgl.glColor3f(*color)
170
+ pgl.glVertex3f(v[0][0] + o[0], v[0][1] + o[1], v[0][2] + o[2])
171
+ pgl.glVertex3f(v[1][0] + o[0], v[1][1] + o[1], v[1][2] + o[2])
172
+ pgl.glEnd()
173
+
174
+
175
+ class PlotAxesOrdinate(PlotAxesBase):
176
+
177
+ def __init__(self, parent_axes):
178
+ super().__init__(parent_axes)
179
+
180
+ def draw_axis(self, axis, color):
181
+ ticks = self._p._axis_ticks[axis]
182
+ radius = self._p._tick_length / 2.0
183
+ if len(ticks) < 2:
184
+ return
185
+
186
+ # calculate the vector for this axis
187
+ axis_lines = [[0, 0, 0], [0, 0, 0]]
188
+ axis_lines[0][axis], axis_lines[1][axis] = ticks[0], ticks[-1]
189
+ axis_vector = vec_sub(axis_lines[1], axis_lines[0])
190
+
191
+ # calculate angle to the z direction vector
192
+ pos_z = get_direction_vectors()[2]
193
+ d = abs(dot_product(axis_vector, pos_z))
194
+ d = d / vec_mag(axis_vector)
195
+
196
+ # don't draw labels if we're looking down the axis
197
+ labels_visible = abs(d - 1.0) > 0.02
198
+
199
+ # draw the ticks and labels
200
+ for tick in ticks:
201
+ self.draw_tick_line(axis, color, radius, tick, labels_visible)
202
+
203
+ # draw the axis line and labels
204
+ self.draw_axis_line(axis, color, ticks[0], ticks[-1], labels_visible)
205
+
206
+ def draw_axis_line(self, axis, color, a_min, a_max, labels_visible):
207
+ axis_line = [[0, 0, 0], [0, 0, 0]]
208
+ axis_line[0][axis], axis_line[1][axis] = a_min, a_max
209
+ self.draw_line(axis_line, color)
210
+ if labels_visible:
211
+ self.draw_axis_line_labels(axis, color, axis_line)
212
+
213
+ def draw_axis_line_labels(self, axis, color, axis_line):
214
+ if not self._p._label_axes:
215
+ return
216
+ axis_labels = [axis_line[0][::], axis_line[1][::]]
217
+ axis_labels[0][axis] -= 0.3
218
+ axis_labels[1][axis] += 0.3
219
+ a_str = ['X', 'Y', 'Z'][axis]
220
+ self.draw_text("-" + a_str, axis_labels[0], color)
221
+ self.draw_text("+" + a_str, axis_labels[1], color)
222
+
223
+ def draw_tick_line(self, axis, color, radius, tick, labels_visible):
224
+ tick_axis = {0: 1, 1: 0, 2: 1}[axis]
225
+ tick_line = [[0, 0, 0], [0, 0, 0]]
226
+ tick_line[0][axis] = tick_line[1][axis] = tick
227
+ tick_line[0][tick_axis], tick_line[1][tick_axis] = -radius, radius
228
+ self.draw_line(tick_line, color)
229
+ if labels_visible:
230
+ self.draw_tick_line_label(axis, color, radius, tick)
231
+
232
+ def draw_tick_line_label(self, axis, color, radius, tick):
233
+ if not self._p._label_axes:
234
+ return
235
+ tick_label_vector = [0, 0, 0]
236
+ tick_label_vector[axis] = tick
237
+ tick_label_vector[{0: 1, 1: 0, 2: 1}[axis]] = [-1, 1, 1][
238
+ axis] * radius * 3.5
239
+ self.draw_text(str(tick), tick_label_vector, color, scale=0.5)
240
+
241
+
242
+ class PlotAxesFrame(PlotAxesBase):
243
+
244
+ def __init__(self, parent_axes):
245
+ super().__init__(parent_axes)
246
+
247
+ def draw_background(self, color):
248
+ pass
249
+
250
+ def draw_axis(self, axis, color):
251
+ raise NotImplementedError()
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_camera.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pyglet.gl as pgl
2
+ from sympy.plotting.pygletplot.plot_rotation import get_spherical_rotatation
3
+ from sympy.plotting.pygletplot.util import get_model_matrix, model_to_screen, \
4
+ screen_to_model, vec_subs
5
+
6
+
7
+ class PlotCamera:
8
+
9
+ min_dist = 0.05
10
+ max_dist = 500.0
11
+
12
+ min_ortho_dist = 100.0
13
+ max_ortho_dist = 10000.0
14
+
15
+ _default_dist = 6.0
16
+ _default_ortho_dist = 600.0
17
+
18
+ rot_presets = {
19
+ 'xy': (0, 0, 0),
20
+ 'xz': (-90, 0, 0),
21
+ 'yz': (0, 90, 0),
22
+ 'perspective': (-45, 0, -45)
23
+ }
24
+
25
+ def __init__(self, window, ortho=False):
26
+ self.window = window
27
+ self.axes = self.window.plot.axes
28
+ self.ortho = ortho
29
+ self.reset()
30
+
31
+ def init_rot_matrix(self):
32
+ pgl.glPushMatrix()
33
+ pgl.glLoadIdentity()
34
+ self._rot = get_model_matrix()
35
+ pgl.glPopMatrix()
36
+
37
+ def set_rot_preset(self, preset_name):
38
+ self.init_rot_matrix()
39
+ if preset_name not in self.rot_presets:
40
+ raise ValueError(
41
+ "%s is not a valid rotation preset." % preset_name)
42
+ r = self.rot_presets[preset_name]
43
+ self.euler_rotate(r[0], 1, 0, 0)
44
+ self.euler_rotate(r[1], 0, 1, 0)
45
+ self.euler_rotate(r[2], 0, 0, 1)
46
+
47
+ def reset(self):
48
+ self._dist = 0.0
49
+ self._x, self._y = 0.0, 0.0
50
+ self._rot = None
51
+ if self.ortho:
52
+ self._dist = self._default_ortho_dist
53
+ else:
54
+ self._dist = self._default_dist
55
+ self.init_rot_matrix()
56
+
57
+ def mult_rot_matrix(self, rot):
58
+ pgl.glPushMatrix()
59
+ pgl.glLoadMatrixf(rot)
60
+ pgl.glMultMatrixf(self._rot)
61
+ self._rot = get_model_matrix()
62
+ pgl.glPopMatrix()
63
+
64
+ def setup_projection(self):
65
+ pgl.glMatrixMode(pgl.GL_PROJECTION)
66
+ pgl.glLoadIdentity()
67
+ if self.ortho:
68
+ # yep, this is pseudo ortho (don't tell anyone)
69
+ pgl.gluPerspective(
70
+ 0.3, float(self.window.width)/float(self.window.height),
71
+ self.min_ortho_dist - 0.01, self.max_ortho_dist + 0.01)
72
+ else:
73
+ pgl.gluPerspective(
74
+ 30.0, float(self.window.width)/float(self.window.height),
75
+ self.min_dist - 0.01, self.max_dist + 0.01)
76
+ pgl.glMatrixMode(pgl.GL_MODELVIEW)
77
+
78
+ def _get_scale(self):
79
+ return 1.0, 1.0, 1.0
80
+
81
+ def apply_transformation(self):
82
+ pgl.glLoadIdentity()
83
+ pgl.glTranslatef(self._x, self._y, -self._dist)
84
+ if self._rot is not None:
85
+ pgl.glMultMatrixf(self._rot)
86
+ pgl.glScalef(*self._get_scale())
87
+
88
+ def spherical_rotate(self, p1, p2, sensitivity=1.0):
89
+ mat = get_spherical_rotatation(p1, p2, self.window.width,
90
+ self.window.height, sensitivity)
91
+ if mat is not None:
92
+ self.mult_rot_matrix(mat)
93
+
94
+ def euler_rotate(self, angle, x, y, z):
95
+ pgl.glPushMatrix()
96
+ pgl.glLoadMatrixf(self._rot)
97
+ pgl.glRotatef(angle, x, y, z)
98
+ self._rot = get_model_matrix()
99
+ pgl.glPopMatrix()
100
+
101
+ def zoom_relative(self, clicks, sensitivity):
102
+
103
+ if self.ortho:
104
+ dist_d = clicks * sensitivity * 50.0
105
+ min_dist = self.min_ortho_dist
106
+ max_dist = self.max_ortho_dist
107
+ else:
108
+ dist_d = clicks * sensitivity
109
+ min_dist = self.min_dist
110
+ max_dist = self.max_dist
111
+
112
+ new_dist = (self._dist - dist_d)
113
+ if (clicks < 0 and new_dist < max_dist) or new_dist > min_dist:
114
+ self._dist = new_dist
115
+
116
+ def mouse_translate(self, x, y, dx, dy):
117
+ pgl.glPushMatrix()
118
+ pgl.glLoadIdentity()
119
+ pgl.glTranslatef(0, 0, -self._dist)
120
+ z = model_to_screen(0, 0, 0)[2]
121
+ d = vec_subs(screen_to_model(x, y, z), screen_to_model(x - dx, y - dy, z))
122
+ pgl.glPopMatrix()
123
+ self._x += d[0]
124
+ self._y += d[1]
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_controller.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pyglet.window import key
2
+ from pyglet.window.mouse import LEFT, RIGHT, MIDDLE
3
+ from sympy.plotting.pygletplot.util import get_direction_vectors, get_basis_vectors
4
+
5
+
6
+ class PlotController:
7
+
8
+ normal_mouse_sensitivity = 4.0
9
+ modified_mouse_sensitivity = 1.0
10
+
11
+ normal_key_sensitivity = 160.0
12
+ modified_key_sensitivity = 40.0
13
+
14
+ keymap = {
15
+ key.LEFT: 'left',
16
+ key.A: 'left',
17
+ key.NUM_4: 'left',
18
+
19
+ key.RIGHT: 'right',
20
+ key.D: 'right',
21
+ key.NUM_6: 'right',
22
+
23
+ key.UP: 'up',
24
+ key.W: 'up',
25
+ key.NUM_8: 'up',
26
+
27
+ key.DOWN: 'down',
28
+ key.S: 'down',
29
+ key.NUM_2: 'down',
30
+
31
+ key.Z: 'rotate_z_neg',
32
+ key.NUM_1: 'rotate_z_neg',
33
+
34
+ key.C: 'rotate_z_pos',
35
+ key.NUM_3: 'rotate_z_pos',
36
+
37
+ key.Q: 'spin_left',
38
+ key.NUM_7: 'spin_left',
39
+ key.E: 'spin_right',
40
+ key.NUM_9: 'spin_right',
41
+
42
+ key.X: 'reset_camera',
43
+ key.NUM_5: 'reset_camera',
44
+
45
+ key.NUM_ADD: 'zoom_in',
46
+ key.PAGEUP: 'zoom_in',
47
+ key.R: 'zoom_in',
48
+
49
+ key.NUM_SUBTRACT: 'zoom_out',
50
+ key.PAGEDOWN: 'zoom_out',
51
+ key.F: 'zoom_out',
52
+
53
+ key.RSHIFT: 'modify_sensitivity',
54
+ key.LSHIFT: 'modify_sensitivity',
55
+
56
+ key.F1: 'rot_preset_xy',
57
+ key.F2: 'rot_preset_xz',
58
+ key.F3: 'rot_preset_yz',
59
+ key.F4: 'rot_preset_perspective',
60
+
61
+ key.F5: 'toggle_axes',
62
+ key.F6: 'toggle_axe_colors',
63
+
64
+ key.F8: 'save_image'
65
+ }
66
+
67
+ def __init__(self, window, *, invert_mouse_zoom=False, **kwargs):
68
+ self.invert_mouse_zoom = invert_mouse_zoom
69
+ self.window = window
70
+ self.camera = window.camera
71
+ self.action = {
72
+ # Rotation around the view Y (up) vector
73
+ 'left': False,
74
+ 'right': False,
75
+ # Rotation around the view X vector
76
+ 'up': False,
77
+ 'down': False,
78
+ # Rotation around the view Z vector
79
+ 'spin_left': False,
80
+ 'spin_right': False,
81
+ # Rotation around the model Z vector
82
+ 'rotate_z_neg': False,
83
+ 'rotate_z_pos': False,
84
+ # Reset to the default rotation
85
+ 'reset_camera': False,
86
+ # Performs camera z-translation
87
+ 'zoom_in': False,
88
+ 'zoom_out': False,
89
+ # Use alternative sensitivity (speed)
90
+ 'modify_sensitivity': False,
91
+ # Rotation presets
92
+ 'rot_preset_xy': False,
93
+ 'rot_preset_xz': False,
94
+ 'rot_preset_yz': False,
95
+ 'rot_preset_perspective': False,
96
+ # axes
97
+ 'toggle_axes': False,
98
+ 'toggle_axe_colors': False,
99
+ # screenshot
100
+ 'save_image': False
101
+ }
102
+
103
+ def update(self, dt):
104
+ z = 0
105
+ if self.action['zoom_out']:
106
+ z -= 1
107
+ if self.action['zoom_in']:
108
+ z += 1
109
+ if z != 0:
110
+ self.camera.zoom_relative(z/10.0, self.get_key_sensitivity()/10.0)
111
+
112
+ dx, dy, dz = 0, 0, 0
113
+ if self.action['left']:
114
+ dx -= 1
115
+ if self.action['right']:
116
+ dx += 1
117
+ if self.action['up']:
118
+ dy -= 1
119
+ if self.action['down']:
120
+ dy += 1
121
+ if self.action['spin_left']:
122
+ dz += 1
123
+ if self.action['spin_right']:
124
+ dz -= 1
125
+
126
+ if not self.is_2D():
127
+ if dx != 0:
128
+ self.camera.euler_rotate(dx*dt*self.get_key_sensitivity(),
129
+ *(get_direction_vectors()[1]))
130
+ if dy != 0:
131
+ self.camera.euler_rotate(dy*dt*self.get_key_sensitivity(),
132
+ *(get_direction_vectors()[0]))
133
+ if dz != 0:
134
+ self.camera.euler_rotate(dz*dt*self.get_key_sensitivity(),
135
+ *(get_direction_vectors()[2]))
136
+ else:
137
+ self.camera.mouse_translate(0, 0, dx*dt*self.get_key_sensitivity(),
138
+ -dy*dt*self.get_key_sensitivity())
139
+
140
+ rz = 0
141
+ if self.action['rotate_z_neg'] and not self.is_2D():
142
+ rz -= 1
143
+ if self.action['rotate_z_pos'] and not self.is_2D():
144
+ rz += 1
145
+
146
+ if rz != 0:
147
+ self.camera.euler_rotate(rz*dt*self.get_key_sensitivity(),
148
+ *(get_basis_vectors()[2]))
149
+
150
+ if self.action['reset_camera']:
151
+ self.camera.reset()
152
+
153
+ if self.action['rot_preset_xy']:
154
+ self.camera.set_rot_preset('xy')
155
+ if self.action['rot_preset_xz']:
156
+ self.camera.set_rot_preset('xz')
157
+ if self.action['rot_preset_yz']:
158
+ self.camera.set_rot_preset('yz')
159
+ if self.action['rot_preset_perspective']:
160
+ self.camera.set_rot_preset('perspective')
161
+
162
+ if self.action['toggle_axes']:
163
+ self.action['toggle_axes'] = False
164
+ self.camera.axes.toggle_visible()
165
+
166
+ if self.action['toggle_axe_colors']:
167
+ self.action['toggle_axe_colors'] = False
168
+ self.camera.axes.toggle_colors()
169
+
170
+ if self.action['save_image']:
171
+ self.action['save_image'] = False
172
+ self.window.plot.saveimage()
173
+
174
+ return True
175
+
176
+ def get_mouse_sensitivity(self):
177
+ if self.action['modify_sensitivity']:
178
+ return self.modified_mouse_sensitivity
179
+ else:
180
+ return self.normal_mouse_sensitivity
181
+
182
+ def get_key_sensitivity(self):
183
+ if self.action['modify_sensitivity']:
184
+ return self.modified_key_sensitivity
185
+ else:
186
+ return self.normal_key_sensitivity
187
+
188
+ def on_key_press(self, symbol, modifiers):
189
+ if symbol in self.keymap:
190
+ self.action[self.keymap[symbol]] = True
191
+
192
+ def on_key_release(self, symbol, modifiers):
193
+ if symbol in self.keymap:
194
+ self.action[self.keymap[symbol]] = False
195
+
196
+ def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers):
197
+ if buttons & LEFT:
198
+ if self.is_2D():
199
+ self.camera.mouse_translate(x, y, dx, dy)
200
+ else:
201
+ self.camera.spherical_rotate((x - dx, y - dy), (x, y),
202
+ self.get_mouse_sensitivity())
203
+ if buttons & MIDDLE:
204
+ self.camera.zoom_relative([1, -1][self.invert_mouse_zoom]*dy,
205
+ self.get_mouse_sensitivity()/20.0)
206
+ if buttons & RIGHT:
207
+ self.camera.mouse_translate(x, y, dx, dy)
208
+
209
+ def on_mouse_scroll(self, x, y, dx, dy):
210
+ self.camera.zoom_relative([1, -1][self.invert_mouse_zoom]*dy,
211
+ self.get_mouse_sensitivity())
212
+
213
+ def is_2D(self):
214
+ functions = self.window.plot._functions
215
+ for i in functions:
216
+ if len(functions[i].i_vars) > 1 or len(functions[i].d_vars) > 2:
217
+ return False
218
+ return True
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_curve.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pyglet.gl as pgl
2
+ from sympy.core import S
3
+ from sympy.plotting.pygletplot.plot_mode_base import PlotModeBase
4
+
5
+
6
+ class PlotCurve(PlotModeBase):
7
+
8
+ style_override = 'wireframe'
9
+
10
+ def _on_calculate_verts(self):
11
+ self.t_interval = self.intervals[0]
12
+ self.t_set = list(self.t_interval.frange())
13
+ self.bounds = [[S.Infinity, S.NegativeInfinity, 0],
14
+ [S.Infinity, S.NegativeInfinity, 0],
15
+ [S.Infinity, S.NegativeInfinity, 0]]
16
+ evaluate = self._get_evaluator()
17
+
18
+ self._calculating_verts_pos = 0.0
19
+ self._calculating_verts_len = float(self.t_interval.v_len)
20
+
21
+ self.verts = []
22
+ b = self.bounds
23
+ for t in self.t_set:
24
+ try:
25
+ _e = evaluate(t) # calculate vertex
26
+ except (NameError, ZeroDivisionError):
27
+ _e = None
28
+ if _e is not None: # update bounding box
29
+ for axis in range(3):
30
+ b[axis][0] = min([b[axis][0], _e[axis]])
31
+ b[axis][1] = max([b[axis][1], _e[axis]])
32
+ self.verts.append(_e)
33
+ self._calculating_verts_pos += 1.0
34
+
35
+ for axis in range(3):
36
+ b[axis][2] = b[axis][1] - b[axis][0]
37
+ if b[axis][2] == 0.0:
38
+ b[axis][2] = 1.0
39
+
40
+ self.push_wireframe(self.draw_verts(False))
41
+
42
+ def _on_calculate_cverts(self):
43
+ if not self.verts or not self.color:
44
+ return
45
+
46
+ def set_work_len(n):
47
+ self._calculating_cverts_len = float(n)
48
+
49
+ def inc_work_pos():
50
+ self._calculating_cverts_pos += 1.0
51
+ set_work_len(1)
52
+ self._calculating_cverts_pos = 0
53
+ self.cverts = self.color.apply_to_curve(self.verts,
54
+ self.t_set,
55
+ set_len=set_work_len,
56
+ inc_pos=inc_work_pos)
57
+ self.push_wireframe(self.draw_verts(True))
58
+
59
+ def calculate_one_cvert(self, t):
60
+ vert = self.verts[t]
61
+ return self.color(vert[0], vert[1], vert[2],
62
+ self.t_set[t], None)
63
+
64
+ def draw_verts(self, use_cverts):
65
+ def f():
66
+ pgl.glBegin(pgl.GL_LINE_STRIP)
67
+ for t in range(len(self.t_set)):
68
+ p = self.verts[t]
69
+ if p is None:
70
+ pgl.glEnd()
71
+ pgl.glBegin(pgl.GL_LINE_STRIP)
72
+ continue
73
+ if use_cverts:
74
+ c = self.cverts[t]
75
+ if c is None:
76
+ c = (0, 0, 0)
77
+ pgl.glColor3f(*c)
78
+ else:
79
+ pgl.glColor3f(*self.default_wireframe_color)
80
+ pgl.glVertex3f(*p)
81
+ pgl.glEnd()
82
+ return f
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_interval.py ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.singleton import S
2
+ from sympy.core.symbol import Symbol
3
+ from sympy.core.sympify import sympify
4
+ from sympy.core.numbers import Integer
5
+
6
+
7
+ class PlotInterval:
8
+ """
9
+ """
10
+ _v, _v_min, _v_max, _v_steps = None, None, None, None
11
+
12
+ def require_all_args(f):
13
+ def check(self, *args, **kwargs):
14
+ for g in [self._v, self._v_min, self._v_max, self._v_steps]:
15
+ if g is None:
16
+ raise ValueError("PlotInterval is incomplete.")
17
+ return f(self, *args, **kwargs)
18
+ return check
19
+
20
+ def __init__(self, *args):
21
+ if len(args) == 1:
22
+ if isinstance(args[0], PlotInterval):
23
+ self.fill_from(args[0])
24
+ return
25
+ elif isinstance(args[0], str):
26
+ try:
27
+ args = eval(args[0])
28
+ except TypeError:
29
+ s_eval_error = "Could not interpret string %s."
30
+ raise ValueError(s_eval_error % (args[0]))
31
+ elif isinstance(args[0], (tuple, list)):
32
+ args = args[0]
33
+ else:
34
+ raise ValueError("Not an interval.")
35
+ if not isinstance(args, (tuple, list)) or len(args) > 4:
36
+ f_error = "PlotInterval must be a tuple or list of length 4 or less."
37
+ raise ValueError(f_error)
38
+
39
+ args = list(args)
40
+ if len(args) > 0 and (args[0] is None or isinstance(args[0], Symbol)):
41
+ self.v = args.pop(0)
42
+ if len(args) in [2, 3]:
43
+ self.v_min = args.pop(0)
44
+ self.v_max = args.pop(0)
45
+ if len(args) == 1:
46
+ self.v_steps = args.pop(0)
47
+ elif len(args) == 1:
48
+ self.v_steps = args.pop(0)
49
+
50
+ def get_v(self):
51
+ return self._v
52
+
53
+ def set_v(self, v):
54
+ if v is None:
55
+ self._v = None
56
+ return
57
+ if not isinstance(v, Symbol):
58
+ raise ValueError("v must be a SymPy Symbol.")
59
+ self._v = v
60
+
61
+ def get_v_min(self):
62
+ return self._v_min
63
+
64
+ def set_v_min(self, v_min):
65
+ if v_min is None:
66
+ self._v_min = None
67
+ return
68
+ try:
69
+ self._v_min = sympify(v_min)
70
+ float(self._v_min.evalf())
71
+ except TypeError:
72
+ raise ValueError("v_min could not be interpreted as a number.")
73
+
74
+ def get_v_max(self):
75
+ return self._v_max
76
+
77
+ def set_v_max(self, v_max):
78
+ if v_max is None:
79
+ self._v_max = None
80
+ return
81
+ try:
82
+ self._v_max = sympify(v_max)
83
+ float(self._v_max.evalf())
84
+ except TypeError:
85
+ raise ValueError("v_max could not be interpreted as a number.")
86
+
87
+ def get_v_steps(self):
88
+ return self._v_steps
89
+
90
+ def set_v_steps(self, v_steps):
91
+ if v_steps is None:
92
+ self._v_steps = None
93
+ return
94
+ if isinstance(v_steps, int):
95
+ v_steps = Integer(v_steps)
96
+ elif not isinstance(v_steps, Integer):
97
+ raise ValueError("v_steps must be an int or SymPy Integer.")
98
+ if v_steps <= S.Zero:
99
+ raise ValueError("v_steps must be positive.")
100
+ self._v_steps = v_steps
101
+
102
+ @require_all_args
103
+ def get_v_len(self):
104
+ return self.v_steps + 1
105
+
106
+ v = property(get_v, set_v)
107
+ v_min = property(get_v_min, set_v_min)
108
+ v_max = property(get_v_max, set_v_max)
109
+ v_steps = property(get_v_steps, set_v_steps)
110
+ v_len = property(get_v_len)
111
+
112
+ def fill_from(self, b):
113
+ if b.v is not None:
114
+ self.v = b.v
115
+ if b.v_min is not None:
116
+ self.v_min = b.v_min
117
+ if b.v_max is not None:
118
+ self.v_max = b.v_max
119
+ if b.v_steps is not None:
120
+ self.v_steps = b.v_steps
121
+
122
+ @staticmethod
123
+ def try_parse(*args):
124
+ """
125
+ Returns a PlotInterval if args can be interpreted
126
+ as such, otherwise None.
127
+ """
128
+ if len(args) == 1 and isinstance(args[0], PlotInterval):
129
+ return args[0]
130
+ try:
131
+ return PlotInterval(*args)
132
+ except ValueError:
133
+ return None
134
+
135
+ def _str_base(self):
136
+ return ",".join([str(self.v), str(self.v_min),
137
+ str(self.v_max), str(self.v_steps)])
138
+
139
+ def __repr__(self):
140
+ """
141
+ A string representing the interval in class constructor form.
142
+ """
143
+ return "PlotInterval(%s)" % (self._str_base())
144
+
145
+ def __str__(self):
146
+ """
147
+ A string representing the interval in list form.
148
+ """
149
+ return "[%s]" % (self._str_base())
150
+
151
+ @require_all_args
152
+ def assert_complete(self):
153
+ pass
154
+
155
+ @require_all_args
156
+ def vrange(self):
157
+ """
158
+ Yields v_steps+1 SymPy numbers ranging from
159
+ v_min to v_max.
160
+ """
161
+ d = (self.v_max - self.v_min) / self.v_steps
162
+ for i in range(self.v_steps + 1):
163
+ a = self.v_min + (d * Integer(i))
164
+ yield a
165
+
166
+ @require_all_args
167
+ def vrange2(self):
168
+ """
169
+ Yields v_steps pairs of SymPy numbers ranging from
170
+ (v_min, v_min + step) to (v_max - step, v_max).
171
+ """
172
+ d = (self.v_max - self.v_min) / self.v_steps
173
+ a = self.v_min + (d * S.Zero)
174
+ for i in range(self.v_steps):
175
+ b = self.v_min + (d * Integer(i + 1))
176
+ yield a, b
177
+ a = b
178
+
179
+ def frange(self):
180
+ for i in self.vrange():
181
+ yield float(i.evalf())
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_mode.py ADDED
@@ -0,0 +1,400 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .plot_interval import PlotInterval
2
+ from .plot_object import PlotObject
3
+ from .util import parse_option_string
4
+ from sympy.core.symbol import Symbol
5
+ from sympy.core.sympify import sympify
6
+ from sympy.geometry.entity import GeometryEntity
7
+ from sympy.utilities.iterables import is_sequence
8
+
9
+
10
+ class PlotMode(PlotObject):
11
+ """
12
+ Grandparent class for plotting
13
+ modes. Serves as interface for
14
+ registration, lookup, and init
15
+ of modes.
16
+
17
+ To create a new plot mode,
18
+ inherit from PlotModeBase
19
+ or one of its children, such
20
+ as PlotSurface or PlotCurve.
21
+ """
22
+
23
+ ## Class-level attributes
24
+ ## used to register and lookup
25
+ ## plot modes. See PlotModeBase
26
+ ## for descriptions and usage.
27
+
28
+ i_vars, d_vars = '', ''
29
+ intervals = []
30
+ aliases = []
31
+ is_default = False
32
+
33
+ ## Draw is the only method here which
34
+ ## is meant to be overridden in child
35
+ ## classes, and PlotModeBase provides
36
+ ## a base implementation.
37
+ def draw(self):
38
+ raise NotImplementedError()
39
+
40
+ ## Everything else in this file has to
41
+ ## do with registration and retrieval
42
+ ## of plot modes. This is where I've
43
+ ## hidden much of the ugliness of automatic
44
+ ## plot mode divination...
45
+
46
+ ## Plot mode registry data structures
47
+ _mode_alias_list = []
48
+ _mode_map = {
49
+ 1: {1: {}, 2: {}},
50
+ 2: {1: {}, 2: {}},
51
+ 3: {1: {}, 2: {}},
52
+ } # [d][i][alias_str]: class
53
+ _mode_default_map = {
54
+ 1: {},
55
+ 2: {},
56
+ 3: {},
57
+ } # [d][i]: class
58
+ _i_var_max, _d_var_max = 2, 3
59
+
60
+ def __new__(cls, *args, **kwargs):
61
+ """
62
+ This is the function which interprets
63
+ arguments given to Plot.__init__ and
64
+ Plot.__setattr__. Returns an initialized
65
+ instance of the appropriate child class.
66
+ """
67
+
68
+ newargs, newkwargs = PlotMode._extract_options(args, kwargs)
69
+ mode_arg = newkwargs.get('mode', '')
70
+
71
+ # Interpret the arguments
72
+ d_vars, intervals = PlotMode._interpret_args(newargs)
73
+ i_vars = PlotMode._find_i_vars(d_vars, intervals)
74
+ i, d = max([len(i_vars), len(intervals)]), len(d_vars)
75
+
76
+ # Find the appropriate mode
77
+ subcls = PlotMode._get_mode(mode_arg, i, d)
78
+
79
+ # Create the object
80
+ o = object.__new__(subcls)
81
+
82
+ # Do some setup for the mode instance
83
+ o.d_vars = d_vars
84
+ o._fill_i_vars(i_vars)
85
+ o._fill_intervals(intervals)
86
+ o.options = newkwargs
87
+
88
+ return o
89
+
90
+ @staticmethod
91
+ def _get_mode(mode_arg, i_var_count, d_var_count):
92
+ """
93
+ Tries to return an appropriate mode class.
94
+ Intended to be called only by __new__.
95
+
96
+ mode_arg
97
+ Can be a string or a class. If it is a
98
+ PlotMode subclass, it is simply returned.
99
+ If it is a string, it can an alias for
100
+ a mode or an empty string. In the latter
101
+ case, we try to find a default mode for
102
+ the i_var_count and d_var_count.
103
+
104
+ i_var_count
105
+ The number of independent variables
106
+ needed to evaluate the d_vars.
107
+
108
+ d_var_count
109
+ The number of dependent variables;
110
+ usually the number of functions to
111
+ be evaluated in plotting.
112
+
113
+ For example, a Cartesian function y = f(x) has
114
+ one i_var (x) and one d_var (y). A parametric
115
+ form x,y,z = f(u,v), f(u,v), f(u,v) has two
116
+ two i_vars (u,v) and three d_vars (x,y,z).
117
+ """
118
+ # if the mode_arg is simply a PlotMode class,
119
+ # check that the mode supports the numbers
120
+ # of independent and dependent vars, then
121
+ # return it
122
+ try:
123
+ m = None
124
+ if issubclass(mode_arg, PlotMode):
125
+ m = mode_arg
126
+ except TypeError:
127
+ pass
128
+ if m:
129
+ if not m._was_initialized:
130
+ raise ValueError(("To use unregistered plot mode %s "
131
+ "you must first call %s._init_mode().")
132
+ % (m.__name__, m.__name__))
133
+ if d_var_count != m.d_var_count:
134
+ raise ValueError(("%s can only plot functions "
135
+ "with %i dependent variables.")
136
+ % (m.__name__,
137
+ m.d_var_count))
138
+ if i_var_count > m.i_var_count:
139
+ raise ValueError(("%s cannot plot functions "
140
+ "with more than %i independent "
141
+ "variables.")
142
+ % (m.__name__,
143
+ m.i_var_count))
144
+ return m
145
+ # If it is a string, there are two possibilities.
146
+ if isinstance(mode_arg, str):
147
+ i, d = i_var_count, d_var_count
148
+ if i > PlotMode._i_var_max:
149
+ raise ValueError(var_count_error(True, True))
150
+ if d > PlotMode._d_var_max:
151
+ raise ValueError(var_count_error(False, True))
152
+ # If the string is '', try to find a suitable
153
+ # default mode
154
+ if not mode_arg:
155
+ return PlotMode._get_default_mode(i, d)
156
+ # Otherwise, interpret the string as a mode
157
+ # alias (e.g. 'cartesian', 'parametric', etc)
158
+ else:
159
+ return PlotMode._get_aliased_mode(mode_arg, i, d)
160
+ else:
161
+ raise ValueError("PlotMode argument must be "
162
+ "a class or a string")
163
+
164
+ @staticmethod
165
+ def _get_default_mode(i, d, i_vars=-1):
166
+ if i_vars == -1:
167
+ i_vars = i
168
+ try:
169
+ return PlotMode._mode_default_map[d][i]
170
+ except KeyError:
171
+ # Keep looking for modes in higher i var counts
172
+ # which support the given d var count until we
173
+ # reach the max i_var count.
174
+ if i < PlotMode._i_var_max:
175
+ return PlotMode._get_default_mode(i + 1, d, i_vars)
176
+ else:
177
+ raise ValueError(("Couldn't find a default mode "
178
+ "for %i independent and %i "
179
+ "dependent variables.") % (i_vars, d))
180
+
181
+ @staticmethod
182
+ def _get_aliased_mode(alias, i, d, i_vars=-1):
183
+ if i_vars == -1:
184
+ i_vars = i
185
+ if alias not in PlotMode._mode_alias_list:
186
+ raise ValueError(("Couldn't find a mode called"
187
+ " %s. Known modes: %s.")
188
+ % (alias, ", ".join(PlotMode._mode_alias_list)))
189
+ try:
190
+ return PlotMode._mode_map[d][i][alias]
191
+ except TypeError:
192
+ # Keep looking for modes in higher i var counts
193
+ # which support the given d var count and alias
194
+ # until we reach the max i_var count.
195
+ if i < PlotMode._i_var_max:
196
+ return PlotMode._get_aliased_mode(alias, i + 1, d, i_vars)
197
+ else:
198
+ raise ValueError(("Couldn't find a %s mode "
199
+ "for %i independent and %i "
200
+ "dependent variables.")
201
+ % (alias, i_vars, d))
202
+
203
+ @classmethod
204
+ def _register(cls):
205
+ """
206
+ Called once for each user-usable plot mode.
207
+ For Cartesian2D, it is invoked after the
208
+ class definition: Cartesian2D._register()
209
+ """
210
+ name = cls.__name__
211
+ cls._init_mode()
212
+
213
+ try:
214
+ i, d = cls.i_var_count, cls.d_var_count
215
+ # Add the mode to _mode_map under all
216
+ # given aliases
217
+ for a in cls.aliases:
218
+ if a not in PlotMode._mode_alias_list:
219
+ # Also track valid aliases, so
220
+ # we can quickly know when given
221
+ # an invalid one in _get_mode.
222
+ PlotMode._mode_alias_list.append(a)
223
+ PlotMode._mode_map[d][i][a] = cls
224
+ if cls.is_default:
225
+ # If this mode was marked as the
226
+ # default for this d,i combination,
227
+ # also set that.
228
+ PlotMode._mode_default_map[d][i] = cls
229
+
230
+ except Exception as e:
231
+ raise RuntimeError(("Failed to register "
232
+ "plot mode %s. Reason: %s")
233
+ % (name, (str(e))))
234
+
235
+ @classmethod
236
+ def _init_mode(cls):
237
+ """
238
+ Initializes the plot mode based on
239
+ the 'mode-specific parameters' above.
240
+ Only intended to be called by
241
+ PlotMode._register(). To use a mode without
242
+ registering it, you can directly call
243
+ ModeSubclass._init_mode().
244
+ """
245
+ def symbols_list(symbol_str):
246
+ return [Symbol(s) for s in symbol_str]
247
+
248
+ # Convert the vars strs into
249
+ # lists of symbols.
250
+ cls.i_vars = symbols_list(cls.i_vars)
251
+ cls.d_vars = symbols_list(cls.d_vars)
252
+
253
+ # Var count is used often, calculate
254
+ # it once here
255
+ cls.i_var_count = len(cls.i_vars)
256
+ cls.d_var_count = len(cls.d_vars)
257
+
258
+ if cls.i_var_count > PlotMode._i_var_max:
259
+ raise ValueError(var_count_error(True, False))
260
+ if cls.d_var_count > PlotMode._d_var_max:
261
+ raise ValueError(var_count_error(False, False))
262
+
263
+ # Try to use first alias as primary_alias
264
+ if len(cls.aliases) > 0:
265
+ cls.primary_alias = cls.aliases[0]
266
+ else:
267
+ cls.primary_alias = cls.__name__
268
+
269
+ di = cls.intervals
270
+ if len(di) != cls.i_var_count:
271
+ raise ValueError("Plot mode must provide a "
272
+ "default interval for each i_var.")
273
+ for i in range(cls.i_var_count):
274
+ # default intervals must be given [min,max,steps]
275
+ # (no var, but they must be in the same order as i_vars)
276
+ if len(di[i]) != 3:
277
+ raise ValueError("length should be equal to 3")
278
+
279
+ # Initialize an incomplete interval,
280
+ # to later be filled with a var when
281
+ # the mode is instantiated.
282
+ di[i] = PlotInterval(None, *di[i])
283
+
284
+ # To prevent people from using modes
285
+ # without these required fields set up.
286
+ cls._was_initialized = True
287
+
288
+ _was_initialized = False
289
+
290
+ ## Initializer Helper Methods
291
+
292
+ @staticmethod
293
+ def _find_i_vars(functions, intervals):
294
+ i_vars = []
295
+
296
+ # First, collect i_vars in the
297
+ # order they are given in any
298
+ # intervals.
299
+ for i in intervals:
300
+ if i.v is None:
301
+ continue
302
+ elif i.v in i_vars:
303
+ raise ValueError(("Multiple intervals given "
304
+ "for %s.") % (str(i.v)))
305
+ i_vars.append(i.v)
306
+
307
+ # Then, find any remaining
308
+ # i_vars in given functions
309
+ # (aka d_vars)
310
+ for f in functions:
311
+ for a in f.free_symbols:
312
+ if a not in i_vars:
313
+ i_vars.append(a)
314
+
315
+ return i_vars
316
+
317
+ def _fill_i_vars(self, i_vars):
318
+ # copy default i_vars
319
+ self.i_vars = [Symbol(str(i)) for i in self.i_vars]
320
+ # replace with given i_vars
321
+ for i in range(len(i_vars)):
322
+ self.i_vars[i] = i_vars[i]
323
+
324
+ def _fill_intervals(self, intervals):
325
+ # copy default intervals
326
+ self.intervals = [PlotInterval(i) for i in self.intervals]
327
+ # track i_vars used so far
328
+ v_used = []
329
+ # fill copy of default
330
+ # intervals with given info
331
+ for i in range(len(intervals)):
332
+ self.intervals[i].fill_from(intervals[i])
333
+ if self.intervals[i].v is not None:
334
+ v_used.append(self.intervals[i].v)
335
+ # Find any orphan intervals and
336
+ # assign them i_vars
337
+ for i in range(len(self.intervals)):
338
+ if self.intervals[i].v is None:
339
+ u = [v for v in self.i_vars if v not in v_used]
340
+ if len(u) == 0:
341
+ raise ValueError("length should not be equal to 0")
342
+ self.intervals[i].v = u[0]
343
+ v_used.append(u[0])
344
+
345
+ @staticmethod
346
+ def _interpret_args(args):
347
+ interval_wrong_order = "PlotInterval %s was given before any function(s)."
348
+ interpret_error = "Could not interpret %s as a function or interval."
349
+
350
+ functions, intervals = [], []
351
+ if isinstance(args[0], GeometryEntity):
352
+ for coords in list(args[0].arbitrary_point()):
353
+ functions.append(coords)
354
+ intervals.append(PlotInterval.try_parse(args[0].plot_interval()))
355
+ else:
356
+ for a in args:
357
+ i = PlotInterval.try_parse(a)
358
+ if i is not None:
359
+ if len(functions) == 0:
360
+ raise ValueError(interval_wrong_order % (str(i)))
361
+ else:
362
+ intervals.append(i)
363
+ else:
364
+ if is_sequence(a, include=str):
365
+ raise ValueError(interpret_error % (str(a)))
366
+ try:
367
+ f = sympify(a)
368
+ functions.append(f)
369
+ except TypeError:
370
+ raise ValueError(interpret_error % str(a))
371
+
372
+ return functions, intervals
373
+
374
+ @staticmethod
375
+ def _extract_options(args, kwargs):
376
+ newkwargs, newargs = {}, []
377
+ for a in args:
378
+ if isinstance(a, str):
379
+ newkwargs = dict(newkwargs, **parse_option_string(a))
380
+ else:
381
+ newargs.append(a)
382
+ newkwargs = dict(newkwargs, **kwargs)
383
+ return newargs, newkwargs
384
+
385
+
386
+ def var_count_error(is_independent, is_plotting):
387
+ """
388
+ Used to format an error message which differs
389
+ slightly in 4 places.
390
+ """
391
+ if is_plotting:
392
+ v = "Plotting"
393
+ else:
394
+ v = "Registering plot modes"
395
+ if is_independent:
396
+ n, s = PlotMode._i_var_max, "independent"
397
+ else:
398
+ n, s = PlotMode._d_var_max, "dependent"
399
+ return ("%s with more than %i %s variables "
400
+ "is not supported.") % (v, n, s)
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_mode_base.py ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pyglet.gl as pgl
2
+ from sympy.core import S
3
+ from sympy.plotting.pygletplot.color_scheme import ColorScheme
4
+ from sympy.plotting.pygletplot.plot_mode import PlotMode
5
+ from sympy.utilities.iterables import is_sequence
6
+ from time import sleep
7
+ from threading import Thread, Event, RLock
8
+ import warnings
9
+
10
+
11
+ class PlotModeBase(PlotMode):
12
+ """
13
+ Intended parent class for plotting
14
+ modes. Provides base functionality
15
+ in conjunction with its parent,
16
+ PlotMode.
17
+ """
18
+
19
+ ##
20
+ ## Class-Level Attributes
21
+ ##
22
+
23
+ """
24
+ The following attributes are meant
25
+ to be set at the class level, and serve
26
+ as parameters to the plot mode registry
27
+ (in PlotMode). See plot_modes.py for
28
+ concrete examples.
29
+ """
30
+
31
+ """
32
+ i_vars
33
+ 'x' for Cartesian2D
34
+ 'xy' for Cartesian3D
35
+ etc.
36
+
37
+ d_vars
38
+ 'y' for Cartesian2D
39
+ 'r' for Polar
40
+ etc.
41
+ """
42
+ i_vars, d_vars = '', ''
43
+
44
+ """
45
+ intervals
46
+ Default intervals for each i_var, and in the
47
+ same order. Specified [min, max, steps].
48
+ No variable can be given (it is bound later).
49
+ """
50
+ intervals = []
51
+
52
+ """
53
+ aliases
54
+ A list of strings which can be used to
55
+ access this mode.
56
+ 'cartesian' for Cartesian2D and Cartesian3D
57
+ 'polar' for Polar
58
+ 'cylindrical', 'polar' for Cylindrical
59
+
60
+ Note that _init_mode chooses the first alias
61
+ in the list as the mode's primary_alias, which
62
+ will be displayed to the end user in certain
63
+ contexts.
64
+ """
65
+ aliases = []
66
+
67
+ """
68
+ is_default
69
+ Whether to set this mode as the default
70
+ for arguments passed to PlotMode() containing
71
+ the same number of d_vars as this mode and
72
+ at most the same number of i_vars.
73
+ """
74
+ is_default = False
75
+
76
+ """
77
+ All of the above attributes are defined in PlotMode.
78
+ The following ones are specific to PlotModeBase.
79
+ """
80
+
81
+ """
82
+ A list of the render styles. Do not modify.
83
+ """
84
+ styles = {'wireframe': 1, 'solid': 2, 'both': 3}
85
+
86
+ """
87
+ style_override
88
+ Always use this style if not blank.
89
+ """
90
+ style_override = ''
91
+
92
+ """
93
+ default_wireframe_color
94
+ default_solid_color
95
+ Can be used when color is None or being calculated.
96
+ Used by PlotCurve and PlotSurface, but not anywhere
97
+ in PlotModeBase.
98
+ """
99
+
100
+ default_wireframe_color = (0.85, 0.85, 0.85)
101
+ default_solid_color = (0.6, 0.6, 0.9)
102
+ default_rot_preset = 'xy'
103
+
104
+ ##
105
+ ## Instance-Level Attributes
106
+ ##
107
+
108
+ ## 'Abstract' member functions
109
+ def _get_evaluator(self):
110
+ if self.use_lambda_eval:
111
+ try:
112
+ e = self._get_lambda_evaluator()
113
+ return e
114
+ except Exception:
115
+ warnings.warn("\nWarning: creating lambda evaluator failed. "
116
+ "Falling back on SymPy subs evaluator.")
117
+ return self._get_sympy_evaluator()
118
+
119
+ def _get_sympy_evaluator(self):
120
+ raise NotImplementedError()
121
+
122
+ def _get_lambda_evaluator(self):
123
+ raise NotImplementedError()
124
+
125
+ def _on_calculate_verts(self):
126
+ raise NotImplementedError()
127
+
128
+ def _on_calculate_cverts(self):
129
+ raise NotImplementedError()
130
+
131
+ ## Base member functions
132
+ def __init__(self, *args, bounds_callback=None, **kwargs):
133
+ self.verts = []
134
+ self.cverts = []
135
+ self.bounds = [[S.Infinity, S.NegativeInfinity, 0],
136
+ [S.Infinity, S.NegativeInfinity, 0],
137
+ [S.Infinity, S.NegativeInfinity, 0]]
138
+ self.cbounds = [[S.Infinity, S.NegativeInfinity, 0],
139
+ [S.Infinity, S.NegativeInfinity, 0],
140
+ [S.Infinity, S.NegativeInfinity, 0]]
141
+
142
+ self._draw_lock = RLock()
143
+
144
+ self._calculating_verts = Event()
145
+ self._calculating_cverts = Event()
146
+ self._calculating_verts_pos = 0.0
147
+ self._calculating_verts_len = 0.0
148
+ self._calculating_cverts_pos = 0.0
149
+ self._calculating_cverts_len = 0.0
150
+
151
+ self._max_render_stack_size = 3
152
+ self._draw_wireframe = [-1]
153
+ self._draw_solid = [-1]
154
+
155
+ self._style = None
156
+ self._color = None
157
+
158
+ self.predraw = []
159
+ self.postdraw = []
160
+
161
+ self.use_lambda_eval = self.options.pop('use_sympy_eval', None) is None
162
+ self.style = self.options.pop('style', '')
163
+ self.color = self.options.pop('color', 'rainbow')
164
+ self.bounds_callback = bounds_callback
165
+
166
+ self._on_calculate()
167
+
168
+ def synchronized(f):
169
+ def w(self, *args, **kwargs):
170
+ self._draw_lock.acquire()
171
+ try:
172
+ r = f(self, *args, **kwargs)
173
+ return r
174
+ finally:
175
+ self._draw_lock.release()
176
+ return w
177
+
178
+ @synchronized
179
+ def push_wireframe(self, function):
180
+ """
181
+ Push a function which performs gl commands
182
+ used to build a display list. (The list is
183
+ built outside of the function)
184
+ """
185
+ assert callable(function)
186
+ self._draw_wireframe.append(function)
187
+ if len(self._draw_wireframe) > self._max_render_stack_size:
188
+ del self._draw_wireframe[1] # leave marker element
189
+
190
+ @synchronized
191
+ def push_solid(self, function):
192
+ """
193
+ Push a function which performs gl commands
194
+ used to build a display list. (The list is
195
+ built outside of the function)
196
+ """
197
+ assert callable(function)
198
+ self._draw_solid.append(function)
199
+ if len(self._draw_solid) > self._max_render_stack_size:
200
+ del self._draw_solid[1] # leave marker element
201
+
202
+ def _create_display_list(self, function):
203
+ dl = pgl.glGenLists(1)
204
+ pgl.glNewList(dl, pgl.GL_COMPILE)
205
+ function()
206
+ pgl.glEndList()
207
+ return dl
208
+
209
+ def _render_stack_top(self, render_stack):
210
+ top = render_stack[-1]
211
+ if top == -1:
212
+ return -1 # nothing to display
213
+ elif callable(top):
214
+ dl = self._create_display_list(top)
215
+ render_stack[-1] = (dl, top)
216
+ return dl # display newly added list
217
+ elif len(top) == 2:
218
+ if pgl.GL_TRUE == pgl.glIsList(top[0]):
219
+ return top[0] # display stored list
220
+ dl = self._create_display_list(top[1])
221
+ render_stack[-1] = (dl, top[1])
222
+ return dl # display regenerated list
223
+
224
+ def _draw_solid_display_list(self, dl):
225
+ pgl.glPushAttrib(pgl.GL_ENABLE_BIT | pgl.GL_POLYGON_BIT)
226
+ pgl.glPolygonMode(pgl.GL_FRONT_AND_BACK, pgl.GL_FILL)
227
+ pgl.glCallList(dl)
228
+ pgl.glPopAttrib()
229
+
230
+ def _draw_wireframe_display_list(self, dl):
231
+ pgl.glPushAttrib(pgl.GL_ENABLE_BIT | pgl.GL_POLYGON_BIT)
232
+ pgl.glPolygonMode(pgl.GL_FRONT_AND_BACK, pgl.GL_LINE)
233
+ pgl.glEnable(pgl.GL_POLYGON_OFFSET_LINE)
234
+ pgl.glPolygonOffset(-0.005, -50.0)
235
+ pgl.glCallList(dl)
236
+ pgl.glPopAttrib()
237
+
238
+ @synchronized
239
+ def draw(self):
240
+ for f in self.predraw:
241
+ if callable(f):
242
+ f()
243
+ if self.style_override:
244
+ style = self.styles[self.style_override]
245
+ else:
246
+ style = self.styles[self._style]
247
+ # Draw solid component if style includes solid
248
+ if style & 2:
249
+ dl = self._render_stack_top(self._draw_solid)
250
+ if dl > 0 and pgl.GL_TRUE == pgl.glIsList(dl):
251
+ self._draw_solid_display_list(dl)
252
+ # Draw wireframe component if style includes wireframe
253
+ if style & 1:
254
+ dl = self._render_stack_top(self._draw_wireframe)
255
+ if dl > 0 and pgl.GL_TRUE == pgl.glIsList(dl):
256
+ self._draw_wireframe_display_list(dl)
257
+ for f in self.postdraw:
258
+ if callable(f):
259
+ f()
260
+
261
+ def _on_change_color(self, color):
262
+ Thread(target=self._calculate_cverts).start()
263
+
264
+ def _on_calculate(self):
265
+ Thread(target=self._calculate_all).start()
266
+
267
+ def _calculate_all(self):
268
+ self._calculate_verts()
269
+ self._calculate_cverts()
270
+
271
+ def _calculate_verts(self):
272
+ if self._calculating_verts.is_set():
273
+ return
274
+ self._calculating_verts.set()
275
+ try:
276
+ self._on_calculate_verts()
277
+ finally:
278
+ self._calculating_verts.clear()
279
+ if callable(self.bounds_callback):
280
+ self.bounds_callback()
281
+
282
+ def _calculate_cverts(self):
283
+ if self._calculating_verts.is_set():
284
+ return
285
+ while self._calculating_cverts.is_set():
286
+ sleep(0) # wait for previous calculation
287
+ self._calculating_cverts.set()
288
+ try:
289
+ self._on_calculate_cverts()
290
+ finally:
291
+ self._calculating_cverts.clear()
292
+
293
+ def _get_calculating_verts(self):
294
+ return self._calculating_verts.is_set()
295
+
296
+ def _get_calculating_verts_pos(self):
297
+ return self._calculating_verts_pos
298
+
299
+ def _get_calculating_verts_len(self):
300
+ return self._calculating_verts_len
301
+
302
+ def _get_calculating_cverts(self):
303
+ return self._calculating_cverts.is_set()
304
+
305
+ def _get_calculating_cverts_pos(self):
306
+ return self._calculating_cverts_pos
307
+
308
+ def _get_calculating_cverts_len(self):
309
+ return self._calculating_cverts_len
310
+
311
+ ## Property handlers
312
+ def _get_style(self):
313
+ return self._style
314
+
315
+ @synchronized
316
+ def _set_style(self, v):
317
+ if v is None:
318
+ return
319
+ if v == '':
320
+ step_max = 0
321
+ for i in self.intervals:
322
+ if i.v_steps is None:
323
+ continue
324
+ step_max = max([step_max, int(i.v_steps)])
325
+ v = ['both', 'solid'][step_max > 40]
326
+ if v not in self.styles:
327
+ raise ValueError("v should be there in self.styles")
328
+ if v == self._style:
329
+ return
330
+ self._style = v
331
+
332
+ def _get_color(self):
333
+ return self._color
334
+
335
+ @synchronized
336
+ def _set_color(self, v):
337
+ try:
338
+ if v is not None:
339
+ if is_sequence(v):
340
+ v = ColorScheme(*v)
341
+ else:
342
+ v = ColorScheme(v)
343
+ if repr(v) == repr(self._color):
344
+ return
345
+ self._on_change_color(v)
346
+ self._color = v
347
+ except Exception as e:
348
+ raise RuntimeError("Color change failed. "
349
+ "Reason: %s" % (str(e)))
350
+
351
+ style = property(_get_style, _set_style)
352
+ color = property(_get_color, _set_color)
353
+
354
+ calculating_verts = property(_get_calculating_verts)
355
+ calculating_verts_pos = property(_get_calculating_verts_pos)
356
+ calculating_verts_len = property(_get_calculating_verts_len)
357
+
358
+ calculating_cverts = property(_get_calculating_cverts)
359
+ calculating_cverts_pos = property(_get_calculating_cverts_pos)
360
+ calculating_cverts_len = property(_get_calculating_cverts_len)
361
+
362
+ ## String representations
363
+
364
+ def __str__(self):
365
+ f = ", ".join(str(d) for d in self.d_vars)
366
+ o = "'mode=%s'" % (self.primary_alias)
367
+ return ", ".join([f, o])
368
+
369
+ def __repr__(self):
370
+ f = ", ".join(str(d) for d in self.d_vars)
371
+ i = ", ".join(str(i) for i in self.intervals)
372
+ d = [('mode', self.primary_alias),
373
+ ('color', str(self.color)),
374
+ ('style', str(self.style))]
375
+
376
+ o = "'%s'" % ("; ".join("%s=%s" % (k, v)
377
+ for k, v in d if v != 'None'))
378
+ return ", ".join([f, i, o])
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_modes.py ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.utilities.lambdify import lambdify
2
+ from sympy.core.numbers import pi
3
+ from sympy.functions import sin, cos
4
+ from sympy.plotting.pygletplot.plot_curve import PlotCurve
5
+ from sympy.plotting.pygletplot.plot_surface import PlotSurface
6
+
7
+ from math import sin as p_sin
8
+ from math import cos as p_cos
9
+
10
+
11
+ def float_vec3(f):
12
+ def inner(*args):
13
+ v = f(*args)
14
+ return float(v[0]), float(v[1]), float(v[2])
15
+ return inner
16
+
17
+
18
+ class Cartesian2D(PlotCurve):
19
+ i_vars, d_vars = 'x', 'y'
20
+ intervals = [[-5, 5, 100]]
21
+ aliases = ['cartesian']
22
+ is_default = True
23
+
24
+ def _get_sympy_evaluator(self):
25
+ fy = self.d_vars[0]
26
+ x = self.t_interval.v
27
+
28
+ @float_vec3
29
+ def e(_x):
30
+ return (_x, fy.subs(x, _x), 0.0)
31
+ return e
32
+
33
+ def _get_lambda_evaluator(self):
34
+ fy = self.d_vars[0]
35
+ x = self.t_interval.v
36
+ return lambdify([x], [x, fy, 0.0])
37
+
38
+
39
+ class Cartesian3D(PlotSurface):
40
+ i_vars, d_vars = 'xy', 'z'
41
+ intervals = [[-1, 1, 40], [-1, 1, 40]]
42
+ aliases = ['cartesian', 'monge']
43
+ is_default = True
44
+
45
+ def _get_sympy_evaluator(self):
46
+ fz = self.d_vars[0]
47
+ x = self.u_interval.v
48
+ y = self.v_interval.v
49
+
50
+ @float_vec3
51
+ def e(_x, _y):
52
+ return (_x, _y, fz.subs(x, _x).subs(y, _y))
53
+ return e
54
+
55
+ def _get_lambda_evaluator(self):
56
+ fz = self.d_vars[0]
57
+ x = self.u_interval.v
58
+ y = self.v_interval.v
59
+ return lambdify([x, y], [x, y, fz])
60
+
61
+
62
+ class ParametricCurve2D(PlotCurve):
63
+ i_vars, d_vars = 't', 'xy'
64
+ intervals = [[0, 2*pi, 100]]
65
+ aliases = ['parametric']
66
+ is_default = True
67
+
68
+ def _get_sympy_evaluator(self):
69
+ fx, fy = self.d_vars
70
+ t = self.t_interval.v
71
+
72
+ @float_vec3
73
+ def e(_t):
74
+ return (fx.subs(t, _t), fy.subs(t, _t), 0.0)
75
+ return e
76
+
77
+ def _get_lambda_evaluator(self):
78
+ fx, fy = self.d_vars
79
+ t = self.t_interval.v
80
+ return lambdify([t], [fx, fy, 0.0])
81
+
82
+
83
+ class ParametricCurve3D(PlotCurve):
84
+ i_vars, d_vars = 't', 'xyz'
85
+ intervals = [[0, 2*pi, 100]]
86
+ aliases = ['parametric']
87
+ is_default = True
88
+
89
+ def _get_sympy_evaluator(self):
90
+ fx, fy, fz = self.d_vars
91
+ t = self.t_interval.v
92
+
93
+ @float_vec3
94
+ def e(_t):
95
+ return (fx.subs(t, _t), fy.subs(t, _t), fz.subs(t, _t))
96
+ return e
97
+
98
+ def _get_lambda_evaluator(self):
99
+ fx, fy, fz = self.d_vars
100
+ t = self.t_interval.v
101
+ return lambdify([t], [fx, fy, fz])
102
+
103
+
104
+ class ParametricSurface(PlotSurface):
105
+ i_vars, d_vars = 'uv', 'xyz'
106
+ intervals = [[-1, 1, 40], [-1, 1, 40]]
107
+ aliases = ['parametric']
108
+ is_default = True
109
+
110
+ def _get_sympy_evaluator(self):
111
+ fx, fy, fz = self.d_vars
112
+ u = self.u_interval.v
113
+ v = self.v_interval.v
114
+
115
+ @float_vec3
116
+ def e(_u, _v):
117
+ return (fx.subs(u, _u).subs(v, _v),
118
+ fy.subs(u, _u).subs(v, _v),
119
+ fz.subs(u, _u).subs(v, _v))
120
+ return e
121
+
122
+ def _get_lambda_evaluator(self):
123
+ fx, fy, fz = self.d_vars
124
+ u = self.u_interval.v
125
+ v = self.v_interval.v
126
+ return lambdify([u, v], [fx, fy, fz])
127
+
128
+
129
+ class Polar(PlotCurve):
130
+ i_vars, d_vars = 't', 'r'
131
+ intervals = [[0, 2*pi, 100]]
132
+ aliases = ['polar']
133
+ is_default = False
134
+
135
+ def _get_sympy_evaluator(self):
136
+ fr = self.d_vars[0]
137
+ t = self.t_interval.v
138
+
139
+ def e(_t):
140
+ _r = float(fr.subs(t, _t))
141
+ return (_r*p_cos(_t), _r*p_sin(_t), 0.0)
142
+ return e
143
+
144
+ def _get_lambda_evaluator(self):
145
+ fr = self.d_vars[0]
146
+ t = self.t_interval.v
147
+ fx, fy = fr*cos(t), fr*sin(t)
148
+ return lambdify([t], [fx, fy, 0.0])
149
+
150
+
151
+ class Cylindrical(PlotSurface):
152
+ i_vars, d_vars = 'th', 'r'
153
+ intervals = [[0, 2*pi, 40], [-1, 1, 20]]
154
+ aliases = ['cylindrical', 'polar']
155
+ is_default = False
156
+
157
+ def _get_sympy_evaluator(self):
158
+ fr = self.d_vars[0]
159
+ t = self.u_interval.v
160
+ h = self.v_interval.v
161
+
162
+ def e(_t, _h):
163
+ _r = float(fr.subs(t, _t).subs(h, _h))
164
+ return (_r*p_cos(_t), _r*p_sin(_t), _h)
165
+ return e
166
+
167
+ def _get_lambda_evaluator(self):
168
+ fr = self.d_vars[0]
169
+ t = self.u_interval.v
170
+ h = self.v_interval.v
171
+ fx, fy = fr*cos(t), fr*sin(t)
172
+ return lambdify([t, h], [fx, fy, h])
173
+
174
+
175
+ class Spherical(PlotSurface):
176
+ i_vars, d_vars = 'tp', 'r'
177
+ intervals = [[0, 2*pi, 40], [0, pi, 20]]
178
+ aliases = ['spherical']
179
+ is_default = False
180
+
181
+ def _get_sympy_evaluator(self):
182
+ fr = self.d_vars[0]
183
+ t = self.u_interval.v
184
+ p = self.v_interval.v
185
+
186
+ def e(_t, _p):
187
+ _r = float(fr.subs(t, _t).subs(p, _p))
188
+ return (_r*p_cos(_t)*p_sin(_p),
189
+ _r*p_sin(_t)*p_sin(_p),
190
+ _r*p_cos(_p))
191
+ return e
192
+
193
+ def _get_lambda_evaluator(self):
194
+ fr = self.d_vars[0]
195
+ t = self.u_interval.v
196
+ p = self.v_interval.v
197
+ fx = fr * cos(t) * sin(p)
198
+ fy = fr * sin(t) * sin(p)
199
+ fz = fr * cos(p)
200
+ return lambdify([t, p], [fx, fy, fz])
201
+
202
+ Cartesian2D._register()
203
+ Cartesian3D._register()
204
+ ParametricCurve2D._register()
205
+ ParametricCurve3D._register()
206
+ ParametricSurface._register()
207
+ Polar._register()
208
+ Cylindrical._register()
209
+ Spherical._register()
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_object.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class PlotObject:
2
+ """
3
+ Base class for objects which can be displayed in
4
+ a Plot.
5
+ """
6
+ visible = True
7
+
8
+ def _draw(self):
9
+ if self.visible:
10
+ self.draw()
11
+
12
+ def draw(self):
13
+ """
14
+ OpenGL rendering code for the plot object.
15
+ Override in base class.
16
+ """
17
+ pass
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_rotation.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ try:
2
+ from ctypes import c_float
3
+ except ImportError:
4
+ pass
5
+
6
+ import pyglet.gl as pgl
7
+ from math import sqrt as _sqrt, acos as _acos
8
+
9
+
10
+ def cross(a, b):
11
+ return (a[1] * b[2] - a[2] * b[1],
12
+ a[2] * b[0] - a[0] * b[2],
13
+ a[0] * b[1] - a[1] * b[0])
14
+
15
+
16
+ def dot(a, b):
17
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
18
+
19
+
20
+ def mag(a):
21
+ return _sqrt(a[0]**2 + a[1]**2 + a[2]**2)
22
+
23
+
24
+ def norm(a):
25
+ m = mag(a)
26
+ return (a[0] / m, a[1] / m, a[2] / m)
27
+
28
+
29
+ def get_sphere_mapping(x, y, width, height):
30
+ x = min([max([x, 0]), width])
31
+ y = min([max([y, 0]), height])
32
+
33
+ sr = _sqrt((width/2)**2 + (height/2)**2)
34
+ sx = ((x - width / 2) / sr)
35
+ sy = ((y - height / 2) / sr)
36
+
37
+ sz = 1.0 - sx**2 - sy**2
38
+
39
+ if sz > 0.0:
40
+ sz = _sqrt(sz)
41
+ return (sx, sy, sz)
42
+ else:
43
+ sz = 0
44
+ return norm((sx, sy, sz))
45
+
46
+ rad2deg = 180.0 / 3.141592
47
+
48
+
49
+ def get_spherical_rotatation(p1, p2, width, height, theta_multiplier):
50
+ v1 = get_sphere_mapping(p1[0], p1[1], width, height)
51
+ v2 = get_sphere_mapping(p2[0], p2[1], width, height)
52
+
53
+ d = min(max([dot(v1, v2), -1]), 1)
54
+
55
+ if abs(d - 1.0) < 0.000001:
56
+ return None
57
+
58
+ raxis = norm( cross(v1, v2) )
59
+ rtheta = theta_multiplier * rad2deg * _acos(d)
60
+
61
+ pgl.glPushMatrix()
62
+ pgl.glLoadIdentity()
63
+ pgl.glRotatef(rtheta, *raxis)
64
+ mat = (c_float*16)()
65
+ pgl.glGetFloatv(pgl.GL_MODELVIEW_MATRIX, mat)
66
+ pgl.glPopMatrix()
67
+
68
+ return mat
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_surface.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pyglet.gl as pgl
2
+
3
+ from sympy.core import S
4
+ from sympy.plotting.pygletplot.plot_mode_base import PlotModeBase
5
+
6
+
7
+ class PlotSurface(PlotModeBase):
8
+
9
+ default_rot_preset = 'perspective'
10
+
11
+ def _on_calculate_verts(self):
12
+ self.u_interval = self.intervals[0]
13
+ self.u_set = list(self.u_interval.frange())
14
+ self.v_interval = self.intervals[1]
15
+ self.v_set = list(self.v_interval.frange())
16
+ self.bounds = [[S.Infinity, S.NegativeInfinity, 0],
17
+ [S.Infinity, S.NegativeInfinity, 0],
18
+ [S.Infinity, S.NegativeInfinity, 0]]
19
+ evaluate = self._get_evaluator()
20
+
21
+ self._calculating_verts_pos = 0.0
22
+ self._calculating_verts_len = float(
23
+ self.u_interval.v_len*self.v_interval.v_len)
24
+
25
+ verts = []
26
+ b = self.bounds
27
+ for u in self.u_set:
28
+ column = []
29
+ for v in self.v_set:
30
+ try:
31
+ _e = evaluate(u, v) # calculate vertex
32
+ except ZeroDivisionError:
33
+ _e = None
34
+ if _e is not None: # update bounding box
35
+ for axis in range(3):
36
+ b[axis][0] = min([b[axis][0], _e[axis]])
37
+ b[axis][1] = max([b[axis][1], _e[axis]])
38
+ column.append(_e)
39
+ self._calculating_verts_pos += 1.0
40
+
41
+ verts.append(column)
42
+ for axis in range(3):
43
+ b[axis][2] = b[axis][1] - b[axis][0]
44
+ if b[axis][2] == 0.0:
45
+ b[axis][2] = 1.0
46
+
47
+ self.verts = verts
48
+ self.push_wireframe(self.draw_verts(False, False))
49
+ self.push_solid(self.draw_verts(False, True))
50
+
51
+ def _on_calculate_cverts(self):
52
+ if not self.verts or not self.color:
53
+ return
54
+
55
+ def set_work_len(n):
56
+ self._calculating_cverts_len = float(n)
57
+
58
+ def inc_work_pos():
59
+ self._calculating_cverts_pos += 1.0
60
+ set_work_len(1)
61
+ self._calculating_cverts_pos = 0
62
+ self.cverts = self.color.apply_to_surface(self.verts,
63
+ self.u_set,
64
+ self.v_set,
65
+ set_len=set_work_len,
66
+ inc_pos=inc_work_pos)
67
+ self.push_solid(self.draw_verts(True, True))
68
+
69
+ def calculate_one_cvert(self, u, v):
70
+ vert = self.verts[u][v]
71
+ return self.color(vert[0], vert[1], vert[2],
72
+ self.u_set[u], self.v_set[v])
73
+
74
+ def draw_verts(self, use_cverts, use_solid_color):
75
+ def f():
76
+ for u in range(1, len(self.u_set)):
77
+ pgl.glBegin(pgl.GL_QUAD_STRIP)
78
+ for v in range(len(self.v_set)):
79
+ pa = self.verts[u - 1][v]
80
+ pb = self.verts[u][v]
81
+ if pa is None or pb is None:
82
+ pgl.glEnd()
83
+ pgl.glBegin(pgl.GL_QUAD_STRIP)
84
+ continue
85
+ if use_cverts:
86
+ ca = self.cverts[u - 1][v]
87
+ cb = self.cverts[u][v]
88
+ if ca is None:
89
+ ca = (0, 0, 0)
90
+ if cb is None:
91
+ cb = (0, 0, 0)
92
+ else:
93
+ if use_solid_color:
94
+ ca = cb = self.default_solid_color
95
+ else:
96
+ ca = cb = self.default_wireframe_color
97
+ pgl.glColor3f(*ca)
98
+ pgl.glVertex3f(*pa)
99
+ pgl.glColor3f(*cb)
100
+ pgl.glVertex3f(*pb)
101
+ pgl.glEnd()
102
+ return f
.venv/Lib/site-packages/sympy/plotting/pygletplot/plot_window.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from time import perf_counter
2
+
3
+
4
+ import pyglet.gl as pgl
5
+
6
+ from sympy.plotting.pygletplot.managed_window import ManagedWindow
7
+ from sympy.plotting.pygletplot.plot_camera import PlotCamera
8
+ from sympy.plotting.pygletplot.plot_controller import PlotController
9
+
10
+
11
+ class PlotWindow(ManagedWindow):
12
+
13
+ def __init__(self, plot, antialiasing=True, ortho=False,
14
+ invert_mouse_zoom=False, linewidth=1.5, caption="SymPy Plot",
15
+ **kwargs):
16
+ """
17
+ Named Arguments
18
+ ===============
19
+
20
+ antialiasing = True
21
+ True OR False
22
+ ortho = False
23
+ True OR False
24
+ invert_mouse_zoom = False
25
+ True OR False
26
+ """
27
+ self.plot = plot
28
+
29
+ self.camera = None
30
+ self._calculating = False
31
+
32
+ self.antialiasing = antialiasing
33
+ self.ortho = ortho
34
+ self.invert_mouse_zoom = invert_mouse_zoom
35
+ self.linewidth = linewidth
36
+ self.title = caption
37
+ self.last_caption_update = 0
38
+ self.caption_update_interval = 0.2
39
+ self.drawing_first_object = True
40
+
41
+ super().__init__(**kwargs)
42
+
43
+ def setup(self):
44
+ self.camera = PlotCamera(self, ortho=self.ortho)
45
+ self.controller = PlotController(self,
46
+ invert_mouse_zoom=self.invert_mouse_zoom)
47
+ self.push_handlers(self.controller)
48
+
49
+ pgl.glClearColor(1.0, 1.0, 1.0, 0.0)
50
+ pgl.glClearDepth(1.0)
51
+
52
+ pgl.glDepthFunc(pgl.GL_LESS)
53
+ pgl.glEnable(pgl.GL_DEPTH_TEST)
54
+
55
+ pgl.glEnable(pgl.GL_LINE_SMOOTH)
56
+ pgl.glShadeModel(pgl.GL_SMOOTH)
57
+ pgl.glLineWidth(self.linewidth)
58
+
59
+ pgl.glEnable(pgl.GL_BLEND)
60
+ pgl.glBlendFunc(pgl.GL_SRC_ALPHA, pgl.GL_ONE_MINUS_SRC_ALPHA)
61
+
62
+ if self.antialiasing:
63
+ pgl.glHint(pgl.GL_LINE_SMOOTH_HINT, pgl.GL_NICEST)
64
+ pgl.glHint(pgl.GL_POLYGON_SMOOTH_HINT, pgl.GL_NICEST)
65
+
66
+ self.camera.setup_projection()
67
+
68
+ def on_resize(self, w, h):
69
+ super().on_resize(w, h)
70
+ if self.camera is not None:
71
+ self.camera.setup_projection()
72
+
73
+ def update(self, dt):
74
+ self.controller.update(dt)
75
+
76
+ def draw(self):
77
+ self.plot._render_lock.acquire()
78
+ self.camera.apply_transformation()
79
+
80
+ calc_verts_pos, calc_verts_len = 0, 0
81
+ calc_cverts_pos, calc_cverts_len = 0, 0
82
+
83
+ should_update_caption = (perf_counter() - self.last_caption_update >
84
+ self.caption_update_interval)
85
+
86
+ if len(self.plot._functions.values()) == 0:
87
+ self.drawing_first_object = True
88
+
89
+ iterfunctions = iter(self.plot._functions.values())
90
+
91
+ for r in iterfunctions:
92
+ if self.drawing_first_object:
93
+ self.camera.set_rot_preset(r.default_rot_preset)
94
+ self.drawing_first_object = False
95
+
96
+ pgl.glPushMatrix()
97
+ r._draw()
98
+ pgl.glPopMatrix()
99
+
100
+ # might as well do this while we are
101
+ # iterating and have the lock rather
102
+ # than locking and iterating twice
103
+ # per frame:
104
+
105
+ if should_update_caption:
106
+ try:
107
+ if r.calculating_verts:
108
+ calc_verts_pos += r.calculating_verts_pos
109
+ calc_verts_len += r.calculating_verts_len
110
+ if r.calculating_cverts:
111
+ calc_cverts_pos += r.calculating_cverts_pos
112
+ calc_cverts_len += r.calculating_cverts_len
113
+ except ValueError:
114
+ pass
115
+
116
+ for r in self.plot._pobjects:
117
+ pgl.glPushMatrix()
118
+ r._draw()
119
+ pgl.glPopMatrix()
120
+
121
+ if should_update_caption:
122
+ self.update_caption(calc_verts_pos, calc_verts_len,
123
+ calc_cverts_pos, calc_cverts_len)
124
+ self.last_caption_update = perf_counter()
125
+
126
+ if self.plot._screenshot:
127
+ self.plot._screenshot._execute_saving()
128
+
129
+ self.plot._render_lock.release()
130
+
131
+ def update_caption(self, calc_verts_pos, calc_verts_len,
132
+ calc_cverts_pos, calc_cverts_len):
133
+ caption = self.title
134
+ if calc_verts_len or calc_cverts_len:
135
+ caption += " (calculating"
136
+ if calc_verts_len > 0:
137
+ p = (calc_verts_pos / calc_verts_len) * 100
138
+ caption += " vertices %i%%" % (p)
139
+ if calc_cverts_len > 0:
140
+ p = (calc_cverts_pos / calc_cverts_len) * 100
141
+ caption += " colors %i%%" % (p)
142
+ caption += ")"
143
+ if self.caption != caption:
144
+ self.set_caption(caption)
.venv/Lib/site-packages/sympy/plotting/pygletplot/tests/__init__.py ADDED
File without changes
.venv/Lib/site-packages/sympy/plotting/pygletplot/tests/test_plotting.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.external.importtools import import_module
2
+
3
+ disabled = False
4
+
5
+ # if pyglet.gl fails to import, e.g. opengl is missing, we disable the tests
6
+ pyglet_gl = import_module("pyglet.gl", catch=(OSError,))
7
+ pyglet_window = import_module("pyglet.window", catch=(OSError,))
8
+ if not pyglet_gl or not pyglet_window:
9
+ disabled = True
10
+
11
+
12
+ from sympy.core.symbol import symbols
13
+ from sympy.functions.elementary.exponential import log
14
+ from sympy.functions.elementary.trigonometric import (cos, sin)
15
+ x, y, z = symbols('x, y, z')
16
+
17
+
18
+ def test_plot_2d():
19
+ from sympy.plotting.pygletplot import PygletPlot
20
+ p = PygletPlot(x, [x, -5, 5, 4], visible=False)
21
+ p.wait_for_calculations()
22
+
23
+
24
+ def test_plot_2d_discontinuous():
25
+ from sympy.plotting.pygletplot import PygletPlot
26
+ p = PygletPlot(1/x, [x, -1, 1, 2], visible=False)
27
+ p.wait_for_calculations()
28
+
29
+
30
+ def test_plot_3d():
31
+ from sympy.plotting.pygletplot import PygletPlot
32
+ p = PygletPlot(x*y, [x, -5, 5, 5], [y, -5, 5, 5], visible=False)
33
+ p.wait_for_calculations()
34
+
35
+
36
+ def test_plot_3d_discontinuous():
37
+ from sympy.plotting.pygletplot import PygletPlot
38
+ p = PygletPlot(1/x, [x, -3, 3, 6], [y, -1, 1, 1], visible=False)
39
+ p.wait_for_calculations()
40
+
41
+
42
+ def test_plot_2d_polar():
43
+ from sympy.plotting.pygletplot import PygletPlot
44
+ p = PygletPlot(1/x, [x, -1, 1, 4], 'mode=polar', visible=False)
45
+ p.wait_for_calculations()
46
+
47
+
48
+ def test_plot_3d_cylinder():
49
+ from sympy.plotting.pygletplot import PygletPlot
50
+ p = PygletPlot(
51
+ 1/y, [x, 0, 6.282, 4], [y, -1, 1, 4], 'mode=polar;style=solid',
52
+ visible=False)
53
+ p.wait_for_calculations()
54
+
55
+
56
+ def test_plot_3d_spherical():
57
+ from sympy.plotting.pygletplot import PygletPlot
58
+ p = PygletPlot(
59
+ 1, [x, 0, 6.282, 4], [y, 0, 3.141,
60
+ 4], 'mode=spherical;style=wireframe',
61
+ visible=False)
62
+ p.wait_for_calculations()
63
+
64
+
65
+ def test_plot_2d_parametric():
66
+ from sympy.plotting.pygletplot import PygletPlot
67
+ p = PygletPlot(sin(x), cos(x), [x, 0, 6.282, 4], visible=False)
68
+ p.wait_for_calculations()
69
+
70
+
71
+ def test_plot_3d_parametric():
72
+ from sympy.plotting.pygletplot import PygletPlot
73
+ p = PygletPlot(sin(x), cos(x), x/5.0, [x, 0, 6.282, 4], visible=False)
74
+ p.wait_for_calculations()
75
+
76
+
77
+ def _test_plot_log():
78
+ from sympy.plotting.pygletplot import PygletPlot
79
+ p = PygletPlot(log(x), [x, 0, 6.282, 4], 'mode=polar', visible=False)
80
+ p.wait_for_calculations()
81
+
82
+
83
+ def test_plot_integral():
84
+ # Make sure it doesn't treat x as an independent variable
85
+ from sympy.plotting.pygletplot import PygletPlot
86
+ from sympy.integrals.integrals import Integral
87
+ p = PygletPlot(Integral(z*x, (x, 1, z), (z, 1, y)), visible=False)
88
+ p.wait_for_calculations()
.venv/Lib/site-packages/sympy/plotting/pygletplot/util.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ try:
2
+ from ctypes import c_float, c_int, c_double
3
+ except ImportError:
4
+ pass
5
+
6
+ import pyglet.gl as pgl
7
+ from sympy.core import S
8
+
9
+
10
+ def get_model_matrix(array_type=c_float, glGetMethod=pgl.glGetFloatv):
11
+ """
12
+ Returns the current modelview matrix.
13
+ """
14
+ m = (array_type*16)()
15
+ glGetMethod(pgl.GL_MODELVIEW_MATRIX, m)
16
+ return m
17
+
18
+
19
+ def get_projection_matrix(array_type=c_float, glGetMethod=pgl.glGetFloatv):
20
+ """
21
+ Returns the current modelview matrix.
22
+ """
23
+ m = (array_type*16)()
24
+ glGetMethod(pgl.GL_PROJECTION_MATRIX, m)
25
+ return m
26
+
27
+
28
+ def get_viewport():
29
+ """
30
+ Returns the current viewport.
31
+ """
32
+ m = (c_int*4)()
33
+ pgl.glGetIntegerv(pgl.GL_VIEWPORT, m)
34
+ return m
35
+
36
+
37
+ def get_direction_vectors():
38
+ m = get_model_matrix()
39
+ return ((m[0], m[4], m[8]),
40
+ (m[1], m[5], m[9]),
41
+ (m[2], m[6], m[10]))
42
+
43
+
44
+ def get_view_direction_vectors():
45
+ m = get_model_matrix()
46
+ return ((m[0], m[1], m[2]),
47
+ (m[4], m[5], m[6]),
48
+ (m[8], m[9], m[10]))
49
+
50
+
51
+ def get_basis_vectors():
52
+ return ((1, 0, 0), (0, 1, 0), (0, 0, 1))
53
+
54
+
55
+ def screen_to_model(x, y, z):
56
+ m = get_model_matrix(c_double, pgl.glGetDoublev)
57
+ p = get_projection_matrix(c_double, pgl.glGetDoublev)
58
+ w = get_viewport()
59
+ mx, my, mz = c_double(), c_double(), c_double()
60
+ pgl.gluUnProject(x, y, z, m, p, w, mx, my, mz)
61
+ return float(mx.value), float(my.value), float(mz.value)
62
+
63
+
64
+ def model_to_screen(x, y, z):
65
+ m = get_model_matrix(c_double, pgl.glGetDoublev)
66
+ p = get_projection_matrix(c_double, pgl.glGetDoublev)
67
+ w = get_viewport()
68
+ mx, my, mz = c_double(), c_double(), c_double()
69
+ pgl.gluProject(x, y, z, m, p, w, mx, my, mz)
70
+ return float(mx.value), float(my.value), float(mz.value)
71
+
72
+
73
+ def vec_subs(a, b):
74
+ return tuple(a[i] - b[i] for i in range(len(a)))
75
+
76
+
77
+ def billboard_matrix():
78
+ """
79
+ Removes rotational components of
80
+ current matrix so that primitives
81
+ are always drawn facing the viewer.
82
+
83
+ |1|0|0|x|
84
+ |0|1|0|x|
85
+ |0|0|1|x| (x means left unchanged)
86
+ |x|x|x|x|
87
+ """
88
+ m = get_model_matrix()
89
+ # XXX: for i in range(11): m[i] = i ?
90
+ m[0] = 1
91
+ m[1] = 0
92
+ m[2] = 0
93
+ m[4] = 0
94
+ m[5] = 1
95
+ m[6] = 0
96
+ m[8] = 0
97
+ m[9] = 0
98
+ m[10] = 1
99
+ pgl.glLoadMatrixf(m)
100
+
101
+
102
+ def create_bounds():
103
+ return [[S.Infinity, S.NegativeInfinity, 0],
104
+ [S.Infinity, S.NegativeInfinity, 0],
105
+ [S.Infinity, S.NegativeInfinity, 0]]
106
+
107
+
108
+ def update_bounds(b, v):
109
+ if v is None:
110
+ return
111
+ for axis in range(3):
112
+ b[axis][0] = min([b[axis][0], v[axis]])
113
+ b[axis][1] = max([b[axis][1], v[axis]])
114
+
115
+
116
+ def interpolate(a_min, a_max, a_ratio):
117
+ return a_min + a_ratio * (a_max - a_min)
118
+
119
+
120
+ def rinterpolate(a_min, a_max, a_value):
121
+ a_range = a_max - a_min
122
+ if a_max == a_min:
123
+ a_range = 1.0
124
+ return (a_value - a_min) / float(a_range)
125
+
126
+
127
+ def interpolate_color(color1, color2, ratio):
128
+ return tuple(interpolate(color1[i], color2[i], ratio) for i in range(3))
129
+
130
+
131
+ def scale_value(v, v_min, v_len):
132
+ return (v - v_min) / v_len
133
+
134
+
135
+ def scale_value_list(flist):
136
+ v_min, v_max = min(flist), max(flist)
137
+ v_len = v_max - v_min
138
+ return [scale_value(f, v_min, v_len) for f in flist]
139
+
140
+
141
+ def strided_range(r_min, r_max, stride, max_steps=50):
142
+ o_min, o_max = r_min, r_max
143
+ if abs(r_min - r_max) < 0.001:
144
+ return []
145
+ try:
146
+ range(int(r_min - r_max))
147
+ except (TypeError, OverflowError):
148
+ return []
149
+ if r_min > r_max:
150
+ raise ValueError("r_min cannot be greater than r_max")
151
+ r_min_s = (r_min % stride)
152
+ r_max_s = stride - (r_max % stride)
153
+ if abs(r_max_s - stride) < 0.001:
154
+ r_max_s = 0.0
155
+ r_min -= r_min_s
156
+ r_max += r_max_s
157
+ r_steps = int((r_max - r_min)/stride)
158
+ if max_steps and r_steps > max_steps:
159
+ return strided_range(o_min, o_max, stride*2)
160
+ return [r_min] + [r_min + e*stride for e in range(1, r_steps + 1)] + [r_max]
161
+
162
+
163
+ def parse_option_string(s):
164
+ if not isinstance(s, str):
165
+ return None
166
+ options = {}
167
+ for token in s.split(';'):
168
+ pieces = token.split('=')
169
+ if len(pieces) == 1:
170
+ option, value = pieces[0], ""
171
+ elif len(pieces) == 2:
172
+ option, value = pieces
173
+ else:
174
+ raise ValueError("Plot option string '%s' is malformed." % (s))
175
+ options[option.strip()] = value.strip()
176
+ return options
177
+
178
+
179
+ def dot_product(v1, v2):
180
+ return sum(v1[i]*v2[i] for i in range(3))
181
+
182
+
183
+ def vec_sub(v1, v2):
184
+ return tuple(v1[i] - v2[i] for i in range(3))
185
+
186
+
187
+ def vec_mag(v):
188
+ return sum(v[i]**2 for i in range(3))**(0.5)