koichi12 commited on
Commit
cf58bb1
·
verified ·
1 Parent(s): de8bd69

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. .gitattributes +1 -0
  2. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/matrices.cpython-311.pyc +0 -0
  3. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/paulialgebra.cpython-311.pyc +0 -0
  4. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/sho.cpython-311.pyc +0 -0
  5. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/curve.py +1763 -0
  6. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/__pycache__/__init__.cpython-311.pyc +0 -0
  7. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_mixin.cpython-311.pyc +0 -0
  8. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/test_activation.py +348 -0
  9. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/control/__init__.py +16 -0
  10. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/control/control_plots.py +978 -0
  11. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/tests/test_physics_matrices.py +84 -0
  12. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__init__.py +453 -0
  13. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/__init__.cpython-311.pyc +0 -0
  14. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/prefixes.cpython-311.pyc +0 -0
  15. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/quantities.cpython-311.pyc +0 -0
  16. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/definitions/__init__.py +265 -0
  17. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/dimensions.py +590 -0
  18. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/quantities.py +152 -0
  19. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/__init__.cpython-311.pyc +0 -0
  20. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/cgs.cpython-311.pyc +0 -0
  21. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/length_weight_time.cpython-311.pyc +0 -0
  22. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/mks.cpython-311.pyc +0 -0
  23. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/mksa.cpython-311.pyc +0 -0
  24. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/natural.cpython-311.pyc +0 -0
  25. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/si.cpython-311.pyc +0 -0
  26. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/cgs.py +82 -0
  27. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/length_weight_time.py +156 -0
  28. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/mks.py +46 -0
  29. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/mksa.py +54 -0
  30. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/natural.py +27 -0
  31. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/si.py +377 -0
  32. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__init__.py +0 -0
  33. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/__init__.cpython-311.pyc +0 -0
  34. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_dimensions.cpython-311.pyc +0 -0
  35. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_dimensionsystem.cpython-311.pyc +0 -0
  36. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_prefixes.cpython-311.pyc +0 -0
  37. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_quantities.cpython-311.pyc +0 -0
  38. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_unitsystem.cpython-311.pyc +0 -0
  39. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_util.cpython-311.pyc +0 -0
  40. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_dimensions.py +150 -0
  41. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_prefixes.py +86 -0
  42. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_unit_system_cgs_gauss.py +55 -0
  43. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_unitsystem.py +86 -0
  44. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_util.py +178 -0
  45. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/unitsystem.py +205 -0
  46. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/util.py +265 -0
  47. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/__pycache__/test_functions.cpython-311.pyc +0 -0
  48. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/__pycache__/test_printing.cpython-311.pyc +0 -0
  49. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/test_vector.py +274 -0
  50. tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/polys/__pycache__/appellseqs.cpython-311.pyc +0 -0
.gitattributes CHANGED
@@ -263,3 +263,4 @@ tuning-competition-baseline/.venv/lib/python3.11/site-packages/torch/_inductor/_
263
  .venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe filter=lfs diff=lfs merge=lfs -text
264
  .venv/lib/python3.11/site-packages/numpy.libs/libquadmath-96973f99.so.0.0.0 filter=lfs diff=lfs merge=lfs -text
265
  .venv/lib/python3.11/site-packages/numpy.libs/libgfortran-040039e1.so.5.0.0 filter=lfs diff=lfs merge=lfs -text
 
 
263
  .venv/lib/python3.11/site-packages/setuptools/gui-arm64.exe filter=lfs diff=lfs merge=lfs -text
264
  .venv/lib/python3.11/site-packages/numpy.libs/libquadmath-96973f99.so.0.0.0 filter=lfs diff=lfs merge=lfs -text
265
  .venv/lib/python3.11/site-packages/numpy.libs/libgfortran-040039e1.so.5.0.0 filter=lfs diff=lfs merge=lfs -text
266
+ tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/stats/__pycache__/stochastic_process_types.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/matrices.cpython-311.pyc ADDED
Binary file (4.56 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/paulialgebra.cpython-311.pyc ADDED
Binary file (8.87 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/__pycache__/sho.cpython-311.pyc ADDED
Binary file (3.5 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/curve.py ADDED
@@ -0,0 +1,1763 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Implementations of characteristic curves for musculotendon models."""
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from sympy.core.expr import UnevaluatedExpr
6
+ from sympy.core.function import ArgumentIndexError, Function
7
+ from sympy.core.numbers import Float, Integer
8
+ from sympy.functions.elementary.exponential import exp, log
9
+ from sympy.functions.elementary.hyperbolic import cosh, sinh
10
+ from sympy.functions.elementary.miscellaneous import sqrt
11
+ from sympy.printing.precedence import PRECEDENCE
12
+
13
+
14
+ __all__ = [
15
+ 'CharacteristicCurveCollection',
16
+ 'CharacteristicCurveFunction',
17
+ 'FiberForceLengthActiveDeGroote2016',
18
+ 'FiberForceLengthPassiveDeGroote2016',
19
+ 'FiberForceLengthPassiveInverseDeGroote2016',
20
+ 'FiberForceVelocityDeGroote2016',
21
+ 'FiberForceVelocityInverseDeGroote2016',
22
+ 'TendonForceLengthDeGroote2016',
23
+ 'TendonForceLengthInverseDeGroote2016',
24
+ ]
25
+
26
+
27
+ class CharacteristicCurveFunction(Function):
28
+ """Base class for all musculotendon characteristic curve functions."""
29
+
30
+ @classmethod
31
+ def eval(cls):
32
+ msg = (
33
+ f'Cannot directly instantiate {cls.__name__!r}, instances of '
34
+ f'characteristic curves must be of a concrete subclass.'
35
+
36
+ )
37
+ raise TypeError(msg)
38
+
39
+ def _print_code(self, printer):
40
+ """Print code for the function defining the curve using a printer.
41
+
42
+ Explanation
43
+ ===========
44
+
45
+ The order of operations may need to be controlled as constant folding
46
+ the numeric terms within the equations of a musculotendon
47
+ characteristic curve can sometimes results in a numerically-unstable
48
+ expression.
49
+
50
+ Parameters
51
+ ==========
52
+
53
+ printer : Printer
54
+ The printer to be used to print a string representation of the
55
+ characteristic curve as valid code in the target language.
56
+
57
+ """
58
+ return printer._print(printer.parenthesize(
59
+ self.doit(deep=False, evaluate=False), PRECEDENCE['Atom'],
60
+ ))
61
+
62
+ _ccode = _print_code
63
+ _cupycode = _print_code
64
+ _cxxcode = _print_code
65
+ _fcode = _print_code
66
+ _jaxcode = _print_code
67
+ _lambdacode = _print_code
68
+ _mpmathcode = _print_code
69
+ _octave = _print_code
70
+ _pythoncode = _print_code
71
+ _numpycode = _print_code
72
+ _scipycode = _print_code
73
+
74
+
75
+ class TendonForceLengthDeGroote2016(CharacteristicCurveFunction):
76
+ r"""Tendon force-length curve based on De Groote et al., 2016 [1]_.
77
+
78
+ Explanation
79
+ ===========
80
+
81
+ Gives the normalized tendon force produced as a function of normalized
82
+ tendon length.
83
+
84
+ The function is defined by the equation:
85
+
86
+ $fl^T = c_0 \exp{c_3 \left( \tilde{l}^T - c_1 \right)} - c_2$
87
+
88
+ with constant values of $c_0 = 0.2$, $c_1 = 0.995$, $c_2 = 0.25$, and
89
+ $c_3 = 33.93669377311689$.
90
+
91
+ While it is possible to change the constant values, these were carefully
92
+ selected in the original publication to give the characteristic curve
93
+ specific and required properties. For example, the function produces no
94
+ force when the tendon is in an unstrained state. It also produces a force
95
+ of 1 normalized unit when the tendon is under a 5% strain.
96
+
97
+ Examples
98
+ ========
99
+
100
+ The preferred way to instantiate :class:`TendonForceLengthDeGroote2016` is using
101
+ the :meth:`~.with_defaults` constructor because this will automatically
102
+ populate the constants within the characteristic curve equation with the
103
+ floating point values from the original publication. This constructor takes
104
+ a single argument corresponding to normalized tendon length. We'll create a
105
+ :class:`~.Symbol` called ``l_T_tilde`` to represent this.
106
+
107
+ >>> from sympy import Symbol
108
+ >>> from sympy.physics.biomechanics import TendonForceLengthDeGroote2016
109
+ >>> l_T_tilde = Symbol('l_T_tilde')
110
+ >>> fl_T = TendonForceLengthDeGroote2016.with_defaults(l_T_tilde)
111
+ >>> fl_T
112
+ TendonForceLengthDeGroote2016(l_T_tilde, 0.2, 0.995, 0.25,
113
+ 33.93669377311689)
114
+
115
+ It's also possible to populate the four constants with your own values too.
116
+
117
+ >>> from sympy import symbols
118
+ >>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3')
119
+ >>> fl_T = TendonForceLengthDeGroote2016(l_T_tilde, c0, c1, c2, c3)
120
+ >>> fl_T
121
+ TendonForceLengthDeGroote2016(l_T_tilde, c0, c1, c2, c3)
122
+
123
+ You don't just have to use symbols as the arguments, it's also possible to
124
+ use expressions. Let's create a new pair of symbols, ``l_T`` and
125
+ ``l_T_slack``, representing tendon length and tendon slack length
126
+ respectively. We can then represent ``l_T_tilde`` as an expression, the
127
+ ratio of these.
128
+
129
+ >>> l_T, l_T_slack = symbols('l_T l_T_slack')
130
+ >>> l_T_tilde = l_T/l_T_slack
131
+ >>> fl_T = TendonForceLengthDeGroote2016.with_defaults(l_T_tilde)
132
+ >>> fl_T
133
+ TendonForceLengthDeGroote2016(l_T/l_T_slack, 0.2, 0.995, 0.25,
134
+ 33.93669377311689)
135
+
136
+ To inspect the actual symbolic expression that this function represents,
137
+ we can call the :meth:`~.doit` method on an instance. We'll use the keyword
138
+ argument ``evaluate=False`` as this will keep the expression in its
139
+ canonical form and won't simplify any constants.
140
+
141
+ >>> fl_T.doit(evaluate=False)
142
+ -0.25 + 0.2*exp(33.93669377311689*(l_T/l_T_slack - 0.995))
143
+
144
+ The function can also be differentiated. We'll differentiate with respect
145
+ to l_T using the ``diff`` method on an instance with the single positional
146
+ argument ``l_T``.
147
+
148
+ >>> fl_T.diff(l_T)
149
+ 6.787338754623378*exp(33.93669377311689*(l_T/l_T_slack - 0.995))/l_T_slack
150
+
151
+ References
152
+ ==========
153
+
154
+ .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
155
+ of direct collocation optimal control problem formulations for
156
+ solving the muscle redundancy problem, Annals of biomedical
157
+ engineering, 44(10), (2016) pp. 2922-2936
158
+
159
+ """
160
+
161
+ @classmethod
162
+ def with_defaults(cls, l_T_tilde):
163
+ r"""Recommended constructor that will use the published constants.
164
+
165
+ Explanation
166
+ ===========
167
+
168
+ Returns a new instance of the tendon force-length function using the
169
+ four constant values specified in the original publication.
170
+
171
+ These have the values:
172
+
173
+ $c_0 = 0.2$
174
+ $c_1 = 0.995$
175
+ $c_2 = 0.25$
176
+ $c_3 = 33.93669377311689$
177
+
178
+ Parameters
179
+ ==========
180
+
181
+ l_T_tilde : Any (sympifiable)
182
+ Normalized tendon length.
183
+
184
+ """
185
+ c0 = Float('0.2')
186
+ c1 = Float('0.995')
187
+ c2 = Float('0.25')
188
+ c3 = Float('33.93669377311689')
189
+ return cls(l_T_tilde, c0, c1, c2, c3)
190
+
191
+ @classmethod
192
+ def eval(cls, l_T_tilde, c0, c1, c2, c3):
193
+ """Evaluation of basic inputs.
194
+
195
+ Parameters
196
+ ==========
197
+
198
+ l_T_tilde : Any (sympifiable)
199
+ Normalized tendon length.
200
+ c0 : Any (sympifiable)
201
+ The first constant in the characteristic equation. The published
202
+ value is ``0.2``.
203
+ c1 : Any (sympifiable)
204
+ The second constant in the characteristic equation. The published
205
+ value is ``0.995``.
206
+ c2 : Any (sympifiable)
207
+ The third constant in the characteristic equation. The published
208
+ value is ``0.25``.
209
+ c3 : Any (sympifiable)
210
+ The fourth constant in the characteristic equation. The published
211
+ value is ``33.93669377311689``.
212
+
213
+ """
214
+ pass
215
+
216
+ def _eval_evalf(self, prec):
217
+ """Evaluate the expression numerically using ``evalf``."""
218
+ return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
219
+
220
+ def doit(self, deep=True, evaluate=True, **hints):
221
+ """Evaluate the expression defining the function.
222
+
223
+ Parameters
224
+ ==========
225
+
226
+ deep : bool
227
+ Whether ``doit`` should be recursively called. Default is ``True``.
228
+ evaluate : bool.
229
+ Whether the SymPy expression should be evaluated as it is
230
+ constructed. If ``False``, then no constant folding will be
231
+ conducted which will leave the expression in a more numerically-
232
+ stable for values of ``l_T_tilde`` that correspond to a sensible
233
+ operating range for a musculotendon. Default is ``True``.
234
+ **kwargs : dict[str, Any]
235
+ Additional keyword argument pairs to be recursively passed to
236
+ ``doit``.
237
+
238
+ """
239
+ l_T_tilde, *constants = self.args
240
+ if deep:
241
+ hints['evaluate'] = evaluate
242
+ l_T_tilde = l_T_tilde.doit(deep=deep, **hints)
243
+ c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants]
244
+ else:
245
+ c0, c1, c2, c3 = constants
246
+
247
+ if evaluate:
248
+ return c0*exp(c3*(l_T_tilde - c1)) - c2
249
+
250
+ return c0*exp(c3*UnevaluatedExpr(l_T_tilde - c1)) - c2
251
+
252
+ def fdiff(self, argindex=1):
253
+ """Derivative of the function with respect to a single argument.
254
+
255
+ Parameters
256
+ ==========
257
+
258
+ argindex : int
259
+ The index of the function's arguments with respect to which the
260
+ derivative should be taken. Argument indexes start at ``1``.
261
+ Default is ``1``.
262
+
263
+ """
264
+ l_T_tilde, c0, c1, c2, c3 = self.args
265
+ if argindex == 1:
266
+ return c0*c3*exp(c3*UnevaluatedExpr(l_T_tilde - c1))
267
+ elif argindex == 2:
268
+ return exp(c3*UnevaluatedExpr(l_T_tilde - c1))
269
+ elif argindex == 3:
270
+ return -c0*c3*exp(c3*UnevaluatedExpr(l_T_tilde - c1))
271
+ elif argindex == 4:
272
+ return Integer(-1)
273
+ elif argindex == 5:
274
+ return c0*(l_T_tilde - c1)*exp(c3*UnevaluatedExpr(l_T_tilde - c1))
275
+
276
+ raise ArgumentIndexError(self, argindex)
277
+
278
+ def inverse(self, argindex=1):
279
+ """Inverse function.
280
+
281
+ Parameters
282
+ ==========
283
+
284
+ argindex : int
285
+ Value to start indexing the arguments at. Default is ``1``.
286
+
287
+ """
288
+ return TendonForceLengthInverseDeGroote2016
289
+
290
+ def _latex(self, printer):
291
+ """Print a LaTeX representation of the function defining the curve.
292
+
293
+ Parameters
294
+ ==========
295
+
296
+ printer : Printer
297
+ The printer to be used to print the LaTeX string representation.
298
+
299
+ """
300
+ l_T_tilde = self.args[0]
301
+ _l_T_tilde = printer._print(l_T_tilde)
302
+ return r'\operatorname{fl}^T \left( %s \right)' % _l_T_tilde
303
+
304
+
305
+ class TendonForceLengthInverseDeGroote2016(CharacteristicCurveFunction):
306
+ r"""Inverse tendon force-length curve based on De Groote et al., 2016 [1]_.
307
+
308
+ Explanation
309
+ ===========
310
+
311
+ Gives the normalized tendon length that produces a specific normalized
312
+ tendon force.
313
+
314
+ The function is defined by the equation:
315
+
316
+ ${fl^T}^{-1} = frac{\log{\frac{fl^T + c_2}{c_0}}}{c_3} + c_1$
317
+
318
+ with constant values of $c_0 = 0.2$, $c_1 = 0.995$, $c_2 = 0.25$, and
319
+ $c_3 = 33.93669377311689$. This function is the exact analytical inverse
320
+ of the related tendon force-length curve ``TendonForceLengthDeGroote2016``.
321
+
322
+ While it is possible to change the constant values, these were carefully
323
+ selected in the original publication to give the characteristic curve
324
+ specific and required properties. For example, the function produces no
325
+ force when the tendon is in an unstrained state. It also produces a force
326
+ of 1 normalized unit when the tendon is under a 5% strain.
327
+
328
+ Examples
329
+ ========
330
+
331
+ The preferred way to instantiate :class:`TendonForceLengthInverseDeGroote2016` is
332
+ using the :meth:`~.with_defaults` constructor because this will automatically
333
+ populate the constants within the characteristic curve equation with the
334
+ floating point values from the original publication. This constructor takes
335
+ a single argument corresponding to normalized tendon force-length, which is
336
+ equal to the tendon force. We'll create a :class:`~.Symbol` called ``fl_T`` to
337
+ represent this.
338
+
339
+ >>> from sympy import Symbol
340
+ >>> from sympy.physics.biomechanics import TendonForceLengthInverseDeGroote2016
341
+ >>> fl_T = Symbol('fl_T')
342
+ >>> l_T_tilde = TendonForceLengthInverseDeGroote2016.with_defaults(fl_T)
343
+ >>> l_T_tilde
344
+ TendonForceLengthInverseDeGroote2016(fl_T, 0.2, 0.995, 0.25,
345
+ 33.93669377311689)
346
+
347
+ It's also possible to populate the four constants with your own values too.
348
+
349
+ >>> from sympy import symbols
350
+ >>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3')
351
+ >>> l_T_tilde = TendonForceLengthInverseDeGroote2016(fl_T, c0, c1, c2, c3)
352
+ >>> l_T_tilde
353
+ TendonForceLengthInverseDeGroote2016(fl_T, c0, c1, c2, c3)
354
+
355
+ To inspect the actual symbolic expression that this function represents,
356
+ we can call the :meth:`~.doit` method on an instance. We'll use the keyword
357
+ argument ``evaluate=False`` as this will keep the expression in its
358
+ canonical form and won't simplify any constants.
359
+
360
+ >>> l_T_tilde.doit(evaluate=False)
361
+ c1 + log((c2 + fl_T)/c0)/c3
362
+
363
+ The function can also be differentiated. We'll differentiate with respect
364
+ to l_T using the ``diff`` method on an instance with the single positional
365
+ argument ``l_T``.
366
+
367
+ >>> l_T_tilde.diff(fl_T)
368
+ 1/(c3*(c2 + fl_T))
369
+
370
+ References
371
+ ==========
372
+
373
+ .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
374
+ of direct collocation optimal control problem formulations for
375
+ solving the muscle redundancy problem, Annals of biomedical
376
+ engineering, 44(10), (2016) pp. 2922-2936
377
+
378
+ """
379
+
380
+ @classmethod
381
+ def with_defaults(cls, fl_T):
382
+ r"""Recommended constructor that will use the published constants.
383
+
384
+ Explanation
385
+ ===========
386
+
387
+ Returns a new instance of the inverse tendon force-length function
388
+ using the four constant values specified in the original publication.
389
+
390
+ These have the values:
391
+
392
+ $c_0 = 0.2$
393
+ $c_1 = 0.995$
394
+ $c_2 = 0.25$
395
+ $c_3 = 33.93669377311689$
396
+
397
+ Parameters
398
+ ==========
399
+
400
+ fl_T : Any (sympifiable)
401
+ Normalized tendon force as a function of tendon length.
402
+
403
+ """
404
+ c0 = Float('0.2')
405
+ c1 = Float('0.995')
406
+ c2 = Float('0.25')
407
+ c3 = Float('33.93669377311689')
408
+ return cls(fl_T, c0, c1, c2, c3)
409
+
410
+ @classmethod
411
+ def eval(cls, fl_T, c0, c1, c2, c3):
412
+ """Evaluation of basic inputs.
413
+
414
+ Parameters
415
+ ==========
416
+
417
+ fl_T : Any (sympifiable)
418
+ Normalized tendon force as a function of tendon length.
419
+ c0 : Any (sympifiable)
420
+ The first constant in the characteristic equation. The published
421
+ value is ``0.2``.
422
+ c1 : Any (sympifiable)
423
+ The second constant in the characteristic equation. The published
424
+ value is ``0.995``.
425
+ c2 : Any (sympifiable)
426
+ The third constant in the characteristic equation. The published
427
+ value is ``0.25``.
428
+ c3 : Any (sympifiable)
429
+ The fourth constant in the characteristic equation. The published
430
+ value is ``33.93669377311689``.
431
+
432
+ """
433
+ pass
434
+
435
+ def _eval_evalf(self, prec):
436
+ """Evaluate the expression numerically using ``evalf``."""
437
+ return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
438
+
439
+ def doit(self, deep=True, evaluate=True, **hints):
440
+ """Evaluate the expression defining the function.
441
+
442
+ Parameters
443
+ ==========
444
+
445
+ deep : bool
446
+ Whether ``doit`` should be recursively called. Default is ``True``.
447
+ evaluate : bool.
448
+ Whether the SymPy expression should be evaluated as it is
449
+ constructed. If ``False``, then no constant folding will be
450
+ conducted which will leave the expression in a more numerically-
451
+ stable for values of ``l_T_tilde`` that correspond to a sensible
452
+ operating range for a musculotendon. Default is ``True``.
453
+ **kwargs : dict[str, Any]
454
+ Additional keyword argument pairs to be recursively passed to
455
+ ``doit``.
456
+
457
+ """
458
+ fl_T, *constants = self.args
459
+ if deep:
460
+ hints['evaluate'] = evaluate
461
+ fl_T = fl_T.doit(deep=deep, **hints)
462
+ c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants]
463
+ else:
464
+ c0, c1, c2, c3 = constants
465
+
466
+ if evaluate:
467
+ return log((fl_T + c2)/c0)/c3 + c1
468
+
469
+ return log(UnevaluatedExpr((fl_T + c2)/c0))/c3 + c1
470
+
471
+ def fdiff(self, argindex=1):
472
+ """Derivative of the function with respect to a single argument.
473
+
474
+ Parameters
475
+ ==========
476
+
477
+ argindex : int
478
+ The index of the function's arguments with respect to which the
479
+ derivative should be taken. Argument indexes start at ``1``.
480
+ Default is ``1``.
481
+
482
+ """
483
+ fl_T, c0, c1, c2, c3 = self.args
484
+ if argindex == 1:
485
+ return 1/(c3*(fl_T + c2))
486
+ elif argindex == 2:
487
+ return -1/(c0*c3)
488
+ elif argindex == 3:
489
+ return Integer(1)
490
+ elif argindex == 4:
491
+ return 1/(c3*(fl_T + c2))
492
+ elif argindex == 5:
493
+ return -log(UnevaluatedExpr((fl_T + c2)/c0))/c3**2
494
+
495
+ raise ArgumentIndexError(self, argindex)
496
+
497
+ def inverse(self, argindex=1):
498
+ """Inverse function.
499
+
500
+ Parameters
501
+ ==========
502
+
503
+ argindex : int
504
+ Value to start indexing the arguments at. Default is ``1``.
505
+
506
+ """
507
+ return TendonForceLengthDeGroote2016
508
+
509
+ def _latex(self, printer):
510
+ """Print a LaTeX representation of the function defining the curve.
511
+
512
+ Parameters
513
+ ==========
514
+
515
+ printer : Printer
516
+ The printer to be used to print the LaTeX string representation.
517
+
518
+ """
519
+ fl_T = self.args[0]
520
+ _fl_T = printer._print(fl_T)
521
+ return r'\left( \operatorname{fl}^T \right)^{-1} \left( %s \right)' % _fl_T
522
+
523
+
524
+ class FiberForceLengthPassiveDeGroote2016(CharacteristicCurveFunction):
525
+ r"""Passive muscle fiber force-length curve based on De Groote et al., 2016
526
+ [1]_.
527
+
528
+ Explanation
529
+ ===========
530
+
531
+ The function is defined by the equation:
532
+
533
+ $fl^M_{pas} = \frac{\frac{\exp{c_1 \left(\tilde{l^M} - 1\right)}}{c_0} - 1}{\exp{c_1} - 1}$
534
+
535
+ with constant values of $c_0 = 0.6$ and $c_1 = 4.0$.
536
+
537
+ While it is possible to change the constant values, these were carefully
538
+ selected in the original publication to give the characteristic curve
539
+ specific and required properties. For example, the function produces a
540
+ passive fiber force very close to 0 for all normalized fiber lengths
541
+ between 0 and 1.
542
+
543
+ Examples
544
+ ========
545
+
546
+ The preferred way to instantiate :class:`FiberForceLengthPassiveDeGroote2016` is
547
+ using the :meth:`~.with_defaults` constructor because this will automatically
548
+ populate the constants within the characteristic curve equation with the
549
+ floating point values from the original publication. This constructor takes
550
+ a single argument corresponding to normalized muscle fiber length. We'll
551
+ create a :class:`~.Symbol` called ``l_M_tilde`` to represent this.
552
+
553
+ >>> from sympy import Symbol
554
+ >>> from sympy.physics.biomechanics import FiberForceLengthPassiveDeGroote2016
555
+ >>> l_M_tilde = Symbol('l_M_tilde')
556
+ >>> fl_M = FiberForceLengthPassiveDeGroote2016.with_defaults(l_M_tilde)
557
+ >>> fl_M
558
+ FiberForceLengthPassiveDeGroote2016(l_M_tilde, 0.6, 4.0)
559
+
560
+ It's also possible to populate the two constants with your own values too.
561
+
562
+ >>> from sympy import symbols
563
+ >>> c0, c1 = symbols('c0 c1')
564
+ >>> fl_M = FiberForceLengthPassiveDeGroote2016(l_M_tilde, c0, c1)
565
+ >>> fl_M
566
+ FiberForceLengthPassiveDeGroote2016(l_M_tilde, c0, c1)
567
+
568
+ You don't just have to use symbols as the arguments, it's also possible to
569
+ use expressions. Let's create a new pair of symbols, ``l_M`` and
570
+ ``l_M_opt``, representing muscle fiber length and optimal muscle fiber
571
+ length respectively. We can then represent ``l_M_tilde`` as an expression,
572
+ the ratio of these.
573
+
574
+ >>> l_M, l_M_opt = symbols('l_M l_M_opt')
575
+ >>> l_M_tilde = l_M/l_M_opt
576
+ >>> fl_M = FiberForceLengthPassiveDeGroote2016.with_defaults(l_M_tilde)
577
+ >>> fl_M
578
+ FiberForceLengthPassiveDeGroote2016(l_M/l_M_opt, 0.6, 4.0)
579
+
580
+ To inspect the actual symbolic expression that this function represents,
581
+ we can call the :meth:`~.doit` method on an instance. We'll use the keyword
582
+ argument ``evaluate=False`` as this will keep the expression in its
583
+ canonical form and won't simplify any constants.
584
+
585
+ >>> fl_M.doit(evaluate=False)
586
+ 0.0186573603637741*(-1 + exp(6.66666666666667*(l_M/l_M_opt - 1)))
587
+
588
+ The function can also be differentiated. We'll differentiate with respect
589
+ to l_M using the ``diff`` method on an instance with the single positional
590
+ argument ``l_M``.
591
+
592
+ >>> fl_M.diff(l_M)
593
+ 0.12438240242516*exp(6.66666666666667*(l_M/l_M_opt - 1))/l_M_opt
594
+
595
+ References
596
+ ==========
597
+
598
+ .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
599
+ of direct collocation optimal control problem formulations for
600
+ solving the muscle redundancy problem, Annals of biomedical
601
+ engineering, 44(10), (2016) pp. 2922-2936
602
+
603
+ """
604
+
605
+ @classmethod
606
+ def with_defaults(cls, l_M_tilde):
607
+ r"""Recommended constructor that will use the published constants.
608
+
609
+ Explanation
610
+ ===========
611
+
612
+ Returns a new instance of the muscle fiber passive force-length
613
+ function using the four constant values specified in the original
614
+ publication.
615
+
616
+ These have the values:
617
+
618
+ $c_0 = 0.6$
619
+ $c_1 = 4.0$
620
+
621
+ Parameters
622
+ ==========
623
+
624
+ l_M_tilde : Any (sympifiable)
625
+ Normalized muscle fiber length.
626
+
627
+ """
628
+ c0 = Float('0.6')
629
+ c1 = Float('4.0')
630
+ return cls(l_M_tilde, c0, c1)
631
+
632
+ @classmethod
633
+ def eval(cls, l_M_tilde, c0, c1):
634
+ """Evaluation of basic inputs.
635
+
636
+ Parameters
637
+ ==========
638
+
639
+ l_M_tilde : Any (sympifiable)
640
+ Normalized muscle fiber length.
641
+ c0 : Any (sympifiable)
642
+ The first constant in the characteristic equation. The published
643
+ value is ``0.6``.
644
+ c1 : Any (sympifiable)
645
+ The second constant in the characteristic equation. The published
646
+ value is ``4.0``.
647
+
648
+ """
649
+ pass
650
+
651
+ def _eval_evalf(self, prec):
652
+ """Evaluate the expression numerically using ``evalf``."""
653
+ return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
654
+
655
+ def doit(self, deep=True, evaluate=True, **hints):
656
+ """Evaluate the expression defining the function.
657
+
658
+ Parameters
659
+ ==========
660
+
661
+ deep : bool
662
+ Whether ``doit`` should be recursively called. Default is ``True``.
663
+ evaluate : bool.
664
+ Whether the SymPy expression should be evaluated as it is
665
+ constructed. If ``False``, then no constant folding will be
666
+ conducted which will leave the expression in a more numerically-
667
+ stable for values of ``l_T_tilde`` that correspond to a sensible
668
+ operating range for a musculotendon. Default is ``True``.
669
+ **kwargs : dict[str, Any]
670
+ Additional keyword argument pairs to be recursively passed to
671
+ ``doit``.
672
+
673
+ """
674
+ l_M_tilde, *constants = self.args
675
+ if deep:
676
+ hints['evaluate'] = evaluate
677
+ l_M_tilde = l_M_tilde.doit(deep=deep, **hints)
678
+ c0, c1 = [c.doit(deep=deep, **hints) for c in constants]
679
+ else:
680
+ c0, c1 = constants
681
+
682
+ if evaluate:
683
+ return (exp((c1*(l_M_tilde - 1))/c0) - 1)/(exp(c1) - 1)
684
+
685
+ return (exp((c1*UnevaluatedExpr(l_M_tilde - 1))/c0) - 1)/(exp(c1) - 1)
686
+
687
+ def fdiff(self, argindex=1):
688
+ """Derivative of the function with respect to a single argument.
689
+
690
+ Parameters
691
+ ==========
692
+
693
+ argindex : int
694
+ The index of the function's arguments with respect to which the
695
+ derivative should be taken. Argument indexes start at ``1``.
696
+ Default is ``1``.
697
+
698
+ """
699
+ l_M_tilde, c0, c1 = self.args
700
+ if argindex == 1:
701
+ return c1*exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0)/(c0*(exp(c1) - 1))
702
+ elif argindex == 2:
703
+ return (
704
+ -c1*exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0)
705
+ *UnevaluatedExpr(l_M_tilde - 1)/(c0**2*(exp(c1) - 1))
706
+ )
707
+ elif argindex == 3:
708
+ return (
709
+ -exp(c1)*(-1 + exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0))/(exp(c1) - 1)**2
710
+ + exp(c1*UnevaluatedExpr(l_M_tilde - 1)/c0)*(l_M_tilde - 1)/(c0*(exp(c1) - 1))
711
+ )
712
+
713
+ raise ArgumentIndexError(self, argindex)
714
+
715
+ def inverse(self, argindex=1):
716
+ """Inverse function.
717
+
718
+ Parameters
719
+ ==========
720
+
721
+ argindex : int
722
+ Value to start indexing the arguments at. Default is ``1``.
723
+
724
+ """
725
+ return FiberForceLengthPassiveInverseDeGroote2016
726
+
727
+ def _latex(self, printer):
728
+ """Print a LaTeX representation of the function defining the curve.
729
+
730
+ Parameters
731
+ ==========
732
+
733
+ printer : Printer
734
+ The printer to be used to print the LaTeX string representation.
735
+
736
+ """
737
+ l_M_tilde = self.args[0]
738
+ _l_M_tilde = printer._print(l_M_tilde)
739
+ return r'\operatorname{fl}^M_{pas} \left( %s \right)' % _l_M_tilde
740
+
741
+
742
+ class FiberForceLengthPassiveInverseDeGroote2016(CharacteristicCurveFunction):
743
+ r"""Inverse passive muscle fiber force-length curve based on De Groote et
744
+ al., 2016 [1]_.
745
+
746
+ Explanation
747
+ ===========
748
+
749
+ Gives the normalized muscle fiber length that produces a specific normalized
750
+ passive muscle fiber force.
751
+
752
+ The function is defined by the equation:
753
+
754
+ ${fl^M_{pas}}^{-1} = \frac{c_0 \log{\left(\exp{c_1} - 1\right)fl^M_pas + 1}}{c_1} + 1$
755
+
756
+ with constant values of $c_0 = 0.6$ and $c_1 = 4.0$. This function is the
757
+ exact analytical inverse of the related tendon force-length curve
758
+ ``FiberForceLengthPassiveDeGroote2016``.
759
+
760
+ While it is possible to change the constant values, these were carefully
761
+ selected in the original publication to give the characteristic curve
762
+ specific and required properties. For example, the function produces a
763
+ passive fiber force very close to 0 for all normalized fiber lengths
764
+ between 0 and 1.
765
+
766
+ Examples
767
+ ========
768
+
769
+ The preferred way to instantiate
770
+ :class:`FiberForceLengthPassiveInverseDeGroote2016` is using the
771
+ :meth:`~.with_defaults` constructor because this will automatically populate the
772
+ constants within the characteristic curve equation with the floating point
773
+ values from the original publication. This constructor takes a single
774
+ argument corresponding to the normalized passive muscle fiber length-force
775
+ component of the muscle fiber force. We'll create a :class:`~.Symbol` called
776
+ ``fl_M_pas`` to represent this.
777
+
778
+ >>> from sympy import Symbol
779
+ >>> from sympy.physics.biomechanics import FiberForceLengthPassiveInverseDeGroote2016
780
+ >>> fl_M_pas = Symbol('fl_M_pas')
781
+ >>> l_M_tilde = FiberForceLengthPassiveInverseDeGroote2016.with_defaults(fl_M_pas)
782
+ >>> l_M_tilde
783
+ FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, 0.6, 4.0)
784
+
785
+ It's also possible to populate the two constants with your own values too.
786
+
787
+ >>> from sympy import symbols
788
+ >>> c0, c1 = symbols('c0 c1')
789
+ >>> l_M_tilde = FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, c0, c1)
790
+ >>> l_M_tilde
791
+ FiberForceLengthPassiveInverseDeGroote2016(fl_M_pas, c0, c1)
792
+
793
+ To inspect the actual symbolic expression that this function represents,
794
+ we can call the :meth:`~.doit` method on an instance. We'll use the keyword
795
+ argument ``evaluate=False`` as this will keep the expression in its
796
+ canonical form and won't simplify any constants.
797
+
798
+ >>> l_M_tilde.doit(evaluate=False)
799
+ c0*log(1 + fl_M_pas*(exp(c1) - 1))/c1 + 1
800
+
801
+ The function can also be differentiated. We'll differentiate with respect
802
+ to fl_M_pas using the ``diff`` method on an instance with the single positional
803
+ argument ``fl_M_pas``.
804
+
805
+ >>> l_M_tilde.diff(fl_M_pas)
806
+ c0*(exp(c1) - 1)/(c1*(fl_M_pas*(exp(c1) - 1) + 1))
807
+
808
+ References
809
+ ==========
810
+
811
+ .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
812
+ of direct collocation optimal control problem formulations for
813
+ solving the muscle redundancy problem, Annals of biomedical
814
+ engineering, 44(10), (2016) pp. 2922-2936
815
+
816
+ """
817
+
818
+ @classmethod
819
+ def with_defaults(cls, fl_M_pas):
820
+ r"""Recommended constructor that will use the published constants.
821
+
822
+ Explanation
823
+ ===========
824
+
825
+ Returns a new instance of the inverse muscle fiber passive force-length
826
+ function using the four constant values specified in the original
827
+ publication.
828
+
829
+ These have the values:
830
+
831
+ $c_0 = 0.6$
832
+ $c_1 = 4.0$
833
+
834
+ Parameters
835
+ ==========
836
+
837
+ fl_M_pas : Any (sympifiable)
838
+ Normalized passive muscle fiber force as a function of muscle fiber
839
+ length.
840
+
841
+ """
842
+ c0 = Float('0.6')
843
+ c1 = Float('4.0')
844
+ return cls(fl_M_pas, c0, c1)
845
+
846
+ @classmethod
847
+ def eval(cls, fl_M_pas, c0, c1):
848
+ """Evaluation of basic inputs.
849
+
850
+ Parameters
851
+ ==========
852
+
853
+ fl_M_pas : Any (sympifiable)
854
+ Normalized passive muscle fiber force.
855
+ c0 : Any (sympifiable)
856
+ The first constant in the characteristic equation. The published
857
+ value is ``0.6``.
858
+ c1 : Any (sympifiable)
859
+ The second constant in the characteristic equation. The published
860
+ value is ``4.0``.
861
+
862
+ """
863
+ pass
864
+
865
+ def _eval_evalf(self, prec):
866
+ """Evaluate the expression numerically using ``evalf``."""
867
+ return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
868
+
869
+ def doit(self, deep=True, evaluate=True, **hints):
870
+ """Evaluate the expression defining the function.
871
+
872
+ Parameters
873
+ ==========
874
+
875
+ deep : bool
876
+ Whether ``doit`` should be recursively called. Default is ``True``.
877
+ evaluate : bool.
878
+ Whether the SymPy expression should be evaluated as it is
879
+ constructed. If ``False``, then no constant folding will be
880
+ conducted which will leave the expression in a more numerically-
881
+ stable for values of ``l_T_tilde`` that correspond to a sensible
882
+ operating range for a musculotendon. Default is ``True``.
883
+ **kwargs : dict[str, Any]
884
+ Additional keyword argument pairs to be recursively passed to
885
+ ``doit``.
886
+
887
+ """
888
+ fl_M_pas, *constants = self.args
889
+ if deep:
890
+ hints['evaluate'] = evaluate
891
+ fl_M_pas = fl_M_pas.doit(deep=deep, **hints)
892
+ c0, c1 = [c.doit(deep=deep, **hints) for c in constants]
893
+ else:
894
+ c0, c1 = constants
895
+
896
+ if evaluate:
897
+ return c0*log(fl_M_pas*(exp(c1) - 1) + 1)/c1 + 1
898
+
899
+ return c0*log(UnevaluatedExpr(fl_M_pas*(exp(c1) - 1)) + 1)/c1 + 1
900
+
901
+ def fdiff(self, argindex=1):
902
+ """Derivative of the function with respect to a single argument.
903
+
904
+ Parameters
905
+ ==========
906
+
907
+ argindex : int
908
+ The index of the function's arguments with respect to which the
909
+ derivative should be taken. Argument indexes start at ``1``.
910
+ Default is ``1``.
911
+
912
+ """
913
+ fl_M_pas, c0, c1 = self.args
914
+ if argindex == 1:
915
+ return c0*(exp(c1) - 1)/(c1*(fl_M_pas*(exp(c1) - 1) + 1))
916
+ elif argindex == 2:
917
+ return log(fl_M_pas*(exp(c1) - 1) + 1)/c1
918
+ elif argindex == 3:
919
+ return (
920
+ c0*fl_M_pas*exp(c1)/(c1*(fl_M_pas*(exp(c1) - 1) + 1))
921
+ - c0*log(fl_M_pas*(exp(c1) - 1) + 1)/c1**2
922
+ )
923
+
924
+ raise ArgumentIndexError(self, argindex)
925
+
926
+ def inverse(self, argindex=1):
927
+ """Inverse function.
928
+
929
+ Parameters
930
+ ==========
931
+
932
+ argindex : int
933
+ Value to start indexing the arguments at. Default is ``1``.
934
+
935
+ """
936
+ return FiberForceLengthPassiveDeGroote2016
937
+
938
+ def _latex(self, printer):
939
+ """Print a LaTeX representation of the function defining the curve.
940
+
941
+ Parameters
942
+ ==========
943
+
944
+ printer : Printer
945
+ The printer to be used to print the LaTeX string representation.
946
+
947
+ """
948
+ fl_M_pas = self.args[0]
949
+ _fl_M_pas = printer._print(fl_M_pas)
950
+ return r'\left( \operatorname{fl}^M_{pas} \right)^{-1} \left( %s \right)' % _fl_M_pas
951
+
952
+
953
+ class FiberForceLengthActiveDeGroote2016(CharacteristicCurveFunction):
954
+ r"""Active muscle fiber force-length curve based on De Groote et al., 2016
955
+ [1]_.
956
+
957
+ Explanation
958
+ ===========
959
+
960
+ The function is defined by the equation:
961
+
962
+ $fl_{\text{act}}^M = c_0 \exp\left(-\frac{1}{2}\left(\frac{\tilde{l}^M - c_1}{c_2 + c_3 \tilde{l}^M}\right)^2\right)
963
+ + c_4 \exp\left(-\frac{1}{2}\left(\frac{\tilde{l}^M - c_5}{c_6 + c_7 \tilde{l}^M}\right)^2\right)
964
+ + c_8 \exp\left(-\frac{1}{2}\left(\frac{\tilde{l}^M - c_9}{c_{10} + c_{11} \tilde{l}^M}\right)^2\right)$
965
+
966
+ with constant values of $c0 = 0.814$, $c1 = 1.06$, $c2 = 0.162$,
967
+ $c3 = 0.0633$, $c4 = 0.433$, $c5 = 0.717$, $c6 = -0.0299$, $c7 = 0.2$,
968
+ $c8 = 0.1$, $c9 = 1.0$, $c10 = 0.354$, and $c11 = 0.0$.
969
+
970
+ While it is possible to change the constant values, these were carefully
971
+ selected in the original publication to give the characteristic curve
972
+ specific and required properties. For example, the function produces a
973
+ active fiber force of 1 at a normalized fiber length of 1, and an active
974
+ fiber force of 0 at normalized fiber lengths of 0 and 2.
975
+
976
+ Examples
977
+ ========
978
+
979
+ The preferred way to instantiate :class:`FiberForceLengthActiveDeGroote2016` is
980
+ using the :meth:`~.with_defaults` constructor because this will automatically
981
+ populate the constants within the characteristic curve equation with the
982
+ floating point values from the original publication. This constructor takes
983
+ a single argument corresponding to normalized muscle fiber length. We'll
984
+ create a :class:`~.Symbol` called ``l_M_tilde`` to represent this.
985
+
986
+ >>> from sympy import Symbol
987
+ >>> from sympy.physics.biomechanics import FiberForceLengthActiveDeGroote2016
988
+ >>> l_M_tilde = Symbol('l_M_tilde')
989
+ >>> fl_M = FiberForceLengthActiveDeGroote2016.with_defaults(l_M_tilde)
990
+ >>> fl_M
991
+ FiberForceLengthActiveDeGroote2016(l_M_tilde, 0.814, 1.06, 0.162, 0.0633,
992
+ 0.433, 0.717, -0.0299, 0.2, 0.1, 1.0, 0.354, 0.0)
993
+
994
+ It's also possible to populate the two constants with your own values too.
995
+
996
+ >>> from sympy import symbols
997
+ >>> c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = symbols('c0:12')
998
+ >>> fl_M = FiberForceLengthActiveDeGroote2016(l_M_tilde, c0, c1, c2, c3,
999
+ ... c4, c5, c6, c7, c8, c9, c10, c11)
1000
+ >>> fl_M
1001
+ FiberForceLengthActiveDeGroote2016(l_M_tilde, c0, c1, c2, c3, c4, c5, c6,
1002
+ c7, c8, c9, c10, c11)
1003
+
1004
+ You don't just have to use symbols as the arguments, it's also possible to
1005
+ use expressions. Let's create a new pair of symbols, ``l_M`` and
1006
+ ``l_M_opt``, representing muscle fiber length and optimal muscle fiber
1007
+ length respectively. We can then represent ``l_M_tilde`` as an expression,
1008
+ the ratio of these.
1009
+
1010
+ >>> l_M, l_M_opt = symbols('l_M l_M_opt')
1011
+ >>> l_M_tilde = l_M/l_M_opt
1012
+ >>> fl_M = FiberForceLengthActiveDeGroote2016.with_defaults(l_M_tilde)
1013
+ >>> fl_M
1014
+ FiberForceLengthActiveDeGroote2016(l_M/l_M_opt, 0.814, 1.06, 0.162, 0.0633,
1015
+ 0.433, 0.717, -0.0299, 0.2, 0.1, 1.0, 0.354, 0.0)
1016
+
1017
+ To inspect the actual symbolic expression that this function represents,
1018
+ we can call the :meth:`~.doit` method on an instance. We'll use the keyword
1019
+ argument ``evaluate=False`` as this will keep the expression in its
1020
+ canonical form and won't simplify any constants.
1021
+
1022
+ >>> fl_M.doit(evaluate=False)
1023
+ 0.814*exp(-19.0519737844841*(l_M/l_M_opt
1024
+ - 1.06)**2/(0.390740740740741*l_M/l_M_opt + 1)**2)
1025
+ + 0.433*exp(-12.5*(l_M/l_M_opt - 0.717)**2/(l_M/l_M_opt - 0.1495)**2)
1026
+ + 0.1*exp(-3.98991349867535*(l_M/l_M_opt - 1.0)**2)
1027
+
1028
+ The function can also be differentiated. We'll differentiate with respect
1029
+ to l_M using the ``diff`` method on an instance with the single positional
1030
+ argument ``l_M``.
1031
+
1032
+ >>> fl_M.diff(l_M)
1033
+ ((-0.79798269973507*l_M/l_M_opt
1034
+ + 0.79798269973507)*exp(-3.98991349867535*(l_M/l_M_opt - 1.0)**2)
1035
+ + (10.825*(-l_M/l_M_opt + 0.717)/(l_M/l_M_opt - 0.1495)**2
1036
+ + 10.825*(l_M/l_M_opt - 0.717)**2/(l_M/l_M_opt
1037
+ - 0.1495)**3)*exp(-12.5*(l_M/l_M_opt - 0.717)**2/(l_M/l_M_opt - 0.1495)**2)
1038
+ + (31.0166133211401*(-l_M/l_M_opt + 1.06)/(0.390740740740741*l_M/l_M_opt
1039
+ + 1)**2 + 13.6174190361677*(0.943396226415094*l_M/l_M_opt
1040
+ - 1)**2/(0.390740740740741*l_M/l_M_opt
1041
+ + 1)**3)*exp(-21.4067977442463*(0.943396226415094*l_M/l_M_opt
1042
+ - 1)**2/(0.390740740740741*l_M/l_M_opt + 1)**2))/l_M_opt
1043
+
1044
+ References
1045
+ ==========
1046
+
1047
+ .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
1048
+ of direct collocation optimal control problem formulations for
1049
+ solving the muscle redundancy problem, Annals of biomedical
1050
+ engineering, 44(10), (2016) pp. 2922-2936
1051
+
1052
+ """
1053
+
1054
+ @classmethod
1055
+ def with_defaults(cls, l_M_tilde):
1056
+ r"""Recommended constructor that will use the published constants.
1057
+
1058
+ Explanation
1059
+ ===========
1060
+
1061
+ Returns a new instance of the inverse muscle fiber act force-length
1062
+ function using the four constant values specified in the original
1063
+ publication.
1064
+
1065
+ These have the values:
1066
+
1067
+ $c0 = 0.814$
1068
+ $c1 = 1.06$
1069
+ $c2 = 0.162$
1070
+ $c3 = 0.0633$
1071
+ $c4 = 0.433$
1072
+ $c5 = 0.717$
1073
+ $c6 = -0.0299$
1074
+ $c7 = 0.2$
1075
+ $c8 = 0.1$
1076
+ $c9 = 1.0$
1077
+ $c10 = 0.354$
1078
+ $c11 = 0.0$
1079
+
1080
+ Parameters
1081
+ ==========
1082
+
1083
+ fl_M_act : Any (sympifiable)
1084
+ Normalized passive muscle fiber force as a function of muscle fiber
1085
+ length.
1086
+
1087
+ """
1088
+ c0 = Float('0.814')
1089
+ c1 = Float('1.06')
1090
+ c2 = Float('0.162')
1091
+ c3 = Float('0.0633')
1092
+ c4 = Float('0.433')
1093
+ c5 = Float('0.717')
1094
+ c6 = Float('-0.0299')
1095
+ c7 = Float('0.2')
1096
+ c8 = Float('0.1')
1097
+ c9 = Float('1.0')
1098
+ c10 = Float('0.354')
1099
+ c11 = Float('0.0')
1100
+ return cls(l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11)
1101
+
1102
+ @classmethod
1103
+ def eval(cls, l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11):
1104
+ """Evaluation of basic inputs.
1105
+
1106
+ Parameters
1107
+ ==========
1108
+
1109
+ l_M_tilde : Any (sympifiable)
1110
+ Normalized muscle fiber length.
1111
+ c0 : Any (sympifiable)
1112
+ The first constant in the characteristic equation. The published
1113
+ value is ``0.814``.
1114
+ c1 : Any (sympifiable)
1115
+ The second constant in the characteristic equation. The published
1116
+ value is ``1.06``.
1117
+ c2 : Any (sympifiable)
1118
+ The third constant in the characteristic equation. The published
1119
+ value is ``0.162``.
1120
+ c3 : Any (sympifiable)
1121
+ The fourth constant in the characteristic equation. The published
1122
+ value is ``0.0633``.
1123
+ c4 : Any (sympifiable)
1124
+ The fifth constant in the characteristic equation. The published
1125
+ value is ``0.433``.
1126
+ c5 : Any (sympifiable)
1127
+ The sixth constant in the characteristic equation. The published
1128
+ value is ``0.717``.
1129
+ c6 : Any (sympifiable)
1130
+ The seventh constant in the characteristic equation. The published
1131
+ value is ``-0.0299``.
1132
+ c7 : Any (sympifiable)
1133
+ The eighth constant in the characteristic equation. The published
1134
+ value is ``0.2``.
1135
+ c8 : Any (sympifiable)
1136
+ The ninth constant in the characteristic equation. The published
1137
+ value is ``0.1``.
1138
+ c9 : Any (sympifiable)
1139
+ The tenth constant in the characteristic equation. The published
1140
+ value is ``1.0``.
1141
+ c10 : Any (sympifiable)
1142
+ The eleventh constant in the characteristic equation. The published
1143
+ value is ``0.354``.
1144
+ c11 : Any (sympifiable)
1145
+ The tweflth constant in the characteristic equation. The published
1146
+ value is ``0.0``.
1147
+
1148
+ """
1149
+ pass
1150
+
1151
+ def _eval_evalf(self, prec):
1152
+ """Evaluate the expression numerically using ``evalf``."""
1153
+ return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
1154
+
1155
+ def doit(self, deep=True, evaluate=True, **hints):
1156
+ """Evaluate the expression defining the function.
1157
+
1158
+ Parameters
1159
+ ==========
1160
+
1161
+ deep : bool
1162
+ Whether ``doit`` should be recursively called. Default is ``True``.
1163
+ evaluate : bool.
1164
+ Whether the SymPy expression should be evaluated as it is
1165
+ constructed. If ``False``, then no constant folding will be
1166
+ conducted which will leave the expression in a more numerically-
1167
+ stable for values of ``l_M_tilde`` that correspond to a sensible
1168
+ operating range for a musculotendon. Default is ``True``.
1169
+ **kwargs : dict[str, Any]
1170
+ Additional keyword argument pairs to be recursively passed to
1171
+ ``doit``.
1172
+
1173
+ """
1174
+ l_M_tilde, *constants = self.args
1175
+ if deep:
1176
+ hints['evaluate'] = evaluate
1177
+ l_M_tilde = l_M_tilde.doit(deep=deep, **hints)
1178
+ constants = [c.doit(deep=deep, **hints) for c in constants]
1179
+ c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = constants
1180
+
1181
+ if evaluate:
1182
+ return (
1183
+ c0*exp(-(((l_M_tilde - c1)/(c2 + c3*l_M_tilde))**2)/2)
1184
+ + c4*exp(-(((l_M_tilde - c5)/(c6 + c7*l_M_tilde))**2)/2)
1185
+ + c8*exp(-(((l_M_tilde - c9)/(c10 + c11*l_M_tilde))**2)/2)
1186
+ )
1187
+
1188
+ return (
1189
+ c0*exp(-((UnevaluatedExpr(l_M_tilde - c1)/(c2 + c3*l_M_tilde))**2)/2)
1190
+ + c4*exp(-((UnevaluatedExpr(l_M_tilde - c5)/(c6 + c7*l_M_tilde))**2)/2)
1191
+ + c8*exp(-((UnevaluatedExpr(l_M_tilde - c9)/(c10 + c11*l_M_tilde))**2)/2)
1192
+ )
1193
+
1194
+ def fdiff(self, argindex=1):
1195
+ """Derivative of the function with respect to a single argument.
1196
+
1197
+ Parameters
1198
+ ==========
1199
+
1200
+ argindex : int
1201
+ The index of the function's arguments with respect to which the
1202
+ derivative should be taken. Argument indexes start at ``1``.
1203
+ Default is ``1``.
1204
+
1205
+ """
1206
+ l_M_tilde, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11 = self.args
1207
+ if argindex == 1:
1208
+ return (
1209
+ c0*(
1210
+ c3*(l_M_tilde - c1)**2/(c2 + c3*l_M_tilde)**3
1211
+ + (c1 - l_M_tilde)/((c2 + c3*l_M_tilde)**2)
1212
+ )*exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2))
1213
+ + c4*(
1214
+ c7*(l_M_tilde - c5)**2/(c6 + c7*l_M_tilde)**3
1215
+ + (c5 - l_M_tilde)/((c6 + c7*l_M_tilde)**2)
1216
+ )*exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2))
1217
+ + c8*(
1218
+ c11*(l_M_tilde - c9)**2/(c10 + c11*l_M_tilde)**3
1219
+ + (c9 - l_M_tilde)/((c10 + c11*l_M_tilde)**2)
1220
+ )*exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2))
1221
+ )
1222
+ elif argindex == 2:
1223
+ return exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2))
1224
+ elif argindex == 3:
1225
+ return (
1226
+ c0*(l_M_tilde - c1)/(c2 + c3*l_M_tilde)**2
1227
+ *exp(-(l_M_tilde - c1)**2 /(2*(c2 + c3*l_M_tilde)**2))
1228
+ )
1229
+ elif argindex == 4:
1230
+ return (
1231
+ c0*(l_M_tilde - c1)**2/(c2 + c3*l_M_tilde)**3
1232
+ *exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2))
1233
+ )
1234
+ elif argindex == 5:
1235
+ return (
1236
+ c0*l_M_tilde*(l_M_tilde - c1)**2/(c2 + c3*l_M_tilde)**3
1237
+ *exp(-(l_M_tilde - c1)**2/(2*(c2 + c3*l_M_tilde)**2))
1238
+ )
1239
+ elif argindex == 6:
1240
+ return exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2))
1241
+ elif argindex == 7:
1242
+ return (
1243
+ c4*(l_M_tilde - c5)/(c6 + c7*l_M_tilde)**2
1244
+ *exp(-(l_M_tilde - c5)**2 /(2*(c6 + c7*l_M_tilde)**2))
1245
+ )
1246
+ elif argindex == 8:
1247
+ return (
1248
+ c4*(l_M_tilde - c5)**2/(c6 + c7*l_M_tilde)**3
1249
+ *exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2))
1250
+ )
1251
+ elif argindex == 9:
1252
+ return (
1253
+ c4*l_M_tilde*(l_M_tilde - c5)**2/(c6 + c7*l_M_tilde)**3
1254
+ *exp(-(l_M_tilde - c5)**2/(2*(c6 + c7*l_M_tilde)**2))
1255
+ )
1256
+ elif argindex == 10:
1257
+ return exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2))
1258
+ elif argindex == 11:
1259
+ return (
1260
+ c8*(l_M_tilde - c9)/(c10 + c11*l_M_tilde)**2
1261
+ *exp(-(l_M_tilde - c9)**2 /(2*(c10 + c11*l_M_tilde)**2))
1262
+ )
1263
+ elif argindex == 12:
1264
+ return (
1265
+ c8*(l_M_tilde - c9)**2/(c10 + c11*l_M_tilde)**3
1266
+ *exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2))
1267
+ )
1268
+ elif argindex == 13:
1269
+ return (
1270
+ c8*l_M_tilde*(l_M_tilde - c9)**2/(c10 + c11*l_M_tilde)**3
1271
+ *exp(-(l_M_tilde - c9)**2/(2*(c10 + c11*l_M_tilde)**2))
1272
+ )
1273
+
1274
+ raise ArgumentIndexError(self, argindex)
1275
+
1276
+ def _latex(self, printer):
1277
+ """Print a LaTeX representation of the function defining the curve.
1278
+
1279
+ Parameters
1280
+ ==========
1281
+
1282
+ printer : Printer
1283
+ The printer to be used to print the LaTeX string representation.
1284
+
1285
+ """
1286
+ l_M_tilde = self.args[0]
1287
+ _l_M_tilde = printer._print(l_M_tilde)
1288
+ return r'\operatorname{fl}^M_{act} \left( %s \right)' % _l_M_tilde
1289
+
1290
+
1291
+ class FiberForceVelocityDeGroote2016(CharacteristicCurveFunction):
1292
+ r"""Muscle fiber force-velocity curve based on De Groote et al., 2016 [1]_.
1293
+
1294
+ Explanation
1295
+ ===========
1296
+
1297
+ Gives the normalized muscle fiber force produced as a function of
1298
+ normalized tendon velocity.
1299
+
1300
+ The function is defined by the equation:
1301
+
1302
+ $fv^M = c_0 \log{\left(c_1 \tilde{v}_m + c_2\right) + \sqrt{\left(c_1 \tilde{v}_m + c_2\right)^2 + 1}} + c_3$
1303
+
1304
+ with constant values of $c_0 = -0.318$, $c_1 = -8.149$, $c_2 = -0.374$, and
1305
+ $c_3 = 0.886$.
1306
+
1307
+ While it is possible to change the constant values, these were carefully
1308
+ selected in the original publication to give the characteristic curve
1309
+ specific and required properties. For example, the function produces a
1310
+ normalized muscle fiber force of 1 when the muscle fibers are contracting
1311
+ isometrically (they have an extension rate of 0).
1312
+
1313
+ Examples
1314
+ ========
1315
+
1316
+ The preferred way to instantiate :class:`FiberForceVelocityDeGroote2016` is using
1317
+ the :meth:`~.with_defaults` constructor because this will automatically populate
1318
+ the constants within the characteristic curve equation with the floating
1319
+ point values from the original publication. This constructor takes a single
1320
+ argument corresponding to normalized muscle fiber extension velocity. We'll
1321
+ create a :class:`~.Symbol` called ``v_M_tilde`` to represent this.
1322
+
1323
+ >>> from sympy import Symbol
1324
+ >>> from sympy.physics.biomechanics import FiberForceVelocityDeGroote2016
1325
+ >>> v_M_tilde = Symbol('v_M_tilde')
1326
+ >>> fv_M = FiberForceVelocityDeGroote2016.with_defaults(v_M_tilde)
1327
+ >>> fv_M
1328
+ FiberForceVelocityDeGroote2016(v_M_tilde, -0.318, -8.149, -0.374, 0.886)
1329
+
1330
+ It's also possible to populate the four constants with your own values too.
1331
+
1332
+ >>> from sympy import symbols
1333
+ >>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3')
1334
+ >>> fv_M = FiberForceVelocityDeGroote2016(v_M_tilde, c0, c1, c2, c3)
1335
+ >>> fv_M
1336
+ FiberForceVelocityDeGroote2016(v_M_tilde, c0, c1, c2, c3)
1337
+
1338
+ You don't just have to use symbols as the arguments, it's also possible to
1339
+ use expressions. Let's create a new pair of symbols, ``v_M`` and
1340
+ ``v_M_max``, representing muscle fiber extension velocity and maximum
1341
+ muscle fiber extension velocity respectively. We can then represent
1342
+ ``v_M_tilde`` as an expression, the ratio of these.
1343
+
1344
+ >>> v_M, v_M_max = symbols('v_M v_M_max')
1345
+ >>> v_M_tilde = v_M/v_M_max
1346
+ >>> fv_M = FiberForceVelocityDeGroote2016.with_defaults(v_M_tilde)
1347
+ >>> fv_M
1348
+ FiberForceVelocityDeGroote2016(v_M/v_M_max, -0.318, -8.149, -0.374, 0.886)
1349
+
1350
+ To inspect the actual symbolic expression that this function represents,
1351
+ we can call the :meth:`~.doit` method on an instance. We'll use the keyword
1352
+ argument ``evaluate=False`` as this will keep the expression in its
1353
+ canonical form and won't simplify any constants.
1354
+
1355
+ >>> fv_M.doit(evaluate=False)
1356
+ 0.886 - 0.318*log(-8.149*v_M/v_M_max - 0.374 + sqrt(1 + (-8.149*v_M/v_M_max
1357
+ - 0.374)**2))
1358
+
1359
+ The function can also be differentiated. We'll differentiate with respect
1360
+ to v_M using the ``diff`` method on an instance with the single positional
1361
+ argument ``v_M``.
1362
+
1363
+ >>> fv_M.diff(v_M)
1364
+ 2.591382*(1 + (-8.149*v_M/v_M_max - 0.374)**2)**(-1/2)/v_M_max
1365
+
1366
+ References
1367
+ ==========
1368
+
1369
+ .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
1370
+ of direct collocation optimal control problem formulations for
1371
+ solving the muscle redundancy problem, Annals of biomedical
1372
+ engineering, 44(10), (2016) pp. 2922-2936
1373
+
1374
+ """
1375
+
1376
+ @classmethod
1377
+ def with_defaults(cls, v_M_tilde):
1378
+ r"""Recommended constructor that will use the published constants.
1379
+
1380
+ Explanation
1381
+ ===========
1382
+
1383
+ Returns a new instance of the muscle fiber force-velocity function
1384
+ using the four constant values specified in the original publication.
1385
+
1386
+ These have the values:
1387
+
1388
+ $c_0 = -0.318$
1389
+ $c_1 = -8.149$
1390
+ $c_2 = -0.374$
1391
+ $c_3 = 0.886$
1392
+
1393
+ Parameters
1394
+ ==========
1395
+
1396
+ v_M_tilde : Any (sympifiable)
1397
+ Normalized muscle fiber extension velocity.
1398
+
1399
+ """
1400
+ c0 = Float('-0.318')
1401
+ c1 = Float('-8.149')
1402
+ c2 = Float('-0.374')
1403
+ c3 = Float('0.886')
1404
+ return cls(v_M_tilde, c0, c1, c2, c3)
1405
+
1406
+ @classmethod
1407
+ def eval(cls, v_M_tilde, c0, c1, c2, c3):
1408
+ """Evaluation of basic inputs.
1409
+
1410
+ Parameters
1411
+ ==========
1412
+
1413
+ v_M_tilde : Any (sympifiable)
1414
+ Normalized muscle fiber extension velocity.
1415
+ c0 : Any (sympifiable)
1416
+ The first constant in the characteristic equation. The published
1417
+ value is ``-0.318``.
1418
+ c1 : Any (sympifiable)
1419
+ The second constant in the characteristic equation. The published
1420
+ value is ``-8.149``.
1421
+ c2 : Any (sympifiable)
1422
+ The third constant in the characteristic equation. The published
1423
+ value is ``-0.374``.
1424
+ c3 : Any (sympifiable)
1425
+ The fourth constant in the characteristic equation. The published
1426
+ value is ``0.886``.
1427
+
1428
+ """
1429
+ pass
1430
+
1431
+ def _eval_evalf(self, prec):
1432
+ """Evaluate the expression numerically using ``evalf``."""
1433
+ return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
1434
+
1435
+ def doit(self, deep=True, evaluate=True, **hints):
1436
+ """Evaluate the expression defining the function.
1437
+
1438
+ Parameters
1439
+ ==========
1440
+
1441
+ deep : bool
1442
+ Whether ``doit`` should be recursively called. Default is ``True``.
1443
+ evaluate : bool.
1444
+ Whether the SymPy expression should be evaluated as it is
1445
+ constructed. If ``False``, then no constant folding will be
1446
+ conducted which will leave the expression in a more numerically-
1447
+ stable for values of ``v_M_tilde`` that correspond to a sensible
1448
+ operating range for a musculotendon. Default is ``True``.
1449
+ **kwargs : dict[str, Any]
1450
+ Additional keyword argument pairs to be recursively passed to
1451
+ ``doit``.
1452
+
1453
+ """
1454
+ v_M_tilde, *constants = self.args
1455
+ if deep:
1456
+ hints['evaluate'] = evaluate
1457
+ v_M_tilde = v_M_tilde.doit(deep=deep, **hints)
1458
+ c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants]
1459
+ else:
1460
+ c0, c1, c2, c3 = constants
1461
+
1462
+ if evaluate:
1463
+ return c0*log(c1*v_M_tilde + c2 + sqrt((c1*v_M_tilde + c2)**2 + 1)) + c3
1464
+
1465
+ return c0*log(c1*v_M_tilde + c2 + sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)) + c3
1466
+
1467
+ def fdiff(self, argindex=1):
1468
+ """Derivative of the function with respect to a single argument.
1469
+
1470
+ Parameters
1471
+ ==========
1472
+
1473
+ argindex : int
1474
+ The index of the function's arguments with respect to which the
1475
+ derivative should be taken. Argument indexes start at ``1``.
1476
+ Default is ``1``.
1477
+
1478
+ """
1479
+ v_M_tilde, c0, c1, c2, c3 = self.args
1480
+ if argindex == 1:
1481
+ return c0*c1/sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)
1482
+ elif argindex == 2:
1483
+ return log(
1484
+ c1*v_M_tilde + c2
1485
+ + sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)
1486
+ )
1487
+ elif argindex == 3:
1488
+ return c0*v_M_tilde/sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)
1489
+ elif argindex == 4:
1490
+ return c0/sqrt(UnevaluatedExpr(c1*v_M_tilde + c2)**2 + 1)
1491
+ elif argindex == 5:
1492
+ return Integer(1)
1493
+
1494
+ raise ArgumentIndexError(self, argindex)
1495
+
1496
+ def inverse(self, argindex=1):
1497
+ """Inverse function.
1498
+
1499
+ Parameters
1500
+ ==========
1501
+
1502
+ argindex : int
1503
+ Value to start indexing the arguments at. Default is ``1``.
1504
+
1505
+ """
1506
+ return FiberForceVelocityInverseDeGroote2016
1507
+
1508
+ def _latex(self, printer):
1509
+ """Print a LaTeX representation of the function defining the curve.
1510
+
1511
+ Parameters
1512
+ ==========
1513
+
1514
+ printer : Printer
1515
+ The printer to be used to print the LaTeX string representation.
1516
+
1517
+ """
1518
+ v_M_tilde = self.args[0]
1519
+ _v_M_tilde = printer._print(v_M_tilde)
1520
+ return r'\operatorname{fv}^M \left( %s \right)' % _v_M_tilde
1521
+
1522
+
1523
+ class FiberForceVelocityInverseDeGroote2016(CharacteristicCurveFunction):
1524
+ r"""Inverse muscle fiber force-velocity curve based on De Groote et al.,
1525
+ 2016 [1]_.
1526
+
1527
+ Explanation
1528
+ ===========
1529
+
1530
+ Gives the normalized muscle fiber velocity that produces a specific
1531
+ normalized muscle fiber force.
1532
+
1533
+ The function is defined by the equation:
1534
+
1535
+ ${fv^M}^{-1} = \frac{\sinh{\frac{fv^M - c_3}{c_0}} - c_2}{c_1}$
1536
+
1537
+ with constant values of $c_0 = -0.318$, $c_1 = -8.149$, $c_2 = -0.374$, and
1538
+ $c_3 = 0.886$. This function is the exact analytical inverse of the related
1539
+ muscle fiber force-velocity curve ``FiberForceVelocityDeGroote2016``.
1540
+
1541
+ While it is possible to change the constant values, these were carefully
1542
+ selected in the original publication to give the characteristic curve
1543
+ specific and required properties. For example, the function produces a
1544
+ normalized muscle fiber force of 1 when the muscle fibers are contracting
1545
+ isometrically (they have an extension rate of 0).
1546
+
1547
+ Examples
1548
+ ========
1549
+
1550
+ The preferred way to instantiate :class:`FiberForceVelocityInverseDeGroote2016`
1551
+ is using the :meth:`~.with_defaults` constructor because this will automatically
1552
+ populate the constants within the characteristic curve equation with the
1553
+ floating point values from the original publication. This constructor takes
1554
+ a single argument corresponding to normalized muscle fiber force-velocity
1555
+ component of the muscle fiber force. We'll create a :class:`~.Symbol` called
1556
+ ``fv_M`` to represent this.
1557
+
1558
+ >>> from sympy import Symbol
1559
+ >>> from sympy.physics.biomechanics import FiberForceVelocityInverseDeGroote2016
1560
+ >>> fv_M = Symbol('fv_M')
1561
+ >>> v_M_tilde = FiberForceVelocityInverseDeGroote2016.with_defaults(fv_M)
1562
+ >>> v_M_tilde
1563
+ FiberForceVelocityInverseDeGroote2016(fv_M, -0.318, -8.149, -0.374, 0.886)
1564
+
1565
+ It's also possible to populate the four constants with your own values too.
1566
+
1567
+ >>> from sympy import symbols
1568
+ >>> c0, c1, c2, c3 = symbols('c0 c1 c2 c3')
1569
+ >>> v_M_tilde = FiberForceVelocityInverseDeGroote2016(fv_M, c0, c1, c2, c3)
1570
+ >>> v_M_tilde
1571
+ FiberForceVelocityInverseDeGroote2016(fv_M, c0, c1, c2, c3)
1572
+
1573
+ To inspect the actual symbolic expression that this function represents,
1574
+ we can call the :meth:`~.doit` method on an instance. We'll use the keyword
1575
+ argument ``evaluate=False`` as this will keep the expression in its
1576
+ canonical form and won't simplify any constants.
1577
+
1578
+ >>> v_M_tilde.doit(evaluate=False)
1579
+ (-c2 + sinh((-c3 + fv_M)/c0))/c1
1580
+
1581
+ The function can also be differentiated. We'll differentiate with respect
1582
+ to fv_M using the ``diff`` method on an instance with the single positional
1583
+ argument ``fv_M``.
1584
+
1585
+ >>> v_M_tilde.diff(fv_M)
1586
+ cosh((-c3 + fv_M)/c0)/(c0*c1)
1587
+
1588
+ References
1589
+ ==========
1590
+
1591
+ .. [1] De Groote, F., Kinney, A. L., Rao, A. V., & Fregly, B. J., Evaluation
1592
+ of direct collocation optimal control problem formulations for
1593
+ solving the muscle redundancy problem, Annals of biomedical
1594
+ engineering, 44(10), (2016) pp. 2922-2936
1595
+
1596
+ """
1597
+
1598
+ @classmethod
1599
+ def with_defaults(cls, fv_M):
1600
+ r"""Recommended constructor that will use the published constants.
1601
+
1602
+ Explanation
1603
+ ===========
1604
+
1605
+ Returns a new instance of the inverse muscle fiber force-velocity
1606
+ function using the four constant values specified in the original
1607
+ publication.
1608
+
1609
+ These have the values:
1610
+
1611
+ $c_0 = -0.318$
1612
+ $c_1 = -8.149$
1613
+ $c_2 = -0.374$
1614
+ $c_3 = 0.886$
1615
+
1616
+ Parameters
1617
+ ==========
1618
+
1619
+ fv_M : Any (sympifiable)
1620
+ Normalized muscle fiber extension velocity.
1621
+
1622
+ """
1623
+ c0 = Float('-0.318')
1624
+ c1 = Float('-8.149')
1625
+ c2 = Float('-0.374')
1626
+ c3 = Float('0.886')
1627
+ return cls(fv_M, c0, c1, c2, c3)
1628
+
1629
+ @classmethod
1630
+ def eval(cls, fv_M, c0, c1, c2, c3):
1631
+ """Evaluation of basic inputs.
1632
+
1633
+ Parameters
1634
+ ==========
1635
+
1636
+ fv_M : Any (sympifiable)
1637
+ Normalized muscle fiber force as a function of muscle fiber
1638
+ extension velocity.
1639
+ c0 : Any (sympifiable)
1640
+ The first constant in the characteristic equation. The published
1641
+ value is ``-0.318``.
1642
+ c1 : Any (sympifiable)
1643
+ The second constant in the characteristic equation. The published
1644
+ value is ``-8.149``.
1645
+ c2 : Any (sympifiable)
1646
+ The third constant in the characteristic equation. The published
1647
+ value is ``-0.374``.
1648
+ c3 : Any (sympifiable)
1649
+ The fourth constant in the characteristic equation. The published
1650
+ value is ``0.886``.
1651
+
1652
+ """
1653
+ pass
1654
+
1655
+ def _eval_evalf(self, prec):
1656
+ """Evaluate the expression numerically using ``evalf``."""
1657
+ return self.doit(deep=False, evaluate=False)._eval_evalf(prec)
1658
+
1659
+ def doit(self, deep=True, evaluate=True, **hints):
1660
+ """Evaluate the expression defining the function.
1661
+
1662
+ Parameters
1663
+ ==========
1664
+
1665
+ deep : bool
1666
+ Whether ``doit`` should be recursively called. Default is ``True``.
1667
+ evaluate : bool.
1668
+ Whether the SymPy expression should be evaluated as it is
1669
+ constructed. If ``False``, then no constant folding will be
1670
+ conducted which will leave the expression in a more numerically-
1671
+ stable for values of ``fv_M`` that correspond to a sensible
1672
+ operating range for a musculotendon. Default is ``True``.
1673
+ **kwargs : dict[str, Any]
1674
+ Additional keyword argument pairs to be recursively passed to
1675
+ ``doit``.
1676
+
1677
+ """
1678
+ fv_M, *constants = self.args
1679
+ if deep:
1680
+ hints['evaluate'] = evaluate
1681
+ fv_M = fv_M.doit(deep=deep, **hints)
1682
+ c0, c1, c2, c3 = [c.doit(deep=deep, **hints) for c in constants]
1683
+ else:
1684
+ c0, c1, c2, c3 = constants
1685
+
1686
+ if evaluate:
1687
+ return (sinh((fv_M - c3)/c0) - c2)/c1
1688
+
1689
+ return (sinh(UnevaluatedExpr(fv_M - c3)/c0) - c2)/c1
1690
+
1691
+ def fdiff(self, argindex=1):
1692
+ """Derivative of the function with respect to a single argument.
1693
+
1694
+ Parameters
1695
+ ==========
1696
+
1697
+ argindex : int
1698
+ The index of the function's arguments with respect to which the
1699
+ derivative should be taken. Argument indexes start at ``1``.
1700
+ Default is ``1``.
1701
+
1702
+ """
1703
+ fv_M, c0, c1, c2, c3 = self.args
1704
+ if argindex == 1:
1705
+ return cosh((fv_M - c3)/c0)/(c0*c1)
1706
+ elif argindex == 2:
1707
+ return (c3 - fv_M)*cosh((fv_M - c3)/c0)/(c0**2*c1)
1708
+ elif argindex == 3:
1709
+ return (c2 - sinh((fv_M - c3)/c0))/c1**2
1710
+ elif argindex == 4:
1711
+ return -1/c1
1712
+ elif argindex == 5:
1713
+ return -cosh((fv_M - c3)/c0)/(c0*c1)
1714
+
1715
+ raise ArgumentIndexError(self, argindex)
1716
+
1717
+ def inverse(self, argindex=1):
1718
+ """Inverse function.
1719
+
1720
+ Parameters
1721
+ ==========
1722
+
1723
+ argindex : int
1724
+ Value to start indexing the arguments at. Default is ``1``.
1725
+
1726
+ """
1727
+ return FiberForceVelocityDeGroote2016
1728
+
1729
+ def _latex(self, printer):
1730
+ """Print a LaTeX representation of the function defining the curve.
1731
+
1732
+ Parameters
1733
+ ==========
1734
+
1735
+ printer : Printer
1736
+ The printer to be used to print the LaTeX string representation.
1737
+
1738
+ """
1739
+ fv_M = self.args[0]
1740
+ _fv_M = printer._print(fv_M)
1741
+ return r'\left( \operatorname{fv}^M \right)^{-1} \left( %s \right)' % _fv_M
1742
+
1743
+
1744
+ @dataclass(frozen=True)
1745
+ class CharacteristicCurveCollection:
1746
+ """Simple data container to group together related characteristic curves."""
1747
+ tendon_force_length: CharacteristicCurveFunction
1748
+ tendon_force_length_inverse: CharacteristicCurveFunction
1749
+ fiber_force_length_passive: CharacteristicCurveFunction
1750
+ fiber_force_length_passive_inverse: CharacteristicCurveFunction
1751
+ fiber_force_length_active: CharacteristicCurveFunction
1752
+ fiber_force_velocity: CharacteristicCurveFunction
1753
+ fiber_force_velocity_inverse: CharacteristicCurveFunction
1754
+
1755
+ def __iter__(self):
1756
+ """Iterator support for ``CharacteristicCurveCollection``."""
1757
+ yield self.tendon_force_length
1758
+ yield self.tendon_force_length_inverse
1759
+ yield self.fiber_force_length_passive
1760
+ yield self.fiber_force_length_passive_inverse
1761
+ yield self.fiber_force_length_active
1762
+ yield self.fiber_force_velocity
1763
+ yield self.fiber_force_velocity_inverse
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (233 Bytes). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/__pycache__/test_mixin.cpython-311.pyc ADDED
Binary file (4.28 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/biomechanics/tests/test_activation.py ADDED
@@ -0,0 +1,348 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Tests for the ``sympy.physics.biomechanics.activation.py`` module."""
2
+
3
+ import pytest
4
+
5
+ from sympy import Symbol
6
+ from sympy.core.numbers import Float, Integer, Rational
7
+ from sympy.functions.elementary.hyperbolic import tanh
8
+ from sympy.matrices import Matrix
9
+ from sympy.matrices.dense import zeros
10
+ from sympy.physics.mechanics import dynamicsymbols
11
+ from sympy.physics.biomechanics import (
12
+ ActivationBase,
13
+ FirstOrderActivationDeGroote2016,
14
+ ZerothOrderActivation,
15
+ )
16
+ from sympy.physics.biomechanics._mixin import _NamedMixin
17
+ from sympy.simplify.simplify import simplify
18
+
19
+
20
+ class TestZerothOrderActivation:
21
+
22
+ @staticmethod
23
+ def test_class():
24
+ assert issubclass(ZerothOrderActivation, ActivationBase)
25
+ assert issubclass(ZerothOrderActivation, _NamedMixin)
26
+ assert ZerothOrderActivation.__name__ == 'ZerothOrderActivation'
27
+
28
+ @pytest.fixture(autouse=True)
29
+ def _zeroth_order_activation_fixture(self):
30
+ self.name = 'name'
31
+ self.e = dynamicsymbols('e_name')
32
+ self.instance = ZerothOrderActivation(self.name)
33
+
34
+ def test_instance(self):
35
+ instance = ZerothOrderActivation(self.name)
36
+ assert isinstance(instance, ZerothOrderActivation)
37
+
38
+ def test_with_defaults(self):
39
+ instance = ZerothOrderActivation.with_defaults(self.name)
40
+ assert isinstance(instance, ZerothOrderActivation)
41
+ assert instance == ZerothOrderActivation(self.name)
42
+
43
+ def test_name(self):
44
+ assert hasattr(self.instance, 'name')
45
+ assert self.instance.name == self.name
46
+
47
+ def test_order(self):
48
+ assert hasattr(self.instance, 'order')
49
+ assert self.instance.order == 0
50
+
51
+ def test_excitation_attribute(self):
52
+ assert hasattr(self.instance, 'e')
53
+ assert hasattr(self.instance, 'excitation')
54
+ e_expected = dynamicsymbols('e_name')
55
+ assert self.instance.e == e_expected
56
+ assert self.instance.excitation == e_expected
57
+ assert self.instance.e is self.instance.excitation
58
+
59
+ def test_activation_attribute(self):
60
+ assert hasattr(self.instance, 'a')
61
+ assert hasattr(self.instance, 'activation')
62
+ a_expected = dynamicsymbols('e_name')
63
+ assert self.instance.a == a_expected
64
+ assert self.instance.activation == a_expected
65
+ assert self.instance.a is self.instance.activation is self.instance.e
66
+
67
+ def test_state_vars_attribute(self):
68
+ assert hasattr(self.instance, 'x')
69
+ assert hasattr(self.instance, 'state_vars')
70
+ assert self.instance.x == self.instance.state_vars
71
+ x_expected = zeros(0, 1)
72
+ assert self.instance.x == x_expected
73
+ assert self.instance.state_vars == x_expected
74
+ assert isinstance(self.instance.x, Matrix)
75
+ assert isinstance(self.instance.state_vars, Matrix)
76
+ assert self.instance.x.shape == (0, 1)
77
+ assert self.instance.state_vars.shape == (0, 1)
78
+
79
+ def test_input_vars_attribute(self):
80
+ assert hasattr(self.instance, 'r')
81
+ assert hasattr(self.instance, 'input_vars')
82
+ assert self.instance.r == self.instance.input_vars
83
+ r_expected = Matrix([self.e])
84
+ assert self.instance.r == r_expected
85
+ assert self.instance.input_vars == r_expected
86
+ assert isinstance(self.instance.r, Matrix)
87
+ assert isinstance(self.instance.input_vars, Matrix)
88
+ assert self.instance.r.shape == (1, 1)
89
+ assert self.instance.input_vars.shape == (1, 1)
90
+
91
+ def test_constants_attribute(self):
92
+ assert hasattr(self.instance, 'p')
93
+ assert hasattr(self.instance, 'constants')
94
+ assert self.instance.p == self.instance.constants
95
+ p_expected = zeros(0, 1)
96
+ assert self.instance.p == p_expected
97
+ assert self.instance.constants == p_expected
98
+ assert isinstance(self.instance.p, Matrix)
99
+ assert isinstance(self.instance.constants, Matrix)
100
+ assert self.instance.p.shape == (0, 1)
101
+ assert self.instance.constants.shape == (0, 1)
102
+
103
+ def test_M_attribute(self):
104
+ assert hasattr(self.instance, 'M')
105
+ M_expected = Matrix([])
106
+ assert self.instance.M == M_expected
107
+ assert isinstance(self.instance.M, Matrix)
108
+ assert self.instance.M.shape == (0, 0)
109
+
110
+ def test_F(self):
111
+ assert hasattr(self.instance, 'F')
112
+ F_expected = zeros(0, 1)
113
+ assert self.instance.F == F_expected
114
+ assert isinstance(self.instance.F, Matrix)
115
+ assert self.instance.F.shape == (0, 1)
116
+
117
+ def test_rhs(self):
118
+ assert hasattr(self.instance, 'rhs')
119
+ rhs_expected = zeros(0, 1)
120
+ rhs = self.instance.rhs()
121
+ assert rhs == rhs_expected
122
+ assert isinstance(rhs, Matrix)
123
+ assert rhs.shape == (0, 1)
124
+
125
+ def test_repr(self):
126
+ expected = 'ZerothOrderActivation(\'name\')'
127
+ assert repr(self.instance) == expected
128
+
129
+
130
+ class TestFirstOrderActivationDeGroote2016:
131
+
132
+ @staticmethod
133
+ def test_class():
134
+ assert issubclass(FirstOrderActivationDeGroote2016, ActivationBase)
135
+ assert issubclass(FirstOrderActivationDeGroote2016, _NamedMixin)
136
+ assert FirstOrderActivationDeGroote2016.__name__ == 'FirstOrderActivationDeGroote2016'
137
+
138
+ @pytest.fixture(autouse=True)
139
+ def _first_order_activation_de_groote_2016_fixture(self):
140
+ self.name = 'name'
141
+ self.e = dynamicsymbols('e_name')
142
+ self.a = dynamicsymbols('a_name')
143
+ self.tau_a = Symbol('tau_a')
144
+ self.tau_d = Symbol('tau_d')
145
+ self.b = Symbol('b')
146
+ self.instance = FirstOrderActivationDeGroote2016(
147
+ self.name,
148
+ self.tau_a,
149
+ self.tau_d,
150
+ self.b,
151
+ )
152
+
153
+ def test_instance(self):
154
+ instance = FirstOrderActivationDeGroote2016(self.name)
155
+ assert isinstance(instance, FirstOrderActivationDeGroote2016)
156
+
157
+ def test_with_defaults(self):
158
+ instance = FirstOrderActivationDeGroote2016.with_defaults(self.name)
159
+ assert isinstance(instance, FirstOrderActivationDeGroote2016)
160
+ assert instance.tau_a == Float('0.015')
161
+ assert instance.activation_time_constant == Float('0.015')
162
+ assert instance.tau_d == Float('0.060')
163
+ assert instance.deactivation_time_constant == Float('0.060')
164
+ assert instance.b == Float('10.0')
165
+ assert instance.smoothing_rate == Float('10.0')
166
+
167
+ def test_name(self):
168
+ assert hasattr(self.instance, 'name')
169
+ assert self.instance.name == self.name
170
+
171
+ def test_order(self):
172
+ assert hasattr(self.instance, 'order')
173
+ assert self.instance.order == 1
174
+
175
+ def test_excitation(self):
176
+ assert hasattr(self.instance, 'e')
177
+ assert hasattr(self.instance, 'excitation')
178
+ e_expected = dynamicsymbols('e_name')
179
+ assert self.instance.e == e_expected
180
+ assert self.instance.excitation == e_expected
181
+ assert self.instance.e is self.instance.excitation
182
+
183
+ def test_excitation_is_immutable(self):
184
+ with pytest.raises(AttributeError):
185
+ self.instance.e = None
186
+ with pytest.raises(AttributeError):
187
+ self.instance.excitation = None
188
+
189
+ def test_activation(self):
190
+ assert hasattr(self.instance, 'a')
191
+ assert hasattr(self.instance, 'activation')
192
+ a_expected = dynamicsymbols('a_name')
193
+ assert self.instance.a == a_expected
194
+ assert self.instance.activation == a_expected
195
+
196
+ def test_activation_is_immutable(self):
197
+ with pytest.raises(AttributeError):
198
+ self.instance.a = None
199
+ with pytest.raises(AttributeError):
200
+ self.instance.activation = None
201
+
202
+ @pytest.mark.parametrize(
203
+ 'tau_a, expected',
204
+ [
205
+ (None, Symbol('tau_a_name')),
206
+ (Symbol('tau_a'), Symbol('tau_a')),
207
+ (Float('0.015'), Float('0.015')),
208
+ ]
209
+ )
210
+ def test_activation_time_constant(self, tau_a, expected):
211
+ instance = FirstOrderActivationDeGroote2016(
212
+ 'name', activation_time_constant=tau_a,
213
+ )
214
+ assert instance.tau_a == expected
215
+ assert instance.activation_time_constant == expected
216
+ assert instance.tau_a is instance.activation_time_constant
217
+
218
+ def test_activation_time_constant_is_immutable(self):
219
+ with pytest.raises(AttributeError):
220
+ self.instance.tau_a = None
221
+ with pytest.raises(AttributeError):
222
+ self.instance.activation_time_constant = None
223
+
224
+ @pytest.mark.parametrize(
225
+ 'tau_d, expected',
226
+ [
227
+ (None, Symbol('tau_d_name')),
228
+ (Symbol('tau_d'), Symbol('tau_d')),
229
+ (Float('0.060'), Float('0.060')),
230
+ ]
231
+ )
232
+ def test_deactivation_time_constant(self, tau_d, expected):
233
+ instance = FirstOrderActivationDeGroote2016(
234
+ 'name', deactivation_time_constant=tau_d,
235
+ )
236
+ assert instance.tau_d == expected
237
+ assert instance.deactivation_time_constant == expected
238
+ assert instance.tau_d is instance.deactivation_time_constant
239
+
240
+ def test_deactivation_time_constant_is_immutable(self):
241
+ with pytest.raises(AttributeError):
242
+ self.instance.tau_d = None
243
+ with pytest.raises(AttributeError):
244
+ self.instance.deactivation_time_constant = None
245
+
246
+ @pytest.mark.parametrize(
247
+ 'b, expected',
248
+ [
249
+ (None, Symbol('b_name')),
250
+ (Symbol('b'), Symbol('b')),
251
+ (Integer('10'), Integer('10')),
252
+ ]
253
+ )
254
+ def test_smoothing_rate(self, b, expected):
255
+ instance = FirstOrderActivationDeGroote2016(
256
+ 'name', smoothing_rate=b,
257
+ )
258
+ assert instance.b == expected
259
+ assert instance.smoothing_rate == expected
260
+ assert instance.b is instance.smoothing_rate
261
+
262
+ def test_smoothing_rate_is_immutable(self):
263
+ with pytest.raises(AttributeError):
264
+ self.instance.b = None
265
+ with pytest.raises(AttributeError):
266
+ self.instance.smoothing_rate = None
267
+
268
+ def test_state_vars(self):
269
+ assert hasattr(self.instance, 'x')
270
+ assert hasattr(self.instance, 'state_vars')
271
+ assert self.instance.x == self.instance.state_vars
272
+ x_expected = Matrix([self.a])
273
+ assert self.instance.x == x_expected
274
+ assert self.instance.state_vars == x_expected
275
+ assert isinstance(self.instance.x, Matrix)
276
+ assert isinstance(self.instance.state_vars, Matrix)
277
+ assert self.instance.x.shape == (1, 1)
278
+ assert self.instance.state_vars.shape == (1, 1)
279
+
280
+ def test_input_vars(self):
281
+ assert hasattr(self.instance, 'r')
282
+ assert hasattr(self.instance, 'input_vars')
283
+ assert self.instance.r == self.instance.input_vars
284
+ r_expected = Matrix([self.e])
285
+ assert self.instance.r == r_expected
286
+ assert self.instance.input_vars == r_expected
287
+ assert isinstance(self.instance.r, Matrix)
288
+ assert isinstance(self.instance.input_vars, Matrix)
289
+ assert self.instance.r.shape == (1, 1)
290
+ assert self.instance.input_vars.shape == (1, 1)
291
+
292
+ def test_constants(self):
293
+ assert hasattr(self.instance, 'p')
294
+ assert hasattr(self.instance, 'constants')
295
+ assert self.instance.p == self.instance.constants
296
+ p_expected = Matrix([self.tau_a, self.tau_d, self.b])
297
+ assert self.instance.p == p_expected
298
+ assert self.instance.constants == p_expected
299
+ assert isinstance(self.instance.p, Matrix)
300
+ assert isinstance(self.instance.constants, Matrix)
301
+ assert self.instance.p.shape == (3, 1)
302
+ assert self.instance.constants.shape == (3, 1)
303
+
304
+ def test_M(self):
305
+ assert hasattr(self.instance, 'M')
306
+ M_expected = Matrix([1])
307
+ assert self.instance.M == M_expected
308
+ assert isinstance(self.instance.M, Matrix)
309
+ assert self.instance.M.shape == (1, 1)
310
+
311
+ def test_F(self):
312
+ assert hasattr(self.instance, 'F')
313
+ da_expr = (
314
+ ((1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a)))
315
+ *(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a)))
316
+ + ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d)
317
+ *(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a))))
318
+ *(self.e - self.a)
319
+ )
320
+ F_expected = Matrix([da_expr])
321
+ assert self.instance.F == F_expected
322
+ assert isinstance(self.instance.F, Matrix)
323
+ assert self.instance.F.shape == (1, 1)
324
+
325
+ def test_rhs(self):
326
+ assert hasattr(self.instance, 'rhs')
327
+ da_expr = (
328
+ ((1/(self.tau_a*(Rational(1, 2) + Rational(3, 2)*self.a)))
329
+ *(Rational(1, 2) + Rational(1, 2)*tanh(self.b*(self.e - self.a)))
330
+ + ((Rational(1, 2) + Rational(3, 2)*self.a)/self.tau_d)
331
+ *(Rational(1, 2) - Rational(1, 2)*tanh(self.b*(self.e - self.a))))
332
+ *(self.e - self.a)
333
+ )
334
+ rhs_expected = Matrix([da_expr])
335
+ rhs = self.instance.rhs()
336
+ assert rhs == rhs_expected
337
+ assert isinstance(rhs, Matrix)
338
+ assert rhs.shape == (1, 1)
339
+ assert simplify(self.instance.M.solve(self.instance.F) - rhs) == zeros(1)
340
+
341
+ def test_repr(self):
342
+ expected = (
343
+ 'FirstOrderActivationDeGroote2016(\'name\', '
344
+ 'activation_time_constant=tau_a, '
345
+ 'deactivation_time_constant=tau_d, '
346
+ 'smoothing_rate=b)'
347
+ )
348
+ assert repr(self.instance) == expected
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/control/__init__.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .lti import (TransferFunction, Series, MIMOSeries, Parallel, MIMOParallel,
2
+ Feedback, MIMOFeedback, TransferFunctionMatrix, StateSpace, gbt, bilinear, forward_diff,
3
+ backward_diff, phase_margin, gain_margin)
4
+ from .control_plots import (pole_zero_numerical_data, pole_zero_plot, step_response_numerical_data,
5
+ step_response_plot, impulse_response_numerical_data, impulse_response_plot, ramp_response_numerical_data,
6
+ ramp_response_plot, bode_magnitude_numerical_data, bode_phase_numerical_data, bode_magnitude_plot,
7
+ bode_phase_plot, bode_plot)
8
+
9
+ __all__ = ['TransferFunction', 'Series', 'MIMOSeries', 'Parallel',
10
+ 'MIMOParallel', 'Feedback', 'MIMOFeedback', 'TransferFunctionMatrix', 'StateSpace',
11
+ 'gbt', 'bilinear', 'forward_diff', 'backward_diff', 'phase_margin', 'gain_margin',
12
+ 'pole_zero_numerical_data', 'pole_zero_plot', 'step_response_numerical_data',
13
+ 'step_response_plot', 'impulse_response_numerical_data', 'impulse_response_plot',
14
+ 'ramp_response_numerical_data', 'ramp_response_plot',
15
+ 'bode_magnitude_numerical_data', 'bode_phase_numerical_data',
16
+ 'bode_magnitude_plot', 'bode_phase_plot', 'bode_plot']
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/control/control_plots.py ADDED
@@ -0,0 +1,978 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.numbers import I, pi
2
+ from sympy.functions.elementary.exponential import (exp, log)
3
+ from sympy.polys.partfrac import apart
4
+ from sympy.core.symbol import Dummy
5
+ from sympy.external import import_module
6
+ from sympy.functions import arg, Abs
7
+ from sympy.integrals.laplace import _fast_inverse_laplace
8
+ from sympy.physics.control.lti import SISOLinearTimeInvariant
9
+ from sympy.plotting.series import LineOver1DRangeSeries
10
+ from sympy.polys.polytools import Poly
11
+ from sympy.printing.latex import latex
12
+
13
+ __all__ = ['pole_zero_numerical_data', 'pole_zero_plot',
14
+ 'step_response_numerical_data', 'step_response_plot',
15
+ 'impulse_response_numerical_data', 'impulse_response_plot',
16
+ 'ramp_response_numerical_data', 'ramp_response_plot',
17
+ 'bode_magnitude_numerical_data', 'bode_phase_numerical_data',
18
+ 'bode_magnitude_plot', 'bode_phase_plot', 'bode_plot']
19
+
20
+ matplotlib = import_module(
21
+ 'matplotlib', import_kwargs={'fromlist': ['pyplot']},
22
+ catch=(RuntimeError,))
23
+
24
+ numpy = import_module('numpy')
25
+
26
+ if matplotlib:
27
+ plt = matplotlib.pyplot
28
+
29
+ if numpy:
30
+ np = numpy # Matplotlib already has numpy as a compulsory dependency. No need to install it separately.
31
+
32
+
33
+ def _check_system(system):
34
+ """Function to check whether the dynamical system passed for plots is
35
+ compatible or not."""
36
+ if not isinstance(system, SISOLinearTimeInvariant):
37
+ raise NotImplementedError("Only SISO LTI systems are currently supported.")
38
+ sys = system.to_expr()
39
+ len_free_symbols = len(sys.free_symbols)
40
+ if len_free_symbols > 1:
41
+ raise ValueError("Extra degree of freedom found. Make sure"
42
+ " that there are no free symbols in the dynamical system other"
43
+ " than the variable of Laplace transform.")
44
+ if sys.has(exp):
45
+ # Should test that exp is not part of a constant, in which case
46
+ # no exception is required, compare exp(s) with s*exp(1)
47
+ raise NotImplementedError("Time delay terms are not supported.")
48
+
49
+
50
+ def pole_zero_numerical_data(system):
51
+ """
52
+ Returns the numerical data of poles and zeros of the system.
53
+ It is internally used by ``pole_zero_plot`` to get the data
54
+ for plotting poles and zeros. Users can use this data to further
55
+ analyse the dynamics of the system or plot using a different
56
+ backend/plotting-module.
57
+
58
+ Parameters
59
+ ==========
60
+
61
+ system : SISOLinearTimeInvariant
62
+ The system for which the pole-zero data is to be computed.
63
+
64
+ Returns
65
+ =======
66
+
67
+ tuple : (zeros, poles)
68
+ zeros = Zeros of the system. NumPy array of complex numbers.
69
+ poles = Poles of the system. NumPy array of complex numbers.
70
+
71
+ Raises
72
+ ======
73
+
74
+ NotImplementedError
75
+ When a SISO LTI system is not passed.
76
+
77
+ When time delay terms are present in the system.
78
+
79
+ ValueError
80
+ When more than one free symbol is present in the system.
81
+ The only variable in the transfer function should be
82
+ the variable of the Laplace transform.
83
+
84
+ Examples
85
+ ========
86
+
87
+ >>> from sympy.abc import s
88
+ >>> from sympy.physics.control.lti import TransferFunction
89
+ >>> from sympy.physics.control.control_plots import pole_zero_numerical_data
90
+ >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s)
91
+ >>> pole_zero_numerical_data(tf1) # doctest: +SKIP
92
+ ([-0.+1.j 0.-1.j], [-2. +0.j -0.5+0.8660254j -0.5-0.8660254j -1. +0.j ])
93
+
94
+ See Also
95
+ ========
96
+
97
+ pole_zero_plot
98
+
99
+ """
100
+ _check_system(system)
101
+ system = system.doit() # Get the equivalent TransferFunction object.
102
+
103
+ num_poly = Poly(system.num, system.var).all_coeffs()
104
+ den_poly = Poly(system.den, system.var).all_coeffs()
105
+
106
+ num_poly = np.array(num_poly, dtype=np.complex128)
107
+ den_poly = np.array(den_poly, dtype=np.complex128)
108
+
109
+ zeros = np.roots(num_poly)
110
+ poles = np.roots(den_poly)
111
+
112
+ return zeros, poles
113
+
114
+
115
+ def pole_zero_plot(system, pole_color='blue', pole_markersize=10,
116
+ zero_color='orange', zero_markersize=7, grid=True, show_axes=True,
117
+ show=True, **kwargs):
118
+ r"""
119
+ Returns the Pole-Zero plot (also known as PZ Plot or PZ Map) of a system.
120
+
121
+ A Pole-Zero plot is a graphical representation of a system's poles and
122
+ zeros. It is plotted on a complex plane, with circular markers representing
123
+ the system's zeros and 'x' shaped markers representing the system's poles.
124
+
125
+ Parameters
126
+ ==========
127
+
128
+ system : SISOLinearTimeInvariant type systems
129
+ The system for which the pole-zero plot is to be computed.
130
+ pole_color : str, tuple, optional
131
+ The color of the pole points on the plot. Default color
132
+ is blue. The color can be provided as a matplotlib color string,
133
+ or a 3-tuple of floats each in the 0-1 range.
134
+ pole_markersize : Number, optional
135
+ The size of the markers used to mark the poles in the plot.
136
+ Default pole markersize is 10.
137
+ zero_color : str, tuple, optional
138
+ The color of the zero points on the plot. Default color
139
+ is orange. The color can be provided as a matplotlib color string,
140
+ or a 3-tuple of floats each in the 0-1 range.
141
+ zero_markersize : Number, optional
142
+ The size of the markers used to mark the zeros in the plot.
143
+ Default zero markersize is 7.
144
+ grid : boolean, optional
145
+ If ``True``, the plot will have a grid. Defaults to True.
146
+ show_axes : boolean, optional
147
+ If ``True``, the coordinate axes will be shown. Defaults to False.
148
+ show : boolean, optional
149
+ If ``True``, the plot will be displayed otherwise
150
+ the equivalent matplotlib ``plot`` object will be returned.
151
+ Defaults to True.
152
+
153
+ Examples
154
+ ========
155
+
156
+ .. plot::
157
+ :context: close-figs
158
+ :format: doctest
159
+ :include-source: True
160
+
161
+ >>> from sympy.abc import s
162
+ >>> from sympy.physics.control.lti import TransferFunction
163
+ >>> from sympy.physics.control.control_plots import pole_zero_plot
164
+ >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s)
165
+ >>> pole_zero_plot(tf1) # doctest: +SKIP
166
+
167
+ See Also
168
+ ========
169
+
170
+ pole_zero_numerical_data
171
+
172
+ References
173
+ ==========
174
+
175
+ .. [1] https://en.wikipedia.org/wiki/Pole%E2%80%93zero_plot
176
+
177
+ """
178
+ zeros, poles = pole_zero_numerical_data(system)
179
+
180
+ zero_real = np.real(zeros)
181
+ zero_imag = np.imag(zeros)
182
+
183
+ pole_real = np.real(poles)
184
+ pole_imag = np.imag(poles)
185
+
186
+ plt.plot(pole_real, pole_imag, 'x', mfc='none',
187
+ markersize=pole_markersize, color=pole_color)
188
+ plt.plot(zero_real, zero_imag, 'o', markersize=zero_markersize,
189
+ color=zero_color)
190
+ plt.xlabel('Real Axis')
191
+ plt.ylabel('Imaginary Axis')
192
+ plt.title(f'Poles and Zeros of ${latex(system)}$', pad=20)
193
+
194
+ if grid:
195
+ plt.grid()
196
+ if show_axes:
197
+ plt.axhline(0, color='black')
198
+ plt.axvline(0, color='black')
199
+ if show:
200
+ plt.show()
201
+ return
202
+
203
+ return plt
204
+
205
+
206
+ def step_response_numerical_data(system, prec=8, lower_limit=0,
207
+ upper_limit=10, **kwargs):
208
+ """
209
+ Returns the numerical values of the points in the step response plot
210
+ of a SISO continuous-time system. By default, adaptive sampling
211
+ is used. If the user wants to instead get an uniformly
212
+ sampled response, then ``adaptive`` kwarg should be passed ``False``
213
+ and ``n`` must be passed as additional kwargs.
214
+ Refer to the parameters of class :class:`sympy.plotting.series.LineOver1DRangeSeries`
215
+ for more details.
216
+
217
+ Parameters
218
+ ==========
219
+
220
+ system : SISOLinearTimeInvariant
221
+ The system for which the unit step response data is to be computed.
222
+ prec : int, optional
223
+ The decimal point precision for the point coordinate values.
224
+ Defaults to 8.
225
+ lower_limit : Number, optional
226
+ The lower limit of the plot range. Defaults to 0.
227
+ upper_limit : Number, optional
228
+ The upper limit of the plot range. Defaults to 10.
229
+ kwargs :
230
+ Additional keyword arguments are passed to the underlying
231
+ :class:`sympy.plotting.series.LineOver1DRangeSeries` class.
232
+
233
+ Returns
234
+ =======
235
+
236
+ tuple : (x, y)
237
+ x = Time-axis values of the points in the step response. NumPy array.
238
+ y = Amplitude-axis values of the points in the step response. NumPy array.
239
+
240
+ Raises
241
+ ======
242
+
243
+ NotImplementedError
244
+ When a SISO LTI system is not passed.
245
+
246
+ When time delay terms are present in the system.
247
+
248
+ ValueError
249
+ When more than one free symbol is present in the system.
250
+ The only variable in the transfer function should be
251
+ the variable of the Laplace transform.
252
+
253
+ When ``lower_limit`` parameter is less than 0.
254
+
255
+ Examples
256
+ ========
257
+
258
+ >>> from sympy.abc import s
259
+ >>> from sympy.physics.control.lti import TransferFunction
260
+ >>> from sympy.physics.control.control_plots import step_response_numerical_data
261
+ >>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s)
262
+ >>> step_response_numerical_data(tf1) # doctest: +SKIP
263
+ ([0.0, 0.025413462339411542, 0.0484508722725343, ... , 9.670250533855183, 9.844291913708725, 10.0],
264
+ [0.0, 0.023844582399907256, 0.042894276802320226, ..., 6.828770759094287e-12, 6.456457160755703e-12])
265
+
266
+ See Also
267
+ ========
268
+
269
+ step_response_plot
270
+
271
+ """
272
+ if lower_limit < 0:
273
+ raise ValueError("Lower limit of time must be greater "
274
+ "than or equal to zero.")
275
+ _check_system(system)
276
+ _x = Dummy("x")
277
+ expr = system.to_expr()/(system.var)
278
+ expr = apart(expr, system.var, full=True)
279
+ _y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec)
280
+ return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit),
281
+ **kwargs).get_points()
282
+
283
+
284
+ def step_response_plot(system, color='b', prec=8, lower_limit=0,
285
+ upper_limit=10, show_axes=False, grid=True, show=True, **kwargs):
286
+ r"""
287
+ Returns the unit step response of a continuous-time system. It is
288
+ the response of the system when the input signal is a step function.
289
+
290
+ Parameters
291
+ ==========
292
+
293
+ system : SISOLinearTimeInvariant type
294
+ The LTI SISO system for which the Step Response is to be computed.
295
+ color : str, tuple, optional
296
+ The color of the line. Default is Blue.
297
+ show : boolean, optional
298
+ If ``True``, the plot will be displayed otherwise
299
+ the equivalent matplotlib ``plot`` object will be returned.
300
+ Defaults to True.
301
+ lower_limit : Number, optional
302
+ The lower limit of the plot range. Defaults to 0.
303
+ upper_limit : Number, optional
304
+ The upper limit of the plot range. Defaults to 10.
305
+ prec : int, optional
306
+ The decimal point precision for the point coordinate values.
307
+ Defaults to 8.
308
+ show_axes : boolean, optional
309
+ If ``True``, the coordinate axes will be shown. Defaults to False.
310
+ grid : boolean, optional
311
+ If ``True``, the plot will have a grid. Defaults to True.
312
+
313
+ Examples
314
+ ========
315
+
316
+ .. plot::
317
+ :context: close-figs
318
+ :format: doctest
319
+ :include-source: True
320
+
321
+ >>> from sympy.abc import s
322
+ >>> from sympy.physics.control.lti import TransferFunction
323
+ >>> from sympy.physics.control.control_plots import step_response_plot
324
+ >>> tf1 = TransferFunction(8*s**2 + 18*s + 32, s**3 + 6*s**2 + 14*s + 24, s)
325
+ >>> step_response_plot(tf1) # doctest: +SKIP
326
+
327
+ See Also
328
+ ========
329
+
330
+ impulse_response_plot, ramp_response_plot
331
+
332
+ References
333
+ ==========
334
+
335
+ .. [1] https://www.mathworks.com/help/control/ref/lti.step.html
336
+
337
+ """
338
+ x, y = step_response_numerical_data(system, prec=prec,
339
+ lower_limit=lower_limit, upper_limit=upper_limit, **kwargs)
340
+ plt.plot(x, y, color=color)
341
+ plt.xlabel('Time (s)')
342
+ plt.ylabel('Amplitude')
343
+ plt.title(f'Unit Step Response of ${latex(system)}$', pad=20)
344
+
345
+ if grid:
346
+ plt.grid()
347
+ if show_axes:
348
+ plt.axhline(0, color='black')
349
+ plt.axvline(0, color='black')
350
+ if show:
351
+ plt.show()
352
+ return
353
+
354
+ return plt
355
+
356
+
357
+ def impulse_response_numerical_data(system, prec=8, lower_limit=0,
358
+ upper_limit=10, **kwargs):
359
+ """
360
+ Returns the numerical values of the points in the impulse response plot
361
+ of a SISO continuous-time system. By default, adaptive sampling
362
+ is used. If the user wants to instead get an uniformly
363
+ sampled response, then ``adaptive`` kwarg should be passed ``False``
364
+ and ``n`` must be passed as additional kwargs.
365
+ Refer to the parameters of class :class:`sympy.plotting.series.LineOver1DRangeSeries`
366
+ for more details.
367
+
368
+ Parameters
369
+ ==========
370
+
371
+ system : SISOLinearTimeInvariant
372
+ The system for which the impulse response data is to be computed.
373
+ prec : int, optional
374
+ The decimal point precision for the point coordinate values.
375
+ Defaults to 8.
376
+ lower_limit : Number, optional
377
+ The lower limit of the plot range. Defaults to 0.
378
+ upper_limit : Number, optional
379
+ The upper limit of the plot range. Defaults to 10.
380
+ kwargs :
381
+ Additional keyword arguments are passed to the underlying
382
+ :class:`sympy.plotting.series.LineOver1DRangeSeries` class.
383
+
384
+ Returns
385
+ =======
386
+
387
+ tuple : (x, y)
388
+ x = Time-axis values of the points in the impulse response. NumPy array.
389
+ y = Amplitude-axis values of the points in the impulse response. NumPy array.
390
+
391
+ Raises
392
+ ======
393
+
394
+ NotImplementedError
395
+ When a SISO LTI system is not passed.
396
+
397
+ When time delay terms are present in the system.
398
+
399
+ ValueError
400
+ When more than one free symbol is present in the system.
401
+ The only variable in the transfer function should be
402
+ the variable of the Laplace transform.
403
+
404
+ When ``lower_limit`` parameter is less than 0.
405
+
406
+ Examples
407
+ ========
408
+
409
+ >>> from sympy.abc import s
410
+ >>> from sympy.physics.control.lti import TransferFunction
411
+ >>> from sympy.physics.control.control_plots import impulse_response_numerical_data
412
+ >>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s)
413
+ >>> impulse_response_numerical_data(tf1) # doctest: +SKIP
414
+ ([0.0, 0.06616480200395854,... , 9.854500743565858, 10.0],
415
+ [0.9999999799999999, 0.7042848373025861,...,7.170748906965121e-13, -5.1901263495547205e-12])
416
+
417
+ See Also
418
+ ========
419
+
420
+ impulse_response_plot
421
+
422
+ """
423
+ if lower_limit < 0:
424
+ raise ValueError("Lower limit of time must be greater "
425
+ "than or equal to zero.")
426
+ _check_system(system)
427
+ _x = Dummy("x")
428
+ expr = system.to_expr()
429
+ expr = apart(expr, system.var, full=True)
430
+ _y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec)
431
+ return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit),
432
+ **kwargs).get_points()
433
+
434
+
435
+ def impulse_response_plot(system, color='b', prec=8, lower_limit=0,
436
+ upper_limit=10, show_axes=False, grid=True, show=True, **kwargs):
437
+ r"""
438
+ Returns the unit impulse response (Input is the Dirac-Delta Function) of a
439
+ continuous-time system.
440
+
441
+ Parameters
442
+ ==========
443
+
444
+ system : SISOLinearTimeInvariant type
445
+ The LTI SISO system for which the Impulse Response is to be computed.
446
+ color : str, tuple, optional
447
+ The color of the line. Default is Blue.
448
+ show : boolean, optional
449
+ If ``True``, the plot will be displayed otherwise
450
+ the equivalent matplotlib ``plot`` object will be returned.
451
+ Defaults to True.
452
+ lower_limit : Number, optional
453
+ The lower limit of the plot range. Defaults to 0.
454
+ upper_limit : Number, optional
455
+ The upper limit of the plot range. Defaults to 10.
456
+ prec : int, optional
457
+ The decimal point precision for the point coordinate values.
458
+ Defaults to 8.
459
+ show_axes : boolean, optional
460
+ If ``True``, the coordinate axes will be shown. Defaults to False.
461
+ grid : boolean, optional
462
+ If ``True``, the plot will have a grid. Defaults to True.
463
+
464
+ Examples
465
+ ========
466
+
467
+ .. plot::
468
+ :context: close-figs
469
+ :format: doctest
470
+ :include-source: True
471
+
472
+ >>> from sympy.abc import s
473
+ >>> from sympy.physics.control.lti import TransferFunction
474
+ >>> from sympy.physics.control.control_plots import impulse_response_plot
475
+ >>> tf1 = TransferFunction(8*s**2 + 18*s + 32, s**3 + 6*s**2 + 14*s + 24, s)
476
+ >>> impulse_response_plot(tf1) # doctest: +SKIP
477
+
478
+ See Also
479
+ ========
480
+
481
+ step_response_plot, ramp_response_plot
482
+
483
+ References
484
+ ==========
485
+
486
+ .. [1] https://www.mathworks.com/help/control/ref/dynamicsystem.impulse.html
487
+
488
+ """
489
+ x, y = impulse_response_numerical_data(system, prec=prec,
490
+ lower_limit=lower_limit, upper_limit=upper_limit, **kwargs)
491
+ plt.plot(x, y, color=color)
492
+ plt.xlabel('Time (s)')
493
+ plt.ylabel('Amplitude')
494
+ plt.title(f'Impulse Response of ${latex(system)}$', pad=20)
495
+
496
+ if grid:
497
+ plt.grid()
498
+ if show_axes:
499
+ plt.axhline(0, color='black')
500
+ plt.axvline(0, color='black')
501
+ if show:
502
+ plt.show()
503
+ return
504
+
505
+ return plt
506
+
507
+
508
+ def ramp_response_numerical_data(system, slope=1, prec=8,
509
+ lower_limit=0, upper_limit=10, **kwargs):
510
+ """
511
+ Returns the numerical values of the points in the ramp response plot
512
+ of a SISO continuous-time system. By default, adaptive sampling
513
+ is used. If the user wants to instead get an uniformly
514
+ sampled response, then ``adaptive`` kwarg should be passed ``False``
515
+ and ``n`` must be passed as additional kwargs.
516
+ Refer to the parameters of class :class:`sympy.plotting.series.LineOver1DRangeSeries`
517
+ for more details.
518
+
519
+ Parameters
520
+ ==========
521
+
522
+ system : SISOLinearTimeInvariant
523
+ The system for which the ramp response data is to be computed.
524
+ slope : Number, optional
525
+ The slope of the input ramp function. Defaults to 1.
526
+ prec : int, optional
527
+ The decimal point precision for the point coordinate values.
528
+ Defaults to 8.
529
+ lower_limit : Number, optional
530
+ The lower limit of the plot range. Defaults to 0.
531
+ upper_limit : Number, optional
532
+ The upper limit of the plot range. Defaults to 10.
533
+ kwargs :
534
+ Additional keyword arguments are passed to the underlying
535
+ :class:`sympy.plotting.series.LineOver1DRangeSeries` class.
536
+
537
+ Returns
538
+ =======
539
+
540
+ tuple : (x, y)
541
+ x = Time-axis values of the points in the ramp response plot. NumPy array.
542
+ y = Amplitude-axis values of the points in the ramp response plot. NumPy array.
543
+
544
+ Raises
545
+ ======
546
+
547
+ NotImplementedError
548
+ When a SISO LTI system is not passed.
549
+
550
+ When time delay terms are present in the system.
551
+
552
+ ValueError
553
+ When more than one free symbol is present in the system.
554
+ The only variable in the transfer function should be
555
+ the variable of the Laplace transform.
556
+
557
+ When ``lower_limit`` parameter is less than 0.
558
+
559
+ When ``slope`` is negative.
560
+
561
+ Examples
562
+ ========
563
+
564
+ >>> from sympy.abc import s
565
+ >>> from sympy.physics.control.lti import TransferFunction
566
+ >>> from sympy.physics.control.control_plots import ramp_response_numerical_data
567
+ >>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s)
568
+ >>> ramp_response_numerical_data(tf1) # doctest: +SKIP
569
+ (([0.0, 0.12166980856813935,..., 9.861246379582118, 10.0],
570
+ [1.4504508011325967e-09, 0.006046440489058766,..., 0.12499999999568202, 0.12499999999661349]))
571
+
572
+ See Also
573
+ ========
574
+
575
+ ramp_response_plot
576
+
577
+ """
578
+ if slope < 0:
579
+ raise ValueError("Slope must be greater than or equal"
580
+ " to zero.")
581
+ if lower_limit < 0:
582
+ raise ValueError("Lower limit of time must be greater "
583
+ "than or equal to zero.")
584
+ _check_system(system)
585
+ _x = Dummy("x")
586
+ expr = (slope*system.to_expr())/((system.var)**2)
587
+ expr = apart(expr, system.var, full=True)
588
+ _y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec)
589
+ return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit),
590
+ **kwargs).get_points()
591
+
592
+
593
+ def ramp_response_plot(system, slope=1, color='b', prec=8, lower_limit=0,
594
+ upper_limit=10, show_axes=False, grid=True, show=True, **kwargs):
595
+ r"""
596
+ Returns the ramp response of a continuous-time system.
597
+
598
+ Ramp function is defined as the straight line
599
+ passing through origin ($f(x) = mx$). The slope of
600
+ the ramp function can be varied by the user and
601
+ the default value is 1.
602
+
603
+ Parameters
604
+ ==========
605
+
606
+ system : SISOLinearTimeInvariant type
607
+ The LTI SISO system for which the Ramp Response is to be computed.
608
+ slope : Number, optional
609
+ The slope of the input ramp function. Defaults to 1.
610
+ color : str, tuple, optional
611
+ The color of the line. Default is Blue.
612
+ show : boolean, optional
613
+ If ``True``, the plot will be displayed otherwise
614
+ the equivalent matplotlib ``plot`` object will be returned.
615
+ Defaults to True.
616
+ lower_limit : Number, optional
617
+ The lower limit of the plot range. Defaults to 0.
618
+ upper_limit : Number, optional
619
+ The upper limit of the plot range. Defaults to 10.
620
+ prec : int, optional
621
+ The decimal point precision for the point coordinate values.
622
+ Defaults to 8.
623
+ show_axes : boolean, optional
624
+ If ``True``, the coordinate axes will be shown. Defaults to False.
625
+ grid : boolean, optional
626
+ If ``True``, the plot will have a grid. Defaults to True.
627
+
628
+ Examples
629
+ ========
630
+
631
+ .. plot::
632
+ :context: close-figs
633
+ :format: doctest
634
+ :include-source: True
635
+
636
+ >>> from sympy.abc import s
637
+ >>> from sympy.physics.control.lti import TransferFunction
638
+ >>> from sympy.physics.control.control_plots import ramp_response_plot
639
+ >>> tf1 = TransferFunction(s, (s+4)*(s+8), s)
640
+ >>> ramp_response_plot(tf1, upper_limit=2) # doctest: +SKIP
641
+
642
+ See Also
643
+ ========
644
+
645
+ step_response_plot, impulse_response_plot
646
+
647
+ References
648
+ ==========
649
+
650
+ .. [1] https://en.wikipedia.org/wiki/Ramp_function
651
+
652
+ """
653
+ x, y = ramp_response_numerical_data(system, slope=slope, prec=prec,
654
+ lower_limit=lower_limit, upper_limit=upper_limit, **kwargs)
655
+ plt.plot(x, y, color=color)
656
+ plt.xlabel('Time (s)')
657
+ plt.ylabel('Amplitude')
658
+ plt.title(f'Ramp Response of ${latex(system)}$ [Slope = {slope}]', pad=20)
659
+
660
+ if grid:
661
+ plt.grid()
662
+ if show_axes:
663
+ plt.axhline(0, color='black')
664
+ plt.axvline(0, color='black')
665
+ if show:
666
+ plt.show()
667
+ return
668
+
669
+ return plt
670
+
671
+
672
+ def bode_magnitude_numerical_data(system, initial_exp=-5, final_exp=5, freq_unit='rad/sec', **kwargs):
673
+ """
674
+ Returns the numerical data of the Bode magnitude plot of the system.
675
+ It is internally used by ``bode_magnitude_plot`` to get the data
676
+ for plotting Bode magnitude plot. Users can use this data to further
677
+ analyse the dynamics of the system or plot using a different
678
+ backend/plotting-module.
679
+
680
+ Parameters
681
+ ==========
682
+
683
+ system : SISOLinearTimeInvariant
684
+ The system for which the data is to be computed.
685
+ initial_exp : Number, optional
686
+ The initial exponent of 10 of the semilog plot. Defaults to -5.
687
+ final_exp : Number, optional
688
+ The final exponent of 10 of the semilog plot. Defaults to 5.
689
+ freq_unit : string, optional
690
+ User can choose between ``'rad/sec'`` (radians/second) and ``'Hz'`` (Hertz) as frequency units.
691
+
692
+ Returns
693
+ =======
694
+
695
+ tuple : (x, y)
696
+ x = x-axis values of the Bode magnitude plot.
697
+ y = y-axis values of the Bode magnitude plot.
698
+
699
+ Raises
700
+ ======
701
+
702
+ NotImplementedError
703
+ When a SISO LTI system is not passed.
704
+
705
+ When time delay terms are present in the system.
706
+
707
+ ValueError
708
+ When more than one free symbol is present in the system.
709
+ The only variable in the transfer function should be
710
+ the variable of the Laplace transform.
711
+
712
+ When incorrect frequency units are given as input.
713
+
714
+ Examples
715
+ ========
716
+
717
+ >>> from sympy.abc import s
718
+ >>> from sympy.physics.control.lti import TransferFunction
719
+ >>> from sympy.physics.control.control_plots import bode_magnitude_numerical_data
720
+ >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s)
721
+ >>> bode_magnitude_numerical_data(tf1) # doctest: +SKIP
722
+ ([1e-05, 1.5148378120533502e-05,..., 68437.36188804005, 100000.0],
723
+ [-6.020599914256786, -6.0205999155219505,..., -193.4117304087953, -200.00000000260573])
724
+
725
+ See Also
726
+ ========
727
+
728
+ bode_magnitude_plot, bode_phase_numerical_data
729
+
730
+ """
731
+ _check_system(system)
732
+ expr = system.to_expr()
733
+ freq_units = ('rad/sec', 'Hz')
734
+ if freq_unit not in freq_units:
735
+ raise ValueError('Only "rad/sec" and "Hz" are accepted frequency units.')
736
+
737
+ _w = Dummy("w", real=True)
738
+ if freq_unit == 'Hz':
739
+ repl = I*_w*2*pi
740
+ else:
741
+ repl = I*_w
742
+ w_expr = expr.subs({system.var: repl})
743
+
744
+ mag = 20*log(Abs(w_expr), 10)
745
+
746
+ x, y = LineOver1DRangeSeries(mag,
747
+ (_w, 10**initial_exp, 10**final_exp), xscale='log', **kwargs).get_points()
748
+
749
+ return x, y
750
+
751
+
752
+ def bode_magnitude_plot(system, initial_exp=-5, final_exp=5,
753
+ color='b', show_axes=False, grid=True, show=True, freq_unit='rad/sec', **kwargs):
754
+ r"""
755
+ Returns the Bode magnitude plot of a continuous-time system.
756
+
757
+ See ``bode_plot`` for all the parameters.
758
+ """
759
+ x, y = bode_magnitude_numerical_data(system, initial_exp=initial_exp,
760
+ final_exp=final_exp, freq_unit=freq_unit)
761
+ plt.plot(x, y, color=color, **kwargs)
762
+ plt.xscale('log')
763
+
764
+
765
+ plt.xlabel('Frequency (%s) [Log Scale]' % freq_unit)
766
+ plt.ylabel('Magnitude (dB)')
767
+ plt.title(f'Bode Plot (Magnitude) of ${latex(system)}$', pad=20)
768
+
769
+ if grid:
770
+ plt.grid(True)
771
+ if show_axes:
772
+ plt.axhline(0, color='black')
773
+ plt.axvline(0, color='black')
774
+ if show:
775
+ plt.show()
776
+ return
777
+
778
+ return plt
779
+
780
+
781
+ def bode_phase_numerical_data(system, initial_exp=-5, final_exp=5, freq_unit='rad/sec', phase_unit='rad', phase_unwrap = True, **kwargs):
782
+ """
783
+ Returns the numerical data of the Bode phase plot of the system.
784
+ It is internally used by ``bode_phase_plot`` to get the data
785
+ for plotting Bode phase plot. Users can use this data to further
786
+ analyse the dynamics of the system or plot using a different
787
+ backend/plotting-module.
788
+
789
+ Parameters
790
+ ==========
791
+
792
+ system : SISOLinearTimeInvariant
793
+ The system for which the Bode phase plot data is to be computed.
794
+ initial_exp : Number, optional
795
+ The initial exponent of 10 of the semilog plot. Defaults to -5.
796
+ final_exp : Number, optional
797
+ The final exponent of 10 of the semilog plot. Defaults to 5.
798
+ freq_unit : string, optional
799
+ User can choose between ``'rad/sec'`` (radians/second) and '``'Hz'`` (Hertz) as frequency units.
800
+ phase_unit : string, optional
801
+ User can choose between ``'rad'`` (radians) and ``'deg'`` (degree) as phase units.
802
+ phase_unwrap : bool, optional
803
+ Set to ``True`` by default.
804
+
805
+ Returns
806
+ =======
807
+
808
+ tuple : (x, y)
809
+ x = x-axis values of the Bode phase plot.
810
+ y = y-axis values of the Bode phase plot.
811
+
812
+ Raises
813
+ ======
814
+
815
+ NotImplementedError
816
+ When a SISO LTI system is not passed.
817
+
818
+ When time delay terms are present in the system.
819
+
820
+ ValueError
821
+ When more than one free symbol is present in the system.
822
+ The only variable in the transfer function should be
823
+ the variable of the Laplace transform.
824
+
825
+ When incorrect frequency or phase units are given as input.
826
+
827
+ Examples
828
+ ========
829
+
830
+ >>> from sympy.abc import s
831
+ >>> from sympy.physics.control.lti import TransferFunction
832
+ >>> from sympy.physics.control.control_plots import bode_phase_numerical_data
833
+ >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s)
834
+ >>> bode_phase_numerical_data(tf1) # doctest: +SKIP
835
+ ([1e-05, 1.4472354033813751e-05, 2.035581932165858e-05,..., 47577.3248186011, 67884.09326036123, 100000.0],
836
+ [-2.5000000000291665e-05, -3.6180885085e-05, -5.08895483066e-05,...,-3.1415085799262523, -3.14155265358979])
837
+
838
+ See Also
839
+ ========
840
+
841
+ bode_magnitude_plot, bode_phase_numerical_data
842
+
843
+ """
844
+ _check_system(system)
845
+ expr = system.to_expr()
846
+ freq_units = ('rad/sec', 'Hz')
847
+ phase_units = ('rad', 'deg')
848
+ if freq_unit not in freq_units:
849
+ raise ValueError('Only "rad/sec" and "Hz" are accepted frequency units.')
850
+ if phase_unit not in phase_units:
851
+ raise ValueError('Only "rad" and "deg" are accepted phase units.')
852
+
853
+ _w = Dummy("w", real=True)
854
+ if freq_unit == 'Hz':
855
+ repl = I*_w*2*pi
856
+ else:
857
+ repl = I*_w
858
+ w_expr = expr.subs({system.var: repl})
859
+
860
+ if phase_unit == 'deg':
861
+ phase = arg(w_expr)*180/pi
862
+ else:
863
+ phase = arg(w_expr)
864
+
865
+ x, y = LineOver1DRangeSeries(phase,
866
+ (_w, 10**initial_exp, 10**final_exp), xscale='log', **kwargs).get_points()
867
+
868
+ half = None
869
+ if phase_unwrap:
870
+ if(phase_unit == 'rad'):
871
+ half = pi
872
+ elif(phase_unit == 'deg'):
873
+ half = 180
874
+ if half:
875
+ unit = 2*half
876
+ for i in range(1, len(y)):
877
+ diff = y[i] - y[i - 1]
878
+ if diff > half: # Jump from -half to half
879
+ y[i] = (y[i] - unit)
880
+ elif diff < -half: # Jump from half to -half
881
+ y[i] = (y[i] + unit)
882
+
883
+ return x, y
884
+
885
+
886
+ def bode_phase_plot(system, initial_exp=-5, final_exp=5,
887
+ color='b', show_axes=False, grid=True, show=True, freq_unit='rad/sec', phase_unit='rad', phase_unwrap=True, **kwargs):
888
+ r"""
889
+ Returns the Bode phase plot of a continuous-time system.
890
+
891
+ See ``bode_plot`` for all the parameters.
892
+ """
893
+ x, y = bode_phase_numerical_data(system, initial_exp=initial_exp,
894
+ final_exp=final_exp, freq_unit=freq_unit, phase_unit=phase_unit, phase_unwrap=phase_unwrap)
895
+ plt.plot(x, y, color=color, **kwargs)
896
+ plt.xscale('log')
897
+
898
+ plt.xlabel('Frequency (%s) [Log Scale]' % freq_unit)
899
+ plt.ylabel('Phase (%s)' % phase_unit)
900
+ plt.title(f'Bode Plot (Phase) of ${latex(system)}$', pad=20)
901
+
902
+ if grid:
903
+ plt.grid(True)
904
+ if show_axes:
905
+ plt.axhline(0, color='black')
906
+ plt.axvline(0, color='black')
907
+ if show:
908
+ plt.show()
909
+ return
910
+
911
+ return plt
912
+
913
+
914
+ def bode_plot(system, initial_exp=-5, final_exp=5,
915
+ grid=True, show_axes=False, show=True, freq_unit='rad/sec', phase_unit='rad', phase_unwrap=True, **kwargs):
916
+ r"""
917
+ Returns the Bode phase and magnitude plots of a continuous-time system.
918
+
919
+ Parameters
920
+ ==========
921
+
922
+ system : SISOLinearTimeInvariant type
923
+ The LTI SISO system for which the Bode Plot is to be computed.
924
+ initial_exp : Number, optional
925
+ The initial exponent of 10 of the semilog plot. Defaults to -5.
926
+ final_exp : Number, optional
927
+ The final exponent of 10 of the semilog plot. Defaults to 5.
928
+ show : boolean, optional
929
+ If ``True``, the plot will be displayed otherwise
930
+ the equivalent matplotlib ``plot`` object will be returned.
931
+ Defaults to True.
932
+ prec : int, optional
933
+ The decimal point precision for the point coordinate values.
934
+ Defaults to 8.
935
+ grid : boolean, optional
936
+ If ``True``, the plot will have a grid. Defaults to True.
937
+ show_axes : boolean, optional
938
+ If ``True``, the coordinate axes will be shown. Defaults to False.
939
+ freq_unit : string, optional
940
+ User can choose between ``'rad/sec'`` (radians/second) and ``'Hz'`` (Hertz) as frequency units.
941
+ phase_unit : string, optional
942
+ User can choose between ``'rad'`` (radians) and ``'deg'`` (degree) as phase units.
943
+
944
+ Examples
945
+ ========
946
+
947
+ .. plot::
948
+ :context: close-figs
949
+ :format: doctest
950
+ :include-source: True
951
+
952
+ >>> from sympy.abc import s
953
+ >>> from sympy.physics.control.lti import TransferFunction
954
+ >>> from sympy.physics.control.control_plots import bode_plot
955
+ >>> tf1 = TransferFunction(1*s**2 + 0.1*s + 7.5, 1*s**4 + 0.12*s**3 + 9*s**2, s)
956
+ >>> bode_plot(tf1, initial_exp=0.2, final_exp=0.7) # doctest: +SKIP
957
+
958
+ See Also
959
+ ========
960
+
961
+ bode_magnitude_plot, bode_phase_plot
962
+
963
+ """
964
+ plt.subplot(211)
965
+ mag = bode_magnitude_plot(system, initial_exp=initial_exp, final_exp=final_exp,
966
+ show=False, grid=grid, show_axes=show_axes,
967
+ freq_unit=freq_unit, **kwargs)
968
+ mag.title(f'Bode Plot of ${latex(system)}$', pad=20)
969
+ mag.xlabel(None)
970
+ plt.subplot(212)
971
+ bode_phase_plot(system, initial_exp=initial_exp, final_exp=final_exp,
972
+ show=False, grid=grid, show_axes=show_axes, freq_unit=freq_unit, phase_unit=phase_unit, phase_unwrap=phase_unwrap, **kwargs).title(None)
973
+
974
+ if show:
975
+ plt.show()
976
+ return
977
+
978
+ return plt
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/tests/test_physics_matrices.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.physics.matrices import msigma, mgamma, minkowski_tensor, pat_matrix, mdft
2
+ from sympy.core.numbers import (I, Rational)
3
+ from sympy.core.singleton import S
4
+ from sympy.functions.elementary.miscellaneous import sqrt
5
+ from sympy.matrices.dense import (Matrix, eye, zeros)
6
+ from sympy.testing.pytest import warns_deprecated_sympy
7
+
8
+
9
+ def test_parallel_axis_theorem():
10
+ # This tests the parallel axis theorem matrix by comparing to test
11
+ # matrices.
12
+
13
+ # First case, 1 in all directions.
14
+ mat1 = Matrix(((2, -1, -1), (-1, 2, -1), (-1, -1, 2)))
15
+ assert pat_matrix(1, 1, 1, 1) == mat1
16
+ assert pat_matrix(2, 1, 1, 1) == 2*mat1
17
+
18
+ # Second case, 1 in x, 0 in all others
19
+ mat2 = Matrix(((0, 0, 0), (0, 1, 0), (0, 0, 1)))
20
+ assert pat_matrix(1, 1, 0, 0) == mat2
21
+ assert pat_matrix(2, 1, 0, 0) == 2*mat2
22
+
23
+ # Third case, 1 in y, 0 in all others
24
+ mat3 = Matrix(((1, 0, 0), (0, 0, 0), (0, 0, 1)))
25
+ assert pat_matrix(1, 0, 1, 0) == mat3
26
+ assert pat_matrix(2, 0, 1, 0) == 2*mat3
27
+
28
+ # Fourth case, 1 in z, 0 in all others
29
+ mat4 = Matrix(((1, 0, 0), (0, 1, 0), (0, 0, 0)))
30
+ assert pat_matrix(1, 0, 0, 1) == mat4
31
+ assert pat_matrix(2, 0, 0, 1) == 2*mat4
32
+
33
+
34
+ def test_Pauli():
35
+ #this and the following test are testing both Pauli and Dirac matrices
36
+ #and also that the general Matrix class works correctly in a real world
37
+ #situation
38
+ sigma1 = msigma(1)
39
+ sigma2 = msigma(2)
40
+ sigma3 = msigma(3)
41
+
42
+ assert sigma1 == sigma1
43
+ assert sigma1 != sigma2
44
+
45
+ # sigma*I -> I*sigma (see #354)
46
+ assert sigma1*sigma2 == sigma3*I
47
+ assert sigma3*sigma1 == sigma2*I
48
+ assert sigma2*sigma3 == sigma1*I
49
+
50
+ assert sigma1*sigma1 == eye(2)
51
+ assert sigma2*sigma2 == eye(2)
52
+ assert sigma3*sigma3 == eye(2)
53
+
54
+ assert sigma1*2*sigma1 == 2*eye(2)
55
+ assert sigma1*sigma3*sigma1 == -sigma3
56
+
57
+
58
+ def test_Dirac():
59
+ gamma0 = mgamma(0)
60
+ gamma1 = mgamma(1)
61
+ gamma2 = mgamma(2)
62
+ gamma3 = mgamma(3)
63
+ gamma5 = mgamma(5)
64
+
65
+ # gamma*I -> I*gamma (see #354)
66
+ assert gamma5 == gamma0 * gamma1 * gamma2 * gamma3 * I
67
+ assert gamma1 * gamma2 + gamma2 * gamma1 == zeros(4)
68
+ assert gamma0 * gamma0 == eye(4) * minkowski_tensor[0, 0]
69
+ assert gamma2 * gamma2 != eye(4) * minkowski_tensor[0, 0]
70
+ assert gamma2 * gamma2 == eye(4) * minkowski_tensor[2, 2]
71
+
72
+ assert mgamma(5, True) == \
73
+ mgamma(0, True)*mgamma(1, True)*mgamma(2, True)*mgamma(3, True)*I
74
+
75
+ def test_mdft():
76
+ with warns_deprecated_sympy():
77
+ assert mdft(1) == Matrix([[1]])
78
+ with warns_deprecated_sympy():
79
+ assert mdft(2) == 1/sqrt(2)*Matrix([[1,1],[1,-1]])
80
+ with warns_deprecated_sympy():
81
+ assert mdft(4) == Matrix([[S.Half, S.Half, S.Half, S.Half],
82
+ [S.Half, -I/2, Rational(-1,2), I/2],
83
+ [S.Half, Rational(-1,2), S.Half, Rational(-1,2)],
84
+ [S.Half, I/2, Rational(-1,2), -I/2]])
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__init__.py ADDED
@@ -0,0 +1,453 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # isort:skip_file
2
+ """
3
+ Dimensional analysis and unit systems.
4
+
5
+ This module defines dimension/unit systems and physical quantities. It is
6
+ based on a group-theoretical construction where dimensions are represented as
7
+ vectors (coefficients being the exponents), and units are defined as a dimension
8
+ to which we added a scale.
9
+
10
+ Quantities are built from a factor and a unit, and are the basic objects that
11
+ one will use when doing computations.
12
+
13
+ All objects except systems and prefixes can be used in SymPy expressions.
14
+ Note that as part of a CAS, various objects do not combine automatically
15
+ under operations.
16
+
17
+ Details about the implementation can be found in the documentation, and we
18
+ will not repeat all the explanations we gave there concerning our approach.
19
+ Ideas about future developments can be found on the `Github wiki
20
+ <https://github.com/sympy/sympy/wiki/Unit-systems>`_, and you should consult
21
+ this page if you are willing to help.
22
+
23
+ Useful functions:
24
+
25
+ - ``find_unit``: easily lookup pre-defined units.
26
+ - ``convert_to(expr, newunit)``: converts an expression into the same
27
+ expression expressed in another unit.
28
+
29
+ """
30
+
31
+ from .dimensions import Dimension, DimensionSystem
32
+ from .unitsystem import UnitSystem
33
+ from .util import convert_to
34
+ from .quantities import Quantity
35
+
36
+ from .definitions.dimension_definitions import (
37
+ amount_of_substance, acceleration, action, area,
38
+ capacitance, charge, conductance, current, energy,
39
+ force, frequency, impedance, inductance, length,
40
+ luminous_intensity, magnetic_density,
41
+ magnetic_flux, mass, momentum, power, pressure, temperature, time,
42
+ velocity, voltage, volume
43
+ )
44
+
45
+ Unit = Quantity
46
+
47
+ speed = velocity
48
+ luminosity = luminous_intensity
49
+ magnetic_flux_density = magnetic_density
50
+ amount = amount_of_substance
51
+
52
+ from .prefixes import (
53
+ # 10-power based:
54
+ yotta,
55
+ zetta,
56
+ exa,
57
+ peta,
58
+ tera,
59
+ giga,
60
+ mega,
61
+ kilo,
62
+ hecto,
63
+ deca,
64
+ deci,
65
+ centi,
66
+ milli,
67
+ micro,
68
+ nano,
69
+ pico,
70
+ femto,
71
+ atto,
72
+ zepto,
73
+ yocto,
74
+ # 2-power based:
75
+ kibi,
76
+ mebi,
77
+ gibi,
78
+ tebi,
79
+ pebi,
80
+ exbi,
81
+ )
82
+
83
+ from .definitions import (
84
+ percent, percents,
85
+ permille,
86
+ rad, radian, radians,
87
+ deg, degree, degrees,
88
+ sr, steradian, steradians,
89
+ mil, angular_mil, angular_mils,
90
+ m, meter, meters,
91
+ kg, kilogram, kilograms,
92
+ s, second, seconds,
93
+ A, ampere, amperes,
94
+ K, kelvin, kelvins,
95
+ mol, mole, moles,
96
+ cd, candela, candelas,
97
+ g, gram, grams,
98
+ mg, milligram, milligrams,
99
+ ug, microgram, micrograms,
100
+ t, tonne, metric_ton,
101
+ newton, newtons, N,
102
+ joule, joules, J,
103
+ watt, watts, W,
104
+ pascal, pascals, Pa, pa,
105
+ hertz, hz, Hz,
106
+ coulomb, coulombs, C,
107
+ volt, volts, v, V,
108
+ ohm, ohms,
109
+ siemens, S, mho, mhos,
110
+ farad, farads, F,
111
+ henry, henrys, H,
112
+ tesla, teslas, T,
113
+ weber, webers, Wb, wb,
114
+ optical_power, dioptre, D,
115
+ lux, lx,
116
+ katal, kat,
117
+ gray, Gy,
118
+ becquerel, Bq,
119
+ km, kilometer, kilometers,
120
+ dm, decimeter, decimeters,
121
+ cm, centimeter, centimeters,
122
+ mm, millimeter, millimeters,
123
+ um, micrometer, micrometers, micron, microns,
124
+ nm, nanometer, nanometers,
125
+ pm, picometer, picometers,
126
+ ft, foot, feet,
127
+ inch, inches,
128
+ yd, yard, yards,
129
+ mi, mile, miles,
130
+ nmi, nautical_mile, nautical_miles,
131
+ angstrom, angstroms,
132
+ ha, hectare,
133
+ l, L, liter, liters,
134
+ dl, dL, deciliter, deciliters,
135
+ cl, cL, centiliter, centiliters,
136
+ ml, mL, milliliter, milliliters,
137
+ ms, millisecond, milliseconds,
138
+ us, microsecond, microseconds,
139
+ ns, nanosecond, nanoseconds,
140
+ ps, picosecond, picoseconds,
141
+ minute, minutes,
142
+ h, hour, hours,
143
+ day, days,
144
+ anomalistic_year, anomalistic_years,
145
+ sidereal_year, sidereal_years,
146
+ tropical_year, tropical_years,
147
+ common_year, common_years,
148
+ julian_year, julian_years,
149
+ draconic_year, draconic_years,
150
+ gaussian_year, gaussian_years,
151
+ full_moon_cycle, full_moon_cycles,
152
+ year, years,
153
+ G, gravitational_constant,
154
+ c, speed_of_light,
155
+ elementary_charge,
156
+ hbar,
157
+ planck,
158
+ eV, electronvolt, electronvolts,
159
+ avogadro_number,
160
+ avogadro, avogadro_constant,
161
+ boltzmann, boltzmann_constant,
162
+ stefan, stefan_boltzmann_constant,
163
+ R, molar_gas_constant,
164
+ faraday_constant,
165
+ josephson_constant,
166
+ von_klitzing_constant,
167
+ Da, dalton, amu, amus, atomic_mass_unit, atomic_mass_constant,
168
+ me, electron_rest_mass,
169
+ gee, gees, acceleration_due_to_gravity,
170
+ u0, magnetic_constant, vacuum_permeability,
171
+ e0, electric_constant, vacuum_permittivity,
172
+ Z0, vacuum_impedance,
173
+ coulomb_constant, electric_force_constant,
174
+ atmosphere, atmospheres, atm,
175
+ kPa,
176
+ bar, bars,
177
+ pound, pounds,
178
+ psi,
179
+ dHg0,
180
+ mmHg, torr,
181
+ mmu, mmus, milli_mass_unit,
182
+ quart, quarts,
183
+ ly, lightyear, lightyears,
184
+ au, astronomical_unit, astronomical_units,
185
+ planck_mass,
186
+ planck_time,
187
+ planck_temperature,
188
+ planck_length,
189
+ planck_charge,
190
+ planck_area,
191
+ planck_volume,
192
+ planck_momentum,
193
+ planck_energy,
194
+ planck_force,
195
+ planck_power,
196
+ planck_density,
197
+ planck_energy_density,
198
+ planck_intensity,
199
+ planck_angular_frequency,
200
+ planck_pressure,
201
+ planck_current,
202
+ planck_voltage,
203
+ planck_impedance,
204
+ planck_acceleration,
205
+ bit, bits,
206
+ byte,
207
+ kibibyte, kibibytes,
208
+ mebibyte, mebibytes,
209
+ gibibyte, gibibytes,
210
+ tebibyte, tebibytes,
211
+ pebibyte, pebibytes,
212
+ exbibyte, exbibytes,
213
+ )
214
+
215
+ from .systems import (
216
+ mks, mksa, si
217
+ )
218
+
219
+
220
+ def find_unit(quantity, unit_system="SI"):
221
+ """
222
+ Return a list of matching units or dimension names.
223
+
224
+ - If ``quantity`` is a string -- units/dimensions containing the string
225
+ `quantity`.
226
+ - If ``quantity`` is a unit or dimension -- units having matching base
227
+ units or dimensions.
228
+
229
+ Examples
230
+ ========
231
+
232
+ >>> from sympy.physics import units as u
233
+ >>> u.find_unit('charge')
234
+ ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge']
235
+ >>> u.find_unit(u.charge)
236
+ ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge']
237
+ >>> u.find_unit("ampere")
238
+ ['ampere', 'amperes']
239
+ >>> u.find_unit('angstrom')
240
+ ['angstrom', 'angstroms']
241
+ >>> u.find_unit('volt')
242
+ ['volt', 'volts', 'electronvolt', 'electronvolts', 'planck_voltage']
243
+ >>> u.find_unit(u.inch**3)[:9]
244
+ ['L', 'l', 'cL', 'cl', 'dL', 'dl', 'mL', 'ml', 'liter']
245
+ """
246
+ unit_system = UnitSystem.get_unit_system(unit_system)
247
+
248
+ import sympy.physics.units as u
249
+ rv = []
250
+ if isinstance(quantity, str):
251
+ rv = [i for i in dir(u) if quantity in i and isinstance(getattr(u, i), Quantity)]
252
+ dim = getattr(u, quantity)
253
+ if isinstance(dim, Dimension):
254
+ rv.extend(find_unit(dim))
255
+ else:
256
+ for i in sorted(dir(u)):
257
+ other = getattr(u, i)
258
+ if not isinstance(other, Quantity):
259
+ continue
260
+ if isinstance(quantity, Quantity):
261
+ if quantity.dimension == other.dimension:
262
+ rv.append(str(i))
263
+ elif isinstance(quantity, Dimension):
264
+ if other.dimension == quantity:
265
+ rv.append(str(i))
266
+ elif other.dimension == Dimension(unit_system.get_dimensional_expr(quantity)):
267
+ rv.append(str(i))
268
+ return sorted(set(rv), key=lambda x: (len(x), x))
269
+
270
+ # NOTE: the old units module had additional variables:
271
+ # 'density', 'illuminance', 'resistance'.
272
+ # They were not dimensions, but units (old Unit class).
273
+
274
+ __all__ = [
275
+ 'Dimension', 'DimensionSystem',
276
+ 'UnitSystem',
277
+ 'convert_to',
278
+ 'Quantity',
279
+
280
+ 'amount_of_substance', 'acceleration', 'action', 'area',
281
+ 'capacitance', 'charge', 'conductance', 'current', 'energy',
282
+ 'force', 'frequency', 'impedance', 'inductance', 'length',
283
+ 'luminous_intensity', 'magnetic_density',
284
+ 'magnetic_flux', 'mass', 'momentum', 'power', 'pressure', 'temperature', 'time',
285
+ 'velocity', 'voltage', 'volume',
286
+
287
+ 'Unit',
288
+
289
+ 'speed',
290
+ 'luminosity',
291
+ 'magnetic_flux_density',
292
+ 'amount',
293
+
294
+ 'yotta',
295
+ 'zetta',
296
+ 'exa',
297
+ 'peta',
298
+ 'tera',
299
+ 'giga',
300
+ 'mega',
301
+ 'kilo',
302
+ 'hecto',
303
+ 'deca',
304
+ 'deci',
305
+ 'centi',
306
+ 'milli',
307
+ 'micro',
308
+ 'nano',
309
+ 'pico',
310
+ 'femto',
311
+ 'atto',
312
+ 'zepto',
313
+ 'yocto',
314
+
315
+ 'kibi',
316
+ 'mebi',
317
+ 'gibi',
318
+ 'tebi',
319
+ 'pebi',
320
+ 'exbi',
321
+
322
+ 'percent', 'percents',
323
+ 'permille',
324
+ 'rad', 'radian', 'radians',
325
+ 'deg', 'degree', 'degrees',
326
+ 'sr', 'steradian', 'steradians',
327
+ 'mil', 'angular_mil', 'angular_mils',
328
+ 'm', 'meter', 'meters',
329
+ 'kg', 'kilogram', 'kilograms',
330
+ 's', 'second', 'seconds',
331
+ 'A', 'ampere', 'amperes',
332
+ 'K', 'kelvin', 'kelvins',
333
+ 'mol', 'mole', 'moles',
334
+ 'cd', 'candela', 'candelas',
335
+ 'g', 'gram', 'grams',
336
+ 'mg', 'milligram', 'milligrams',
337
+ 'ug', 'microgram', 'micrograms',
338
+ 't', 'tonne', 'metric_ton',
339
+ 'newton', 'newtons', 'N',
340
+ 'joule', 'joules', 'J',
341
+ 'watt', 'watts', 'W',
342
+ 'pascal', 'pascals', 'Pa', 'pa',
343
+ 'hertz', 'hz', 'Hz',
344
+ 'coulomb', 'coulombs', 'C',
345
+ 'volt', 'volts', 'v', 'V',
346
+ 'ohm', 'ohms',
347
+ 'siemens', 'S', 'mho', 'mhos',
348
+ 'farad', 'farads', 'F',
349
+ 'henry', 'henrys', 'H',
350
+ 'tesla', 'teslas', 'T',
351
+ 'weber', 'webers', 'Wb', 'wb',
352
+ 'optical_power', 'dioptre', 'D',
353
+ 'lux', 'lx',
354
+ 'katal', 'kat',
355
+ 'gray', 'Gy',
356
+ 'becquerel', 'Bq',
357
+ 'km', 'kilometer', 'kilometers',
358
+ 'dm', 'decimeter', 'decimeters',
359
+ 'cm', 'centimeter', 'centimeters',
360
+ 'mm', 'millimeter', 'millimeters',
361
+ 'um', 'micrometer', 'micrometers', 'micron', 'microns',
362
+ 'nm', 'nanometer', 'nanometers',
363
+ 'pm', 'picometer', 'picometers',
364
+ 'ft', 'foot', 'feet',
365
+ 'inch', 'inches',
366
+ 'yd', 'yard', 'yards',
367
+ 'mi', 'mile', 'miles',
368
+ 'nmi', 'nautical_mile', 'nautical_miles',
369
+ 'angstrom', 'angstroms',
370
+ 'ha', 'hectare',
371
+ 'l', 'L', 'liter', 'liters',
372
+ 'dl', 'dL', 'deciliter', 'deciliters',
373
+ 'cl', 'cL', 'centiliter', 'centiliters',
374
+ 'ml', 'mL', 'milliliter', 'milliliters',
375
+ 'ms', 'millisecond', 'milliseconds',
376
+ 'us', 'microsecond', 'microseconds',
377
+ 'ns', 'nanosecond', 'nanoseconds',
378
+ 'ps', 'picosecond', 'picoseconds',
379
+ 'minute', 'minutes',
380
+ 'h', 'hour', 'hours',
381
+ 'day', 'days',
382
+ 'anomalistic_year', 'anomalistic_years',
383
+ 'sidereal_year', 'sidereal_years',
384
+ 'tropical_year', 'tropical_years',
385
+ 'common_year', 'common_years',
386
+ 'julian_year', 'julian_years',
387
+ 'draconic_year', 'draconic_years',
388
+ 'gaussian_year', 'gaussian_years',
389
+ 'full_moon_cycle', 'full_moon_cycles',
390
+ 'year', 'years',
391
+ 'G', 'gravitational_constant',
392
+ 'c', 'speed_of_light',
393
+ 'elementary_charge',
394
+ 'hbar',
395
+ 'planck',
396
+ 'eV', 'electronvolt', 'electronvolts',
397
+ 'avogadro_number',
398
+ 'avogadro', 'avogadro_constant',
399
+ 'boltzmann', 'boltzmann_constant',
400
+ 'stefan', 'stefan_boltzmann_constant',
401
+ 'R', 'molar_gas_constant',
402
+ 'faraday_constant',
403
+ 'josephson_constant',
404
+ 'von_klitzing_constant',
405
+ 'Da', 'dalton', 'amu', 'amus', 'atomic_mass_unit', 'atomic_mass_constant',
406
+ 'me', 'electron_rest_mass',
407
+ 'gee', 'gees', 'acceleration_due_to_gravity',
408
+ 'u0', 'magnetic_constant', 'vacuum_permeability',
409
+ 'e0', 'electric_constant', 'vacuum_permittivity',
410
+ 'Z0', 'vacuum_impedance',
411
+ 'coulomb_constant', 'electric_force_constant',
412
+ 'atmosphere', 'atmospheres', 'atm',
413
+ 'kPa',
414
+ 'bar', 'bars',
415
+ 'pound', 'pounds',
416
+ 'psi',
417
+ 'dHg0',
418
+ 'mmHg', 'torr',
419
+ 'mmu', 'mmus', 'milli_mass_unit',
420
+ 'quart', 'quarts',
421
+ 'ly', 'lightyear', 'lightyears',
422
+ 'au', 'astronomical_unit', 'astronomical_units',
423
+ 'planck_mass',
424
+ 'planck_time',
425
+ 'planck_temperature',
426
+ 'planck_length',
427
+ 'planck_charge',
428
+ 'planck_area',
429
+ 'planck_volume',
430
+ 'planck_momentum',
431
+ 'planck_energy',
432
+ 'planck_force',
433
+ 'planck_power',
434
+ 'planck_density',
435
+ 'planck_energy_density',
436
+ 'planck_intensity',
437
+ 'planck_angular_frequency',
438
+ 'planck_pressure',
439
+ 'planck_current',
440
+ 'planck_voltage',
441
+ 'planck_impedance',
442
+ 'planck_acceleration',
443
+ 'bit', 'bits',
444
+ 'byte',
445
+ 'kibibyte', 'kibibytes',
446
+ 'mebibyte', 'mebibytes',
447
+ 'gibibyte', 'gibibytes',
448
+ 'tebibyte', 'tebibytes',
449
+ 'pebibyte', 'pebibytes',
450
+ 'exbibyte', 'exbibytes',
451
+
452
+ 'mks', 'mksa', 'si',
453
+ ]
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (17.8 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/prefixes.cpython-311.pyc ADDED
Binary file (9.54 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/__pycache__/quantities.cpython-311.pyc ADDED
Binary file (7.38 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/definitions/__init__.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .unit_definitions import (
2
+ percent, percents,
3
+ permille,
4
+ rad, radian, radians,
5
+ deg, degree, degrees,
6
+ sr, steradian, steradians,
7
+ mil, angular_mil, angular_mils,
8
+ m, meter, meters,
9
+ kg, kilogram, kilograms,
10
+ s, second, seconds,
11
+ A, ampere, amperes,
12
+ K, kelvin, kelvins,
13
+ mol, mole, moles,
14
+ cd, candela, candelas,
15
+ g, gram, grams,
16
+ mg, milligram, milligrams,
17
+ ug, microgram, micrograms,
18
+ t, tonne, metric_ton,
19
+ newton, newtons, N,
20
+ joule, joules, J,
21
+ watt, watts, W,
22
+ pascal, pascals, Pa, pa,
23
+ hertz, hz, Hz,
24
+ coulomb, coulombs, C,
25
+ volt, volts, v, V,
26
+ ohm, ohms,
27
+ siemens, S, mho, mhos,
28
+ farad, farads, F,
29
+ henry, henrys, H,
30
+ tesla, teslas, T,
31
+ weber, webers, Wb, wb,
32
+ optical_power, dioptre, D,
33
+ lux, lx,
34
+ katal, kat,
35
+ gray, Gy,
36
+ becquerel, Bq,
37
+ km, kilometer, kilometers,
38
+ dm, decimeter, decimeters,
39
+ cm, centimeter, centimeters,
40
+ mm, millimeter, millimeters,
41
+ um, micrometer, micrometers, micron, microns,
42
+ nm, nanometer, nanometers,
43
+ pm, picometer, picometers,
44
+ ft, foot, feet,
45
+ inch, inches,
46
+ yd, yard, yards,
47
+ mi, mile, miles,
48
+ nmi, nautical_mile, nautical_miles,
49
+ ha, hectare,
50
+ l, L, liter, liters,
51
+ dl, dL, deciliter, deciliters,
52
+ cl, cL, centiliter, centiliters,
53
+ ml, mL, milliliter, milliliters,
54
+ ms, millisecond, milliseconds,
55
+ us, microsecond, microseconds,
56
+ ns, nanosecond, nanoseconds,
57
+ ps, picosecond, picoseconds,
58
+ minute, minutes,
59
+ h, hour, hours,
60
+ day, days,
61
+ anomalistic_year, anomalistic_years,
62
+ sidereal_year, sidereal_years,
63
+ tropical_year, tropical_years,
64
+ common_year, common_years,
65
+ julian_year, julian_years,
66
+ draconic_year, draconic_years,
67
+ gaussian_year, gaussian_years,
68
+ full_moon_cycle, full_moon_cycles,
69
+ year, years,
70
+ G, gravitational_constant,
71
+ c, speed_of_light,
72
+ elementary_charge,
73
+ hbar,
74
+ planck,
75
+ eV, electronvolt, electronvolts,
76
+ avogadro_number,
77
+ avogadro, avogadro_constant,
78
+ boltzmann, boltzmann_constant,
79
+ stefan, stefan_boltzmann_constant,
80
+ R, molar_gas_constant,
81
+ faraday_constant,
82
+ josephson_constant,
83
+ von_klitzing_constant,
84
+ Da, dalton, amu, amus, atomic_mass_unit, atomic_mass_constant,
85
+ me, electron_rest_mass,
86
+ gee, gees, acceleration_due_to_gravity,
87
+ u0, magnetic_constant, vacuum_permeability,
88
+ e0, electric_constant, vacuum_permittivity,
89
+ Z0, vacuum_impedance,
90
+ coulomb_constant, coulombs_constant, electric_force_constant,
91
+ atmosphere, atmospheres, atm,
92
+ kPa, kilopascal,
93
+ bar, bars,
94
+ pound, pounds,
95
+ psi,
96
+ dHg0,
97
+ mmHg, torr,
98
+ mmu, mmus, milli_mass_unit,
99
+ quart, quarts,
100
+ angstrom, angstroms,
101
+ ly, lightyear, lightyears,
102
+ au, astronomical_unit, astronomical_units,
103
+ planck_mass,
104
+ planck_time,
105
+ planck_temperature,
106
+ planck_length,
107
+ planck_charge,
108
+ planck_area,
109
+ planck_volume,
110
+ planck_momentum,
111
+ planck_energy,
112
+ planck_force,
113
+ planck_power,
114
+ planck_density,
115
+ planck_energy_density,
116
+ planck_intensity,
117
+ planck_angular_frequency,
118
+ planck_pressure,
119
+ planck_current,
120
+ planck_voltage,
121
+ planck_impedance,
122
+ planck_acceleration,
123
+ bit, bits,
124
+ byte,
125
+ kibibyte, kibibytes,
126
+ mebibyte, mebibytes,
127
+ gibibyte, gibibytes,
128
+ tebibyte, tebibytes,
129
+ pebibyte, pebibytes,
130
+ exbibyte, exbibytes,
131
+ curie, rutherford
132
+ )
133
+
134
+ __all__ = [
135
+ 'percent', 'percents',
136
+ 'permille',
137
+ 'rad', 'radian', 'radians',
138
+ 'deg', 'degree', 'degrees',
139
+ 'sr', 'steradian', 'steradians',
140
+ 'mil', 'angular_mil', 'angular_mils',
141
+ 'm', 'meter', 'meters',
142
+ 'kg', 'kilogram', 'kilograms',
143
+ 's', 'second', 'seconds',
144
+ 'A', 'ampere', 'amperes',
145
+ 'K', 'kelvin', 'kelvins',
146
+ 'mol', 'mole', 'moles',
147
+ 'cd', 'candela', 'candelas',
148
+ 'g', 'gram', 'grams',
149
+ 'mg', 'milligram', 'milligrams',
150
+ 'ug', 'microgram', 'micrograms',
151
+ 't', 'tonne', 'metric_ton',
152
+ 'newton', 'newtons', 'N',
153
+ 'joule', 'joules', 'J',
154
+ 'watt', 'watts', 'W',
155
+ 'pascal', 'pascals', 'Pa', 'pa',
156
+ 'hertz', 'hz', 'Hz',
157
+ 'coulomb', 'coulombs', 'C',
158
+ 'volt', 'volts', 'v', 'V',
159
+ 'ohm', 'ohms',
160
+ 'siemens', 'S', 'mho', 'mhos',
161
+ 'farad', 'farads', 'F',
162
+ 'henry', 'henrys', 'H',
163
+ 'tesla', 'teslas', 'T',
164
+ 'weber', 'webers', 'Wb', 'wb',
165
+ 'optical_power', 'dioptre', 'D',
166
+ 'lux', 'lx',
167
+ 'katal', 'kat',
168
+ 'gray', 'Gy',
169
+ 'becquerel', 'Bq',
170
+ 'km', 'kilometer', 'kilometers',
171
+ 'dm', 'decimeter', 'decimeters',
172
+ 'cm', 'centimeter', 'centimeters',
173
+ 'mm', 'millimeter', 'millimeters',
174
+ 'um', 'micrometer', 'micrometers', 'micron', 'microns',
175
+ 'nm', 'nanometer', 'nanometers',
176
+ 'pm', 'picometer', 'picometers',
177
+ 'ft', 'foot', 'feet',
178
+ 'inch', 'inches',
179
+ 'yd', 'yard', 'yards',
180
+ 'mi', 'mile', 'miles',
181
+ 'nmi', 'nautical_mile', 'nautical_miles',
182
+ 'ha', 'hectare',
183
+ 'l', 'L', 'liter', 'liters',
184
+ 'dl', 'dL', 'deciliter', 'deciliters',
185
+ 'cl', 'cL', 'centiliter', 'centiliters',
186
+ 'ml', 'mL', 'milliliter', 'milliliters',
187
+ 'ms', 'millisecond', 'milliseconds',
188
+ 'us', 'microsecond', 'microseconds',
189
+ 'ns', 'nanosecond', 'nanoseconds',
190
+ 'ps', 'picosecond', 'picoseconds',
191
+ 'minute', 'minutes',
192
+ 'h', 'hour', 'hours',
193
+ 'day', 'days',
194
+ 'anomalistic_year', 'anomalistic_years',
195
+ 'sidereal_year', 'sidereal_years',
196
+ 'tropical_year', 'tropical_years',
197
+ 'common_year', 'common_years',
198
+ 'julian_year', 'julian_years',
199
+ 'draconic_year', 'draconic_years',
200
+ 'gaussian_year', 'gaussian_years',
201
+ 'full_moon_cycle', 'full_moon_cycles',
202
+ 'year', 'years',
203
+ 'G', 'gravitational_constant',
204
+ 'c', 'speed_of_light',
205
+ 'elementary_charge',
206
+ 'hbar',
207
+ 'planck',
208
+ 'eV', 'electronvolt', 'electronvolts',
209
+ 'avogadro_number',
210
+ 'avogadro', 'avogadro_constant',
211
+ 'boltzmann', 'boltzmann_constant',
212
+ 'stefan', 'stefan_boltzmann_constant',
213
+ 'R', 'molar_gas_constant',
214
+ 'faraday_constant',
215
+ 'josephson_constant',
216
+ 'von_klitzing_constant',
217
+ 'Da', 'dalton', 'amu', 'amus', 'atomic_mass_unit', 'atomic_mass_constant',
218
+ 'me', 'electron_rest_mass',
219
+ 'gee', 'gees', 'acceleration_due_to_gravity',
220
+ 'u0', 'magnetic_constant', 'vacuum_permeability',
221
+ 'e0', 'electric_constant', 'vacuum_permittivity',
222
+ 'Z0', 'vacuum_impedance',
223
+ 'coulomb_constant', 'coulombs_constant', 'electric_force_constant',
224
+ 'atmosphere', 'atmospheres', 'atm',
225
+ 'kPa', 'kilopascal',
226
+ 'bar', 'bars',
227
+ 'pound', 'pounds',
228
+ 'psi',
229
+ 'dHg0',
230
+ 'mmHg', 'torr',
231
+ 'mmu', 'mmus', 'milli_mass_unit',
232
+ 'quart', 'quarts',
233
+ 'angstrom', 'angstroms',
234
+ 'ly', 'lightyear', 'lightyears',
235
+ 'au', 'astronomical_unit', 'astronomical_units',
236
+ 'planck_mass',
237
+ 'planck_time',
238
+ 'planck_temperature',
239
+ 'planck_length',
240
+ 'planck_charge',
241
+ 'planck_area',
242
+ 'planck_volume',
243
+ 'planck_momentum',
244
+ 'planck_energy',
245
+ 'planck_force',
246
+ 'planck_power',
247
+ 'planck_density',
248
+ 'planck_energy_density',
249
+ 'planck_intensity',
250
+ 'planck_angular_frequency',
251
+ 'planck_pressure',
252
+ 'planck_current',
253
+ 'planck_voltage',
254
+ 'planck_impedance',
255
+ 'planck_acceleration',
256
+ 'bit', 'bits',
257
+ 'byte',
258
+ 'kibibyte', 'kibibytes',
259
+ 'mebibyte', 'mebibytes',
260
+ 'gibibyte', 'gibibytes',
261
+ 'tebibyte', 'tebibytes',
262
+ 'pebibyte', 'pebibytes',
263
+ 'exbibyte', 'exbibytes',
264
+ 'curie', 'rutherford',
265
+ ]
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/dimensions.py ADDED
@@ -0,0 +1,590 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Definition of physical dimensions.
3
+
4
+ Unit systems will be constructed on top of these dimensions.
5
+
6
+ Most of the examples in the doc use MKS system and are presented from the
7
+ computer point of view: from a human point, adding length to time is not legal
8
+ in MKS but it is in natural system; for a computer in natural system there is
9
+ no time dimension (but a velocity dimension instead) - in the basis - so the
10
+ question of adding time to length has no meaning.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import collections
16
+ from functools import reduce
17
+
18
+ from sympy.core.basic import Basic
19
+ from sympy.core.containers import (Dict, Tuple)
20
+ from sympy.core.singleton import S
21
+ from sympy.core.sorting import default_sort_key
22
+ from sympy.core.symbol import Symbol
23
+ from sympy.core.sympify import sympify
24
+ from sympy.matrices.dense import Matrix
25
+ from sympy.functions.elementary.trigonometric import TrigonometricFunction
26
+ from sympy.core.expr import Expr
27
+ from sympy.core.power import Pow
28
+
29
+
30
+ class _QuantityMapper:
31
+
32
+ _quantity_scale_factors_global: dict[Expr, Expr] = {}
33
+ _quantity_dimensional_equivalence_map_global: dict[Expr, Expr] = {}
34
+ _quantity_dimension_global: dict[Expr, Expr] = {}
35
+
36
+ def __init__(self, *args, **kwargs):
37
+ self._quantity_dimension_map = {}
38
+ self._quantity_scale_factors = {}
39
+
40
+ def set_quantity_dimension(self, quantity, dimension):
41
+ """
42
+ Set the dimension for the quantity in a unit system.
43
+
44
+ If this relation is valid in every unit system, use
45
+ ``quantity.set_global_dimension(dimension)`` instead.
46
+ """
47
+ from sympy.physics.units import Quantity
48
+ dimension = sympify(dimension)
49
+ if not isinstance(dimension, Dimension):
50
+ if dimension == 1:
51
+ dimension = Dimension(1)
52
+ else:
53
+ raise ValueError("expected dimension or 1")
54
+ elif isinstance(dimension, Quantity):
55
+ dimension = self.get_quantity_dimension(dimension)
56
+ self._quantity_dimension_map[quantity] = dimension
57
+
58
+ def set_quantity_scale_factor(self, quantity, scale_factor):
59
+ """
60
+ Set the scale factor of a quantity relative to another quantity.
61
+
62
+ It should be used only once per quantity to just one other quantity,
63
+ the algorithm will then be able to compute the scale factors to all
64
+ other quantities.
65
+
66
+ In case the scale factor is valid in every unit system, please use
67
+ ``quantity.set_global_relative_scale_factor(scale_factor)`` instead.
68
+ """
69
+ from sympy.physics.units import Quantity
70
+ from sympy.physics.units.prefixes import Prefix
71
+ scale_factor = sympify(scale_factor)
72
+ # replace all prefixes by their ratio to canonical units:
73
+ scale_factor = scale_factor.replace(
74
+ lambda x: isinstance(x, Prefix),
75
+ lambda x: x.scale_factor
76
+ )
77
+ # replace all quantities by their ratio to canonical units:
78
+ scale_factor = scale_factor.replace(
79
+ lambda x: isinstance(x, Quantity),
80
+ lambda x: self.get_quantity_scale_factor(x)
81
+ )
82
+ self._quantity_scale_factors[quantity] = scale_factor
83
+
84
+ def get_quantity_dimension(self, unit):
85
+ from sympy.physics.units import Quantity
86
+ # First look-up the local dimension map, then the global one:
87
+ if unit in self._quantity_dimension_map:
88
+ return self._quantity_dimension_map[unit]
89
+ if unit in self._quantity_dimension_global:
90
+ return self._quantity_dimension_global[unit]
91
+ if unit in self._quantity_dimensional_equivalence_map_global:
92
+ dep_unit = self._quantity_dimensional_equivalence_map_global[unit]
93
+ if isinstance(dep_unit, Quantity):
94
+ return self.get_quantity_dimension(dep_unit)
95
+ else:
96
+ return Dimension(self.get_dimensional_expr(dep_unit))
97
+ if isinstance(unit, Quantity):
98
+ return Dimension(unit.name)
99
+ else:
100
+ return Dimension(1)
101
+
102
+ def get_quantity_scale_factor(self, unit):
103
+ if unit in self._quantity_scale_factors:
104
+ return self._quantity_scale_factors[unit]
105
+ if unit in self._quantity_scale_factors_global:
106
+ mul_factor, other_unit = self._quantity_scale_factors_global[unit]
107
+ return mul_factor*self.get_quantity_scale_factor(other_unit)
108
+ return S.One
109
+
110
+
111
+ class Dimension(Expr):
112
+ """
113
+ This class represent the dimension of a physical quantities.
114
+
115
+ The ``Dimension`` constructor takes as parameters a name and an optional
116
+ symbol.
117
+
118
+ For example, in classical mechanics we know that time is different from
119
+ temperature and dimensions make this difference (but they do not provide
120
+ any measure of these quantites.
121
+
122
+ >>> from sympy.physics.units import Dimension
123
+ >>> length = Dimension('length')
124
+ >>> length
125
+ Dimension(length)
126
+ >>> time = Dimension('time')
127
+ >>> time
128
+ Dimension(time)
129
+
130
+ Dimensions can be composed using multiplication, division and
131
+ exponentiation (by a number) to give new dimensions. Addition and
132
+ subtraction is defined only when the two objects are the same dimension.
133
+
134
+ >>> velocity = length / time
135
+ >>> velocity
136
+ Dimension(length/time)
137
+
138
+ It is possible to use a dimension system object to get the dimensionsal
139
+ dependencies of a dimension, for example the dimension system used by the
140
+ SI units convention can be used:
141
+
142
+ >>> from sympy.physics.units.systems.si import dimsys_SI
143
+ >>> dimsys_SI.get_dimensional_dependencies(velocity)
144
+ {Dimension(length, L): 1, Dimension(time, T): -1}
145
+ >>> length + length
146
+ Dimension(length)
147
+ >>> l2 = length**2
148
+ >>> l2
149
+ Dimension(length**2)
150
+ >>> dimsys_SI.get_dimensional_dependencies(l2)
151
+ {Dimension(length, L): 2}
152
+
153
+ """
154
+
155
+ _op_priority = 13.0
156
+
157
+ # XXX: This doesn't seem to be used anywhere...
158
+ _dimensional_dependencies = {} # type: ignore
159
+
160
+ is_commutative = True
161
+ is_number = False
162
+ # make sqrt(M**2) --> M
163
+ is_positive = True
164
+ is_real = True
165
+
166
+ def __new__(cls, name, symbol=None):
167
+
168
+ if isinstance(name, str):
169
+ name = Symbol(name)
170
+ else:
171
+ name = sympify(name)
172
+
173
+ if not isinstance(name, Expr):
174
+ raise TypeError("Dimension name needs to be a valid math expression")
175
+
176
+ if isinstance(symbol, str):
177
+ symbol = Symbol(symbol)
178
+ elif symbol is not None:
179
+ assert isinstance(symbol, Symbol)
180
+
181
+ obj = Expr.__new__(cls, name)
182
+
183
+ obj._name = name
184
+ obj._symbol = symbol
185
+ return obj
186
+
187
+ @property
188
+ def name(self):
189
+ return self._name
190
+
191
+ @property
192
+ def symbol(self):
193
+ return self._symbol
194
+
195
+ def __str__(self):
196
+ """
197
+ Display the string representation of the dimension.
198
+ """
199
+ if self.symbol is None:
200
+ return "Dimension(%s)" % (self.name)
201
+ else:
202
+ return "Dimension(%s, %s)" % (self.name, self.symbol)
203
+
204
+ def __repr__(self):
205
+ return self.__str__()
206
+
207
+ def __neg__(self):
208
+ return self
209
+
210
+ def __add__(self, other):
211
+ from sympy.physics.units.quantities import Quantity
212
+ other = sympify(other)
213
+ if isinstance(other, Basic):
214
+ if other.has(Quantity):
215
+ raise TypeError("cannot sum dimension and quantity")
216
+ if isinstance(other, Dimension) and self == other:
217
+ return self
218
+ return super().__add__(other)
219
+ return self
220
+
221
+ def __radd__(self, other):
222
+ return self.__add__(other)
223
+
224
+ def __sub__(self, other):
225
+ # there is no notion of ordering (or magnitude) among dimension,
226
+ # subtraction is equivalent to addition when the operation is legal
227
+ return self + other
228
+
229
+ def __rsub__(self, other):
230
+ # there is no notion of ordering (or magnitude) among dimension,
231
+ # subtraction is equivalent to addition when the operation is legal
232
+ return self + other
233
+
234
+ def __pow__(self, other):
235
+ return self._eval_power(other)
236
+
237
+ def _eval_power(self, other):
238
+ other = sympify(other)
239
+ return Dimension(self.name**other)
240
+
241
+ def __mul__(self, other):
242
+ from sympy.physics.units.quantities import Quantity
243
+ if isinstance(other, Basic):
244
+ if other.has(Quantity):
245
+ raise TypeError("cannot sum dimension and quantity")
246
+ if isinstance(other, Dimension):
247
+ return Dimension(self.name*other.name)
248
+ if not other.free_symbols: # other.is_number cannot be used
249
+ return self
250
+ return super().__mul__(other)
251
+ return self
252
+
253
+ def __rmul__(self, other):
254
+ return self.__mul__(other)
255
+
256
+ def __truediv__(self, other):
257
+ return self*Pow(other, -1)
258
+
259
+ def __rtruediv__(self, other):
260
+ return other * pow(self, -1)
261
+
262
+ @classmethod
263
+ def _from_dimensional_dependencies(cls, dependencies):
264
+ return reduce(lambda x, y: x * y, (
265
+ d**e for d, e in dependencies.items()
266
+ ), 1)
267
+
268
+ def has_integer_powers(self, dim_sys):
269
+ """
270
+ Check if the dimension object has only integer powers.
271
+
272
+ All the dimension powers should be integers, but rational powers may
273
+ appear in intermediate steps. This method may be used to check that the
274
+ final result is well-defined.
275
+ """
276
+
277
+ return all(dpow.is_Integer for dpow in dim_sys.get_dimensional_dependencies(self).values())
278
+
279
+
280
+ # Create dimensions according to the base units in MKSA.
281
+ # For other unit systems, they can be derived by transforming the base
282
+ # dimensional dependency dictionary.
283
+
284
+
285
+ class DimensionSystem(Basic, _QuantityMapper):
286
+ r"""
287
+ DimensionSystem represents a coherent set of dimensions.
288
+
289
+ The constructor takes three parameters:
290
+
291
+ - base dimensions;
292
+ - derived dimensions: these are defined in terms of the base dimensions
293
+ (for example velocity is defined from the division of length by time);
294
+ - dependency of dimensions: how the derived dimensions depend
295
+ on the base dimensions.
296
+
297
+ Optionally either the ``derived_dims`` or the ``dimensional_dependencies``
298
+ may be omitted.
299
+ """
300
+
301
+ def __new__(cls, base_dims, derived_dims=(), dimensional_dependencies={}):
302
+ dimensional_dependencies = dict(dimensional_dependencies)
303
+
304
+ def parse_dim(dim):
305
+ if isinstance(dim, str):
306
+ dim = Dimension(Symbol(dim))
307
+ elif isinstance(dim, Dimension):
308
+ pass
309
+ elif isinstance(dim, Symbol):
310
+ dim = Dimension(dim)
311
+ else:
312
+ raise TypeError("%s wrong type" % dim)
313
+ return dim
314
+
315
+ base_dims = [parse_dim(i) for i in base_dims]
316
+ derived_dims = [parse_dim(i) for i in derived_dims]
317
+
318
+ for dim in base_dims:
319
+ if (dim in dimensional_dependencies
320
+ and (len(dimensional_dependencies[dim]) != 1 or
321
+ dimensional_dependencies[dim].get(dim, None) != 1)):
322
+ raise IndexError("Repeated value in base dimensions")
323
+ dimensional_dependencies[dim] = Dict({dim: 1})
324
+
325
+ def parse_dim_name(dim):
326
+ if isinstance(dim, Dimension):
327
+ return dim
328
+ elif isinstance(dim, str):
329
+ return Dimension(Symbol(dim))
330
+ elif isinstance(dim, Symbol):
331
+ return Dimension(dim)
332
+ else:
333
+ raise TypeError("unrecognized type %s for %s" % (type(dim), dim))
334
+
335
+ for dim in dimensional_dependencies.keys():
336
+ dim = parse_dim(dim)
337
+ if (dim not in derived_dims) and (dim not in base_dims):
338
+ derived_dims.append(dim)
339
+
340
+ def parse_dict(d):
341
+ return Dict({parse_dim_name(i): j for i, j in d.items()})
342
+
343
+ # Make sure everything is a SymPy type:
344
+ dimensional_dependencies = {parse_dim_name(i): parse_dict(j) for i, j in
345
+ dimensional_dependencies.items()}
346
+
347
+ for dim in derived_dims:
348
+ if dim in base_dims:
349
+ raise ValueError("Dimension %s both in base and derived" % dim)
350
+ if dim not in dimensional_dependencies:
351
+ # TODO: should this raise a warning?
352
+ dimensional_dependencies[dim] = Dict({dim: 1})
353
+
354
+ base_dims.sort(key=default_sort_key)
355
+ derived_dims.sort(key=default_sort_key)
356
+
357
+ base_dims = Tuple(*base_dims)
358
+ derived_dims = Tuple(*derived_dims)
359
+ dimensional_dependencies = Dict({i: Dict(j) for i, j in dimensional_dependencies.items()})
360
+ obj = Basic.__new__(cls, base_dims, derived_dims, dimensional_dependencies)
361
+ return obj
362
+
363
+ @property
364
+ def base_dims(self):
365
+ return self.args[0]
366
+
367
+ @property
368
+ def derived_dims(self):
369
+ return self.args[1]
370
+
371
+ @property
372
+ def dimensional_dependencies(self):
373
+ return self.args[2]
374
+
375
+ def _get_dimensional_dependencies_for_name(self, dimension):
376
+ if isinstance(dimension, str):
377
+ dimension = Dimension(Symbol(dimension))
378
+ elif not isinstance(dimension, Dimension):
379
+ dimension = Dimension(dimension)
380
+
381
+ if dimension.name.is_Symbol:
382
+ # Dimensions not included in the dependencies are considered
383
+ # as base dimensions:
384
+ return dict(self.dimensional_dependencies.get(dimension, {dimension: 1}))
385
+
386
+ if dimension.name.is_number or dimension.name.is_NumberSymbol:
387
+ return {}
388
+
389
+ get_for_name = self._get_dimensional_dependencies_for_name
390
+
391
+ if dimension.name.is_Mul:
392
+ ret = collections.defaultdict(int)
393
+ dicts = [get_for_name(i) for i in dimension.name.args]
394
+ for d in dicts:
395
+ for k, v in d.items():
396
+ ret[k] += v
397
+ return {k: v for (k, v) in ret.items() if v != 0}
398
+
399
+ if dimension.name.is_Add:
400
+ dicts = [get_for_name(i) for i in dimension.name.args]
401
+ if all(d == dicts[0] for d in dicts[1:]):
402
+ return dicts[0]
403
+ raise TypeError("Only equivalent dimensions can be added or subtracted.")
404
+
405
+ if dimension.name.is_Pow:
406
+ dim_base = get_for_name(dimension.name.base)
407
+ dim_exp = get_for_name(dimension.name.exp)
408
+ if dim_exp == {} or dimension.name.exp.is_Symbol:
409
+ return {k: v * dimension.name.exp for (k, v) in dim_base.items()}
410
+ else:
411
+ raise TypeError("The exponent for the power operator must be a Symbol or dimensionless.")
412
+
413
+ if dimension.name.is_Function:
414
+ args = (Dimension._from_dimensional_dependencies(
415
+ get_for_name(arg)) for arg in dimension.name.args)
416
+ result = dimension.name.func(*args)
417
+
418
+ dicts = [get_for_name(i) for i in dimension.name.args]
419
+
420
+ if isinstance(result, Dimension):
421
+ return self.get_dimensional_dependencies(result)
422
+ elif result.func == dimension.name.func:
423
+ if isinstance(dimension.name, TrigonometricFunction):
424
+ if dicts[0] in ({}, {Dimension('angle'): 1}):
425
+ return {}
426
+ else:
427
+ raise TypeError("The input argument for the function {} must be dimensionless or have dimensions of angle.".format(dimension.func))
428
+ else:
429
+ if all(item == {} for item in dicts):
430
+ return {}
431
+ else:
432
+ raise TypeError("The input arguments for the function {} must be dimensionless.".format(dimension.func))
433
+ else:
434
+ return get_for_name(result)
435
+
436
+ raise TypeError("Type {} not implemented for get_dimensional_dependencies".format(type(dimension.name)))
437
+
438
+ def get_dimensional_dependencies(self, name, mark_dimensionless=False):
439
+ dimdep = self._get_dimensional_dependencies_for_name(name)
440
+ if mark_dimensionless and dimdep == {}:
441
+ return {Dimension(1): 1}
442
+ return dict(dimdep.items())
443
+
444
+ def equivalent_dims(self, dim1, dim2):
445
+ deps1 = self.get_dimensional_dependencies(dim1)
446
+ deps2 = self.get_dimensional_dependencies(dim2)
447
+ return deps1 == deps2
448
+
449
+ def extend(self, new_base_dims, new_derived_dims=(), new_dim_deps=None):
450
+ deps = dict(self.dimensional_dependencies)
451
+ if new_dim_deps:
452
+ deps.update(new_dim_deps)
453
+
454
+ new_dim_sys = DimensionSystem(
455
+ tuple(self.base_dims) + tuple(new_base_dims),
456
+ tuple(self.derived_dims) + tuple(new_derived_dims),
457
+ deps
458
+ )
459
+ new_dim_sys._quantity_dimension_map.update(self._quantity_dimension_map)
460
+ new_dim_sys._quantity_scale_factors.update(self._quantity_scale_factors)
461
+ return new_dim_sys
462
+
463
+ def is_dimensionless(self, dimension):
464
+ """
465
+ Check if the dimension object really has a dimension.
466
+
467
+ A dimension should have at least one component with non-zero power.
468
+ """
469
+ if dimension.name == 1:
470
+ return True
471
+ return self.get_dimensional_dependencies(dimension) == {}
472
+
473
+ @property
474
+ def list_can_dims(self):
475
+ """
476
+ Useless method, kept for compatibility with previous versions.
477
+
478
+ DO NOT USE.
479
+
480
+ List all canonical dimension names.
481
+ """
482
+ dimset = set()
483
+ for i in self.base_dims:
484
+ dimset.update(set(self.get_dimensional_dependencies(i).keys()))
485
+ return tuple(sorted(dimset, key=str))
486
+
487
+ @property
488
+ def inv_can_transf_matrix(self):
489
+ """
490
+ Useless method, kept for compatibility with previous versions.
491
+
492
+ DO NOT USE.
493
+
494
+ Compute the inverse transformation matrix from the base to the
495
+ canonical dimension basis.
496
+
497
+ It corresponds to the matrix where columns are the vector of base
498
+ dimensions in canonical basis.
499
+
500
+ This matrix will almost never be used because dimensions are always
501
+ defined with respect to the canonical basis, so no work has to be done
502
+ to get them in this basis. Nonetheless if this matrix is not square
503
+ (or not invertible) it means that we have chosen a bad basis.
504
+ """
505
+ matrix = reduce(lambda x, y: x.row_join(y),
506
+ [self.dim_can_vector(d) for d in self.base_dims])
507
+ return matrix
508
+
509
+ @property
510
+ def can_transf_matrix(self):
511
+ """
512
+ Useless method, kept for compatibility with previous versions.
513
+
514
+ DO NOT USE.
515
+
516
+ Return the canonical transformation matrix from the canonical to the
517
+ base dimension basis.
518
+
519
+ It is the inverse of the matrix computed with inv_can_transf_matrix().
520
+ """
521
+
522
+ #TODO: the inversion will fail if the system is inconsistent, for
523
+ # example if the matrix is not a square
524
+ return reduce(lambda x, y: x.row_join(y),
525
+ [self.dim_can_vector(d) for d in sorted(self.base_dims, key=str)]
526
+ ).inv()
527
+
528
+ def dim_can_vector(self, dim):
529
+ """
530
+ Useless method, kept for compatibility with previous versions.
531
+
532
+ DO NOT USE.
533
+
534
+ Dimensional representation in terms of the canonical base dimensions.
535
+ """
536
+
537
+ vec = []
538
+ for d in self.list_can_dims:
539
+ vec.append(self.get_dimensional_dependencies(dim).get(d, 0))
540
+ return Matrix(vec)
541
+
542
+ def dim_vector(self, dim):
543
+ """
544
+ Useless method, kept for compatibility with previous versions.
545
+
546
+ DO NOT USE.
547
+
548
+
549
+ Vector representation in terms of the base dimensions.
550
+ """
551
+ return self.can_transf_matrix * Matrix(self.dim_can_vector(dim))
552
+
553
+ def print_dim_base(self, dim):
554
+ """
555
+ Give the string expression of a dimension in term of the basis symbols.
556
+ """
557
+ dims = self.dim_vector(dim)
558
+ symbols = [i.symbol if i.symbol is not None else i.name for i in self.base_dims]
559
+ res = S.One
560
+ for (s, p) in zip(symbols, dims):
561
+ res *= s**p
562
+ return res
563
+
564
+ @property
565
+ def dim(self):
566
+ """
567
+ Useless method, kept for compatibility with previous versions.
568
+
569
+ DO NOT USE.
570
+
571
+ Give the dimension of the system.
572
+
573
+ That is return the number of dimensions forming the basis.
574
+ """
575
+ return len(self.base_dims)
576
+
577
+ @property
578
+ def is_consistent(self):
579
+ """
580
+ Useless method, kept for compatibility with previous versions.
581
+
582
+ DO NOT USE.
583
+
584
+ Check if the system is well defined.
585
+ """
586
+
587
+ # not enough or too many base dimensions compared to independent
588
+ # dimensions
589
+ # in vector language: the set of vectors do not form a basis
590
+ return self.inv_can_transf_matrix.is_square
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/quantities.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Physical quantities.
3
+ """
4
+
5
+ from sympy.core.expr import AtomicExpr
6
+ from sympy.core.symbol import Symbol
7
+ from sympy.core.sympify import sympify
8
+ from sympy.physics.units.dimensions import _QuantityMapper
9
+ from sympy.physics.units.prefixes import Prefix
10
+
11
+
12
+ class Quantity(AtomicExpr):
13
+ """
14
+ Physical quantity: can be a unit of measure, a constant or a generic quantity.
15
+ """
16
+
17
+ is_commutative = True
18
+ is_real = True
19
+ is_number = False
20
+ is_nonzero = True
21
+ is_physical_constant = False
22
+ _diff_wrt = True
23
+
24
+ def __new__(cls, name, abbrev=None,
25
+ latex_repr=None, pretty_unicode_repr=None,
26
+ pretty_ascii_repr=None, mathml_presentation_repr=None,
27
+ is_prefixed=False,
28
+ **assumptions):
29
+
30
+ if not isinstance(name, Symbol):
31
+ name = Symbol(name)
32
+
33
+ if abbrev is None:
34
+ abbrev = name
35
+ elif isinstance(abbrev, str):
36
+ abbrev = Symbol(abbrev)
37
+
38
+ # HACK: These are here purely for type checking. They actually get assigned below.
39
+ cls._is_prefixed = is_prefixed
40
+
41
+ obj = AtomicExpr.__new__(cls, name, abbrev)
42
+ obj._name = name
43
+ obj._abbrev = abbrev
44
+ obj._latex_repr = latex_repr
45
+ obj._unicode_repr = pretty_unicode_repr
46
+ obj._ascii_repr = pretty_ascii_repr
47
+ obj._mathml_repr = mathml_presentation_repr
48
+ obj._is_prefixed = is_prefixed
49
+ return obj
50
+
51
+ def set_global_dimension(self, dimension):
52
+ _QuantityMapper._quantity_dimension_global[self] = dimension
53
+
54
+ def set_global_relative_scale_factor(self, scale_factor, reference_quantity):
55
+ """
56
+ Setting a scale factor that is valid across all unit system.
57
+ """
58
+ from sympy.physics.units import UnitSystem
59
+ scale_factor = sympify(scale_factor)
60
+ if isinstance(scale_factor, Prefix):
61
+ self._is_prefixed = True
62
+ # replace all prefixes by their ratio to canonical units:
63
+ scale_factor = scale_factor.replace(
64
+ lambda x: isinstance(x, Prefix),
65
+ lambda x: x.scale_factor
66
+ )
67
+ scale_factor = sympify(scale_factor)
68
+ UnitSystem._quantity_scale_factors_global[self] = (scale_factor, reference_quantity)
69
+ UnitSystem._quantity_dimensional_equivalence_map_global[self] = reference_quantity
70
+
71
+ @property
72
+ def name(self):
73
+ return self._name
74
+
75
+ @property
76
+ def dimension(self):
77
+ from sympy.physics.units import UnitSystem
78
+ unit_system = UnitSystem.get_default_unit_system()
79
+ return unit_system.get_quantity_dimension(self)
80
+
81
+ @property
82
+ def abbrev(self):
83
+ """
84
+ Symbol representing the unit name.
85
+
86
+ Prepend the abbreviation with the prefix symbol if it is defines.
87
+ """
88
+ return self._abbrev
89
+
90
+ @property
91
+ def scale_factor(self):
92
+ """
93
+ Overall magnitude of the quantity as compared to the canonical units.
94
+ """
95
+ from sympy.physics.units import UnitSystem
96
+ unit_system = UnitSystem.get_default_unit_system()
97
+ return unit_system.get_quantity_scale_factor(self)
98
+
99
+ def _eval_is_positive(self):
100
+ return True
101
+
102
+ def _eval_is_constant(self):
103
+ return True
104
+
105
+ def _eval_Abs(self):
106
+ return self
107
+
108
+ def _eval_subs(self, old, new):
109
+ if isinstance(new, Quantity) and self != old:
110
+ return self
111
+
112
+ def _latex(self, printer):
113
+ if self._latex_repr:
114
+ return self._latex_repr
115
+ else:
116
+ return r'\text{{{}}}'.format(self.args[1] \
117
+ if len(self.args) >= 2 else self.args[0])
118
+
119
+ def convert_to(self, other, unit_system="SI"):
120
+ """
121
+ Convert the quantity to another quantity of same dimensions.
122
+
123
+ Examples
124
+ ========
125
+
126
+ >>> from sympy.physics.units import speed_of_light, meter, second
127
+ >>> speed_of_light
128
+ speed_of_light
129
+ >>> speed_of_light.convert_to(meter/second)
130
+ 299792458*meter/second
131
+
132
+ >>> from sympy.physics.units import liter
133
+ >>> liter.convert_to(meter**3)
134
+ meter**3/1000
135
+ """
136
+ from .util import convert_to
137
+ return convert_to(self, other, unit_system)
138
+
139
+ @property
140
+ def free_symbols(self):
141
+ """Return free symbols from quantity."""
142
+ return set()
143
+
144
+ @property
145
+ def is_prefixed(self):
146
+ """Whether or not the quantity is prefixed. Eg. `kilogram` is prefixed, but `gram` is not."""
147
+ return self._is_prefixed
148
+
149
+ class PhysicalConstant(Quantity):
150
+ """Represents a physical constant, eg. `speed_of_light` or `avogadro_constant`."""
151
+
152
+ is_physical_constant = True
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (582 Bytes). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/cgs.cpython-311.pyc ADDED
Binary file (4.9 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/length_weight_time.cpython-311.pyc ADDED
Binary file (8.33 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/mks.cpython-311.pyc ADDED
Binary file (2.17 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/mksa.cpython-311.pyc ADDED
Binary file (2.49 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/natural.cpython-311.pyc ADDED
Binary file (1.51 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/__pycache__/si.cpython-311.pyc ADDED
Binary file (17.3 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/cgs.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.singleton import S
2
+ from sympy.functions.elementary.miscellaneous import sqrt
3
+ from sympy.physics.units import UnitSystem, centimeter, gram, second, coulomb, charge, speed_of_light, current, mass, \
4
+ length, voltage, magnetic_density, magnetic_flux
5
+ from sympy.physics.units.definitions import coulombs_constant
6
+ from sympy.physics.units.definitions.unit_definitions import statcoulomb, statampere, statvolt, volt, tesla, gauss, \
7
+ weber, maxwell, debye, oersted, ohm, farad, henry, erg, ampere, coulomb_constant
8
+ from sympy.physics.units.systems.mks import dimsys_length_weight_time
9
+
10
+ One = S.One
11
+
12
+ dimsys_cgs = dimsys_length_weight_time.extend(
13
+ [],
14
+ new_dim_deps={
15
+ # Dimensional dependencies for derived dimensions
16
+ "impedance": {"time": 1, "length": -1},
17
+ "conductance": {"time": -1, "length": 1},
18
+ "capacitance": {"length": 1},
19
+ "inductance": {"time": 2, "length": -1},
20
+ "charge": {"mass": S.Half, "length": S(3)/2, "time": -1},
21
+ "current": {"mass": One/2, "length": 3*One/2, "time": -2},
22
+ "voltage": {"length": -One/2, "mass": One/2, "time": -1},
23
+ "magnetic_density": {"length": -One/2, "mass": One/2, "time": -1},
24
+ "magnetic_flux": {"length": 3*One/2, "mass": One/2, "time": -1},
25
+ }
26
+ )
27
+
28
+ cgs_gauss = UnitSystem(
29
+ base_units=[centimeter, gram, second],
30
+ units=[],
31
+ name="cgs_gauss",
32
+ dimension_system=dimsys_cgs)
33
+
34
+
35
+ cgs_gauss.set_quantity_scale_factor(coulombs_constant, 1)
36
+
37
+ cgs_gauss.set_quantity_dimension(statcoulomb, charge)
38
+ cgs_gauss.set_quantity_scale_factor(statcoulomb, centimeter**(S(3)/2)*gram**(S.Half)/second)
39
+
40
+ cgs_gauss.set_quantity_dimension(coulomb, charge)
41
+
42
+ cgs_gauss.set_quantity_dimension(statampere, current)
43
+ cgs_gauss.set_quantity_scale_factor(statampere, statcoulomb/second)
44
+
45
+ cgs_gauss.set_quantity_dimension(statvolt, voltage)
46
+ cgs_gauss.set_quantity_scale_factor(statvolt, erg/statcoulomb)
47
+
48
+ cgs_gauss.set_quantity_dimension(volt, voltage)
49
+
50
+ cgs_gauss.set_quantity_dimension(gauss, magnetic_density)
51
+ cgs_gauss.set_quantity_scale_factor(gauss, sqrt(gram/centimeter)/second)
52
+
53
+ cgs_gauss.set_quantity_dimension(tesla, magnetic_density)
54
+
55
+ cgs_gauss.set_quantity_dimension(maxwell, magnetic_flux)
56
+ cgs_gauss.set_quantity_scale_factor(maxwell, sqrt(centimeter**3*gram)/second)
57
+
58
+ # SI units expressed in CGS-gaussian units:
59
+ cgs_gauss.set_quantity_scale_factor(coulomb, 10*speed_of_light*statcoulomb)
60
+ cgs_gauss.set_quantity_scale_factor(ampere, 10*speed_of_light*statcoulomb/second)
61
+ cgs_gauss.set_quantity_scale_factor(volt, 10**6/speed_of_light*statvolt)
62
+ cgs_gauss.set_quantity_scale_factor(weber, 10**8*maxwell)
63
+ cgs_gauss.set_quantity_scale_factor(tesla, 10**4*gauss)
64
+ cgs_gauss.set_quantity_scale_factor(debye, One/10**18*statcoulomb*centimeter)
65
+ cgs_gauss.set_quantity_scale_factor(oersted, sqrt(gram/centimeter)/second)
66
+ cgs_gauss.set_quantity_scale_factor(ohm, 10**5/speed_of_light**2*second/centimeter)
67
+ cgs_gauss.set_quantity_scale_factor(farad, One/10**5*speed_of_light**2*centimeter)
68
+ cgs_gauss.set_quantity_scale_factor(henry, 10**5/speed_of_light**2/centimeter*second**2)
69
+
70
+ # Coulomb's constant:
71
+ cgs_gauss.set_quantity_dimension(coulomb_constant, 1)
72
+ cgs_gauss.set_quantity_scale_factor(coulomb_constant, 1)
73
+
74
+ __all__ = [
75
+ 'ohm', 'tesla', 'maxwell', 'speed_of_light', 'volt', 'second', 'voltage',
76
+ 'debye', 'dimsys_length_weight_time', 'centimeter', 'coulomb_constant',
77
+ 'farad', 'sqrt', 'UnitSystem', 'current', 'charge', 'weber', 'gram',
78
+ 'statcoulomb', 'gauss', 'S', 'statvolt', 'oersted', 'statampere',
79
+ 'dimsys_cgs', 'coulomb', 'magnetic_density', 'magnetic_flux', 'One',
80
+ 'length', 'erg', 'mass', 'coulombs_constant', 'henry', 'ampere',
81
+ 'cgs_gauss',
82
+ ]
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/length_weight_time.py ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.singleton import S
2
+
3
+ from sympy.core.numbers import pi
4
+
5
+ from sympy.physics.units import DimensionSystem, hertz, kilogram
6
+ from sympy.physics.units.definitions import (
7
+ G, Hz, J, N, Pa, W, c, g, kg, m, s, meter, gram, second, newton,
8
+ joule, watt, pascal)
9
+ from sympy.physics.units.definitions.dimension_definitions import (
10
+ acceleration, action, energy, force, frequency, momentum,
11
+ power, pressure, velocity, length, mass, time)
12
+ from sympy.physics.units.prefixes import PREFIXES, prefix_unit
13
+ from sympy.physics.units.prefixes import (
14
+ kibi, mebi, gibi, tebi, pebi, exbi
15
+ )
16
+ from sympy.physics.units.definitions import (
17
+ cd, K, coulomb, volt, ohm, siemens, farad, henry, tesla, weber, dioptre,
18
+ lux, katal, gray, becquerel, inch, hectare, liter, julian_year,
19
+ gravitational_constant, speed_of_light, elementary_charge, planck, hbar,
20
+ electronvolt, avogadro_number, avogadro_constant, boltzmann_constant,
21
+ stefan_boltzmann_constant, atomic_mass_constant, molar_gas_constant,
22
+ faraday_constant, josephson_constant, von_klitzing_constant,
23
+ acceleration_due_to_gravity, magnetic_constant, vacuum_permittivity,
24
+ vacuum_impedance, coulomb_constant, atmosphere, bar, pound, psi, mmHg,
25
+ milli_mass_unit, quart, lightyear, astronomical_unit, planck_mass,
26
+ planck_time, planck_temperature, planck_length, planck_charge,
27
+ planck_area, planck_volume, planck_momentum, planck_energy, planck_force,
28
+ planck_power, planck_density, planck_energy_density, planck_intensity,
29
+ planck_angular_frequency, planck_pressure, planck_current, planck_voltage,
30
+ planck_impedance, planck_acceleration, bit, byte, kibibyte, mebibyte,
31
+ gibibyte, tebibyte, pebibyte, exbibyte, curie, rutherford, radian, degree,
32
+ steradian, angular_mil, atomic_mass_unit, gee, kPa, ampere, u0, kelvin,
33
+ mol, mole, candela, electric_constant, boltzmann, angstrom
34
+ )
35
+
36
+
37
+ dimsys_length_weight_time = DimensionSystem([
38
+ # Dimensional dependencies for MKS base dimensions
39
+ length,
40
+ mass,
41
+ time,
42
+ ], dimensional_dependencies={
43
+ # Dimensional dependencies for derived dimensions
44
+ "velocity": {"length": 1, "time": -1},
45
+ "acceleration": {"length": 1, "time": -2},
46
+ "momentum": {"mass": 1, "length": 1, "time": -1},
47
+ "force": {"mass": 1, "length": 1, "time": -2},
48
+ "energy": {"mass": 1, "length": 2, "time": -2},
49
+ "power": {"length": 2, "mass": 1, "time": -3},
50
+ "pressure": {"mass": 1, "length": -1, "time": -2},
51
+ "frequency": {"time": -1},
52
+ "action": {"length": 2, "mass": 1, "time": -1},
53
+ "area": {"length": 2},
54
+ "volume": {"length": 3},
55
+ })
56
+
57
+
58
+ One = S.One
59
+
60
+
61
+ # Base units:
62
+ dimsys_length_weight_time.set_quantity_dimension(meter, length)
63
+ dimsys_length_weight_time.set_quantity_scale_factor(meter, One)
64
+
65
+ # gram; used to define its prefixed units
66
+ dimsys_length_weight_time.set_quantity_dimension(gram, mass)
67
+ dimsys_length_weight_time.set_quantity_scale_factor(gram, One)
68
+
69
+ dimsys_length_weight_time.set_quantity_dimension(second, time)
70
+ dimsys_length_weight_time.set_quantity_scale_factor(second, One)
71
+
72
+ # derived units
73
+
74
+ dimsys_length_weight_time.set_quantity_dimension(newton, force)
75
+ dimsys_length_weight_time.set_quantity_scale_factor(newton, kilogram*meter/second**2)
76
+
77
+ dimsys_length_weight_time.set_quantity_dimension(joule, energy)
78
+ dimsys_length_weight_time.set_quantity_scale_factor(joule, newton*meter)
79
+
80
+ dimsys_length_weight_time.set_quantity_dimension(watt, power)
81
+ dimsys_length_weight_time.set_quantity_scale_factor(watt, joule/second)
82
+
83
+ dimsys_length_weight_time.set_quantity_dimension(pascal, pressure)
84
+ dimsys_length_weight_time.set_quantity_scale_factor(pascal, newton/meter**2)
85
+
86
+ dimsys_length_weight_time.set_quantity_dimension(hertz, frequency)
87
+ dimsys_length_weight_time.set_quantity_scale_factor(hertz, One)
88
+
89
+ # Other derived units:
90
+
91
+ dimsys_length_weight_time.set_quantity_dimension(dioptre, 1 / length)
92
+ dimsys_length_weight_time.set_quantity_scale_factor(dioptre, 1/meter)
93
+
94
+ # Common volume and area units
95
+
96
+ dimsys_length_weight_time.set_quantity_dimension(hectare, length**2)
97
+ dimsys_length_weight_time.set_quantity_scale_factor(hectare, (meter**2)*(10000))
98
+
99
+ dimsys_length_weight_time.set_quantity_dimension(liter, length**3)
100
+ dimsys_length_weight_time.set_quantity_scale_factor(liter, meter**3/1000)
101
+
102
+
103
+ # Newton constant
104
+ # REF: NIST SP 959 (June 2019)
105
+
106
+ dimsys_length_weight_time.set_quantity_dimension(gravitational_constant, length ** 3 * mass ** -1 * time ** -2)
107
+ dimsys_length_weight_time.set_quantity_scale_factor(gravitational_constant, 6.67430e-11*m**3/(kg*s**2))
108
+
109
+ # speed of light
110
+
111
+ dimsys_length_weight_time.set_quantity_dimension(speed_of_light, velocity)
112
+ dimsys_length_weight_time.set_quantity_scale_factor(speed_of_light, 299792458*meter/second)
113
+
114
+
115
+ # Planck constant
116
+ # REF: NIST SP 959 (June 2019)
117
+
118
+ dimsys_length_weight_time.set_quantity_dimension(planck, action)
119
+ dimsys_length_weight_time.set_quantity_scale_factor(planck, 6.62607015e-34*joule*second)
120
+
121
+ # Reduced Planck constant
122
+ # REF: NIST SP 959 (June 2019)
123
+
124
+ dimsys_length_weight_time.set_quantity_dimension(hbar, action)
125
+ dimsys_length_weight_time.set_quantity_scale_factor(hbar, planck / (2 * pi))
126
+
127
+
128
+ __all__ = [
129
+ 'mmHg', 'atmosphere', 'newton', 'meter', 'vacuum_permittivity', 'pascal',
130
+ 'magnetic_constant', 'angular_mil', 'julian_year', 'weber', 'exbibyte',
131
+ 'liter', 'molar_gas_constant', 'faraday_constant', 'avogadro_constant',
132
+ 'planck_momentum', 'planck_density', 'gee', 'mol', 'bit', 'gray', 'kibi',
133
+ 'bar', 'curie', 'prefix_unit', 'PREFIXES', 'planck_time', 'gram',
134
+ 'candela', 'force', 'planck_intensity', 'energy', 'becquerel',
135
+ 'planck_acceleration', 'speed_of_light', 'dioptre', 'second', 'frequency',
136
+ 'Hz', 'power', 'lux', 'planck_current', 'momentum', 'tebibyte',
137
+ 'planck_power', 'degree', 'mebi', 'K', 'planck_volume',
138
+ 'quart', 'pressure', 'W', 'joule', 'boltzmann_constant', 'c', 'g',
139
+ 'planck_force', 'exbi', 's', 'watt', 'action', 'hbar', 'gibibyte',
140
+ 'DimensionSystem', 'cd', 'volt', 'planck_charge', 'angstrom',
141
+ 'dimsys_length_weight_time', 'pebi', 'vacuum_impedance', 'planck',
142
+ 'farad', 'gravitational_constant', 'u0', 'hertz', 'tesla', 'steradian',
143
+ 'josephson_constant', 'planck_area', 'stefan_boltzmann_constant',
144
+ 'astronomical_unit', 'J', 'N', 'planck_voltage', 'planck_energy',
145
+ 'atomic_mass_constant', 'rutherford', 'elementary_charge', 'Pa',
146
+ 'planck_mass', 'henry', 'planck_angular_frequency', 'ohm', 'pound',
147
+ 'planck_pressure', 'G', 'avogadro_number', 'psi', 'von_klitzing_constant',
148
+ 'planck_length', 'radian', 'mole', 'acceleration',
149
+ 'planck_energy_density', 'mebibyte', 'length',
150
+ 'acceleration_due_to_gravity', 'planck_temperature', 'tebi', 'inch',
151
+ 'electronvolt', 'coulomb_constant', 'kelvin', 'kPa', 'boltzmann',
152
+ 'milli_mass_unit', 'gibi', 'planck_impedance', 'electric_constant', 'kg',
153
+ 'coulomb', 'siemens', 'byte', 'atomic_mass_unit', 'm', 'kibibyte',
154
+ 'kilogram', 'lightyear', 'mass', 'time', 'pebibyte', 'velocity',
155
+ 'ampere', 'katal',
156
+ ]
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/mks.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MKS unit system.
3
+
4
+ MKS stands for "meter, kilogram, second".
5
+ """
6
+
7
+ from sympy.physics.units import UnitSystem
8
+ from sympy.physics.units.definitions import gravitational_constant, hertz, joule, newton, pascal, watt, speed_of_light, gram, kilogram, meter, second
9
+ from sympy.physics.units.definitions.dimension_definitions import (
10
+ acceleration, action, energy, force, frequency, momentum,
11
+ power, pressure, velocity, length, mass, time)
12
+ from sympy.physics.units.prefixes import PREFIXES, prefix_unit
13
+ from sympy.physics.units.systems.length_weight_time import dimsys_length_weight_time
14
+
15
+ dims = (velocity, acceleration, momentum, force, energy, power, pressure,
16
+ frequency, action)
17
+
18
+ units = [meter, gram, second, joule, newton, watt, pascal, hertz]
19
+ all_units = []
20
+
21
+ # Prefixes of units like gram, joule, newton etc get added using `prefix_unit`
22
+ # in the for loop, but the actual units have to be added manually.
23
+ all_units.extend([gram, joule, newton, watt, pascal, hertz])
24
+
25
+ for u in units:
26
+ all_units.extend(prefix_unit(u, PREFIXES))
27
+ all_units.extend([gravitational_constant, speed_of_light])
28
+
29
+ # unit system
30
+ MKS = UnitSystem(base_units=(meter, kilogram, second), units=all_units, name="MKS", dimension_system=dimsys_length_weight_time, derived_units={
31
+ power: watt,
32
+ time: second,
33
+ pressure: pascal,
34
+ length: meter,
35
+ frequency: hertz,
36
+ mass: kilogram,
37
+ force: newton,
38
+ energy: joule,
39
+ velocity: meter/second,
40
+ acceleration: meter/(second**2),
41
+ })
42
+
43
+
44
+ __all__ = [
45
+ 'MKS', 'units', 'all_units', 'dims',
46
+ ]
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/mksa.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ MKS unit system.
3
+
4
+ MKS stands for "meter, kilogram, second, ampere".
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from sympy.physics.units.definitions import Z0, ampere, coulomb, farad, henry, siemens, tesla, volt, weber, ohm
10
+ from sympy.physics.units.definitions.dimension_definitions import (
11
+ capacitance, charge, conductance, current, impedance, inductance,
12
+ magnetic_density, magnetic_flux, voltage)
13
+ from sympy.physics.units.prefixes import PREFIXES, prefix_unit
14
+ from sympy.physics.units.systems.mks import MKS, dimsys_length_weight_time
15
+ from sympy.physics.units.quantities import Quantity
16
+
17
+ dims = (voltage, impedance, conductance, current, capacitance, inductance, charge,
18
+ magnetic_density, magnetic_flux)
19
+
20
+ units = [ampere, volt, ohm, siemens, farad, henry, coulomb, tesla, weber]
21
+
22
+ all_units: list[Quantity] = []
23
+ for u in units:
24
+ all_units.extend(prefix_unit(u, PREFIXES))
25
+ all_units.extend(units)
26
+
27
+ all_units.append(Z0)
28
+
29
+ dimsys_MKSA = dimsys_length_weight_time.extend([
30
+ # Dimensional dependencies for base dimensions (MKSA not in MKS)
31
+ current,
32
+ ], new_dim_deps={
33
+ # Dimensional dependencies for derived dimensions
34
+ "voltage": {"mass": 1, "length": 2, "current": -1, "time": -3},
35
+ "impedance": {"mass": 1, "length": 2, "current": -2, "time": -3},
36
+ "conductance": {"mass": -1, "length": -2, "current": 2, "time": 3},
37
+ "capacitance": {"mass": -1, "length": -2, "current": 2, "time": 4},
38
+ "inductance": {"mass": 1, "length": 2, "current": -2, "time": -2},
39
+ "charge": {"current": 1, "time": 1},
40
+ "magnetic_density": {"mass": 1, "current": -1, "time": -2},
41
+ "magnetic_flux": {"length": 2, "mass": 1, "current": -1, "time": -2},
42
+ })
43
+
44
+ MKSA = MKS.extend(base=(ampere,), units=all_units, name='MKSA', dimension_system=dimsys_MKSA, derived_units={
45
+ magnetic_flux: weber,
46
+ impedance: ohm,
47
+ current: ampere,
48
+ voltage: volt,
49
+ inductance: henry,
50
+ conductance: siemens,
51
+ magnetic_density: tesla,
52
+ charge: coulomb,
53
+ capacitance: farad,
54
+ })
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/natural.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Naturalunit system.
3
+
4
+ The natural system comes from "setting c = 1, hbar = 1". From the computer
5
+ point of view it means that we use velocity and action instead of length and
6
+ time. Moreover instead of mass we use energy.
7
+ """
8
+
9
+ from sympy.physics.units import DimensionSystem
10
+ from sympy.physics.units.definitions import c, eV, hbar
11
+ from sympy.physics.units.definitions.dimension_definitions import (
12
+ action, energy, force, frequency, length, mass, momentum,
13
+ power, time, velocity)
14
+ from sympy.physics.units.prefixes import PREFIXES, prefix_unit
15
+ from sympy.physics.units.unitsystem import UnitSystem
16
+
17
+
18
+ # dimension system
19
+ _natural_dim = DimensionSystem(
20
+ base_dims=(action, energy, velocity),
21
+ derived_dims=(length, mass, time, momentum, force, power, frequency)
22
+ )
23
+
24
+ units = prefix_unit(eV, PREFIXES)
25
+
26
+ # unit system
27
+ natural = UnitSystem(base_units=(hbar, eV, c), units=units, name="Natural system")
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/systems/si.py ADDED
@@ -0,0 +1,377 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ SI unit system.
3
+ Based on MKSA, which stands for "meter, kilogram, second, ampere".
4
+ Added kelvin, candela and mole.
5
+
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from sympy.physics.units import DimensionSystem, Dimension, dHg0
11
+
12
+ from sympy.physics.units.quantities import Quantity
13
+
14
+ from sympy.core.numbers import (Rational, pi)
15
+ from sympy.core.singleton import S
16
+ from sympy.functions.elementary.miscellaneous import sqrt
17
+ from sympy.physics.units.definitions.dimension_definitions import (
18
+ acceleration, action, current, impedance, length, mass, time, velocity,
19
+ amount_of_substance, temperature, information, frequency, force, pressure,
20
+ energy, power, charge, voltage, capacitance, conductance, magnetic_flux,
21
+ magnetic_density, inductance, luminous_intensity
22
+ )
23
+ from sympy.physics.units.definitions import (
24
+ kilogram, newton, second, meter, gram, cd, K, joule, watt, pascal, hertz,
25
+ coulomb, volt, ohm, siemens, farad, henry, tesla, weber, dioptre, lux,
26
+ katal, gray, becquerel, inch, liter, julian_year, gravitational_constant,
27
+ speed_of_light, elementary_charge, planck, hbar, electronvolt,
28
+ avogadro_number, avogadro_constant, boltzmann_constant, electron_rest_mass,
29
+ stefan_boltzmann_constant, Da, atomic_mass_constant, molar_gas_constant,
30
+ faraday_constant, josephson_constant, von_klitzing_constant,
31
+ acceleration_due_to_gravity, magnetic_constant, vacuum_permittivity,
32
+ vacuum_impedance, coulomb_constant, atmosphere, bar, pound, psi, mmHg,
33
+ milli_mass_unit, quart, lightyear, astronomical_unit, planck_mass,
34
+ planck_time, planck_temperature, planck_length, planck_charge, planck_area,
35
+ planck_volume, planck_momentum, planck_energy, planck_force, planck_power,
36
+ planck_density, planck_energy_density, planck_intensity,
37
+ planck_angular_frequency, planck_pressure, planck_current, planck_voltage,
38
+ planck_impedance, planck_acceleration, bit, byte, kibibyte, mebibyte,
39
+ gibibyte, tebibyte, pebibyte, exbibyte, curie, rutherford, radian, degree,
40
+ steradian, angular_mil, atomic_mass_unit, gee, kPa, ampere, u0, c, kelvin,
41
+ mol, mole, candela, m, kg, s, electric_constant, G, boltzmann
42
+ )
43
+ from sympy.physics.units.prefixes import PREFIXES, prefix_unit
44
+ from sympy.physics.units.systems.mksa import MKSA, dimsys_MKSA
45
+
46
+ derived_dims = (frequency, force, pressure, energy, power, charge, voltage,
47
+ capacitance, conductance, magnetic_flux,
48
+ magnetic_density, inductance, luminous_intensity)
49
+ base_dims = (amount_of_substance, luminous_intensity, temperature)
50
+
51
+ units = [mol, cd, K, lux, hertz, newton, pascal, joule, watt, coulomb, volt,
52
+ farad, ohm, siemens, weber, tesla, henry, candela, lux, becquerel,
53
+ gray, katal]
54
+
55
+ all_units: list[Quantity] = []
56
+ for u in units:
57
+ all_units.extend(prefix_unit(u, PREFIXES))
58
+
59
+ all_units.extend(units)
60
+ all_units.extend([mol, cd, K, lux])
61
+
62
+
63
+ dimsys_SI = dimsys_MKSA.extend(
64
+ [
65
+ # Dimensional dependencies for other base dimensions:
66
+ temperature,
67
+ amount_of_substance,
68
+ luminous_intensity,
69
+ ])
70
+
71
+ dimsys_default = dimsys_SI.extend(
72
+ [information],
73
+ )
74
+
75
+ SI = MKSA.extend(base=(mol, cd, K), units=all_units, name='SI', dimension_system=dimsys_SI, derived_units={
76
+ power: watt,
77
+ magnetic_flux: weber,
78
+ time: second,
79
+ impedance: ohm,
80
+ pressure: pascal,
81
+ current: ampere,
82
+ voltage: volt,
83
+ length: meter,
84
+ frequency: hertz,
85
+ inductance: henry,
86
+ temperature: kelvin,
87
+ amount_of_substance: mole,
88
+ luminous_intensity: candela,
89
+ conductance: siemens,
90
+ mass: kilogram,
91
+ magnetic_density: tesla,
92
+ charge: coulomb,
93
+ force: newton,
94
+ capacitance: farad,
95
+ energy: joule,
96
+ velocity: meter/second,
97
+ })
98
+
99
+ One = S.One
100
+
101
+ SI.set_quantity_dimension(radian, One)
102
+
103
+ SI.set_quantity_scale_factor(ampere, One)
104
+
105
+ SI.set_quantity_scale_factor(kelvin, One)
106
+
107
+ SI.set_quantity_scale_factor(mole, One)
108
+
109
+ SI.set_quantity_scale_factor(candela, One)
110
+
111
+ # MKSA extension to MKS: derived units
112
+
113
+ SI.set_quantity_scale_factor(coulomb, One)
114
+
115
+ SI.set_quantity_scale_factor(volt, joule/coulomb)
116
+
117
+ SI.set_quantity_scale_factor(ohm, volt/ampere)
118
+
119
+ SI.set_quantity_scale_factor(siemens, ampere/volt)
120
+
121
+ SI.set_quantity_scale_factor(farad, coulomb/volt)
122
+
123
+ SI.set_quantity_scale_factor(henry, volt*second/ampere)
124
+
125
+ SI.set_quantity_scale_factor(tesla, volt*second/meter**2)
126
+
127
+ SI.set_quantity_scale_factor(weber, joule/ampere)
128
+
129
+
130
+ SI.set_quantity_dimension(lux, luminous_intensity / length ** 2)
131
+ SI.set_quantity_scale_factor(lux, steradian*candela/meter**2)
132
+
133
+ # katal is the SI unit of catalytic activity
134
+
135
+ SI.set_quantity_dimension(katal, amount_of_substance / time)
136
+ SI.set_quantity_scale_factor(katal, mol/second)
137
+
138
+ # gray is the SI unit of absorbed dose
139
+
140
+ SI.set_quantity_dimension(gray, energy / mass)
141
+ SI.set_quantity_scale_factor(gray, meter**2/second**2)
142
+
143
+ # becquerel is the SI unit of radioactivity
144
+
145
+ SI.set_quantity_dimension(becquerel, 1 / time)
146
+ SI.set_quantity_scale_factor(becquerel, 1/second)
147
+
148
+ #### CONSTANTS ####
149
+
150
+ # elementary charge
151
+ # REF: NIST SP 959 (June 2019)
152
+
153
+ SI.set_quantity_dimension(elementary_charge, charge)
154
+ SI.set_quantity_scale_factor(elementary_charge, 1.602176634e-19*coulomb)
155
+
156
+ # Electronvolt
157
+ # REF: NIST SP 959 (June 2019)
158
+
159
+ SI.set_quantity_dimension(electronvolt, energy)
160
+ SI.set_quantity_scale_factor(electronvolt, 1.602176634e-19*joule)
161
+
162
+ # Avogadro number
163
+ # REF: NIST SP 959 (June 2019)
164
+
165
+ SI.set_quantity_dimension(avogadro_number, One)
166
+ SI.set_quantity_scale_factor(avogadro_number, 6.02214076e23)
167
+
168
+ # Avogadro constant
169
+
170
+ SI.set_quantity_dimension(avogadro_constant, amount_of_substance ** -1)
171
+ SI.set_quantity_scale_factor(avogadro_constant, avogadro_number / mol)
172
+
173
+ # Boltzmann constant
174
+ # REF: NIST SP 959 (June 2019)
175
+
176
+ SI.set_quantity_dimension(boltzmann_constant, energy / temperature)
177
+ SI.set_quantity_scale_factor(boltzmann_constant, 1.380649e-23*joule/kelvin)
178
+
179
+ # Stefan-Boltzmann constant
180
+ # REF: NIST SP 959 (June 2019)
181
+
182
+ SI.set_quantity_dimension(stefan_boltzmann_constant, energy * time ** -1 * length ** -2 * temperature ** -4)
183
+ SI.set_quantity_scale_factor(stefan_boltzmann_constant, pi**2 * boltzmann_constant**4 / (60 * hbar**3 * speed_of_light ** 2))
184
+
185
+ # Atomic mass
186
+ # REF: NIST SP 959 (June 2019)
187
+
188
+ SI.set_quantity_dimension(atomic_mass_constant, mass)
189
+ SI.set_quantity_scale_factor(atomic_mass_constant, 1.66053906660e-24*gram)
190
+
191
+ # Molar gas constant
192
+ # REF: NIST SP 959 (June 2019)
193
+
194
+ SI.set_quantity_dimension(molar_gas_constant, energy / (temperature * amount_of_substance))
195
+ SI.set_quantity_scale_factor(molar_gas_constant, boltzmann_constant * avogadro_constant)
196
+
197
+ # Faraday constant
198
+
199
+ SI.set_quantity_dimension(faraday_constant, charge / amount_of_substance)
200
+ SI.set_quantity_scale_factor(faraday_constant, elementary_charge * avogadro_constant)
201
+
202
+ # Josephson constant
203
+
204
+ SI.set_quantity_dimension(josephson_constant, frequency / voltage)
205
+ SI.set_quantity_scale_factor(josephson_constant, 0.5 * planck / elementary_charge)
206
+
207
+ # Von Klitzing constant
208
+
209
+ SI.set_quantity_dimension(von_klitzing_constant, voltage / current)
210
+ SI.set_quantity_scale_factor(von_klitzing_constant, hbar / elementary_charge ** 2)
211
+
212
+ # Acceleration due to gravity (on the Earth surface)
213
+
214
+ SI.set_quantity_dimension(acceleration_due_to_gravity, acceleration)
215
+ SI.set_quantity_scale_factor(acceleration_due_to_gravity, 9.80665*meter/second**2)
216
+
217
+ # magnetic constant:
218
+
219
+ SI.set_quantity_dimension(magnetic_constant, force / current ** 2)
220
+ SI.set_quantity_scale_factor(magnetic_constant, 4*pi/10**7 * newton/ampere**2)
221
+
222
+ # electric constant:
223
+
224
+ SI.set_quantity_dimension(vacuum_permittivity, capacitance / length)
225
+ SI.set_quantity_scale_factor(vacuum_permittivity, 1/(u0 * c**2))
226
+
227
+ # vacuum impedance:
228
+
229
+ SI.set_quantity_dimension(vacuum_impedance, impedance)
230
+ SI.set_quantity_scale_factor(vacuum_impedance, u0 * c)
231
+
232
+ # Electron rest mass
233
+ SI.set_quantity_dimension(electron_rest_mass, mass)
234
+ SI.set_quantity_scale_factor(electron_rest_mass, 9.1093837015e-31*kilogram)
235
+
236
+ # Coulomb's constant:
237
+ SI.set_quantity_dimension(coulomb_constant, force * length ** 2 / charge ** 2)
238
+ SI.set_quantity_scale_factor(coulomb_constant, 1/(4*pi*vacuum_permittivity))
239
+
240
+ SI.set_quantity_dimension(psi, pressure)
241
+ SI.set_quantity_scale_factor(psi, pound * gee / inch ** 2)
242
+
243
+ SI.set_quantity_dimension(mmHg, pressure)
244
+ SI.set_quantity_scale_factor(mmHg, dHg0 * acceleration_due_to_gravity * kilogram / meter**2)
245
+
246
+ SI.set_quantity_dimension(milli_mass_unit, mass)
247
+ SI.set_quantity_scale_factor(milli_mass_unit, atomic_mass_unit/1000)
248
+
249
+ SI.set_quantity_dimension(quart, length ** 3)
250
+ SI.set_quantity_scale_factor(quart, Rational(231, 4) * inch**3)
251
+
252
+ # Other convenient units and magnitudes
253
+
254
+ SI.set_quantity_dimension(lightyear, length)
255
+ SI.set_quantity_scale_factor(lightyear, speed_of_light*julian_year)
256
+
257
+ SI.set_quantity_dimension(astronomical_unit, length)
258
+ SI.set_quantity_scale_factor(astronomical_unit, 149597870691*meter)
259
+
260
+ # Fundamental Planck units:
261
+
262
+ SI.set_quantity_dimension(planck_mass, mass)
263
+ SI.set_quantity_scale_factor(planck_mass, sqrt(hbar*speed_of_light/G))
264
+
265
+ SI.set_quantity_dimension(planck_time, time)
266
+ SI.set_quantity_scale_factor(planck_time, sqrt(hbar*G/speed_of_light**5))
267
+
268
+ SI.set_quantity_dimension(planck_temperature, temperature)
269
+ SI.set_quantity_scale_factor(planck_temperature, sqrt(hbar*speed_of_light**5/G/boltzmann**2))
270
+
271
+ SI.set_quantity_dimension(planck_length, length)
272
+ SI.set_quantity_scale_factor(planck_length, sqrt(hbar*G/speed_of_light**3))
273
+
274
+ SI.set_quantity_dimension(planck_charge, charge)
275
+ SI.set_quantity_scale_factor(planck_charge, sqrt(4*pi*electric_constant*hbar*speed_of_light))
276
+
277
+ # Derived Planck units:
278
+
279
+ SI.set_quantity_dimension(planck_area, length ** 2)
280
+ SI.set_quantity_scale_factor(planck_area, planck_length**2)
281
+
282
+ SI.set_quantity_dimension(planck_volume, length ** 3)
283
+ SI.set_quantity_scale_factor(planck_volume, planck_length**3)
284
+
285
+ SI.set_quantity_dimension(planck_momentum, mass * velocity)
286
+ SI.set_quantity_scale_factor(planck_momentum, planck_mass * speed_of_light)
287
+
288
+ SI.set_quantity_dimension(planck_energy, energy)
289
+ SI.set_quantity_scale_factor(planck_energy, planck_mass * speed_of_light**2)
290
+
291
+ SI.set_quantity_dimension(planck_force, force)
292
+ SI.set_quantity_scale_factor(planck_force, planck_energy / planck_length)
293
+
294
+ SI.set_quantity_dimension(planck_power, power)
295
+ SI.set_quantity_scale_factor(planck_power, planck_energy / planck_time)
296
+
297
+ SI.set_quantity_dimension(planck_density, mass / length ** 3)
298
+ SI.set_quantity_scale_factor(planck_density, planck_mass / planck_length**3)
299
+
300
+ SI.set_quantity_dimension(planck_energy_density, energy / length ** 3)
301
+ SI.set_quantity_scale_factor(planck_energy_density, planck_energy / planck_length**3)
302
+
303
+ SI.set_quantity_dimension(planck_intensity, mass * time ** (-3))
304
+ SI.set_quantity_scale_factor(planck_intensity, planck_energy_density * speed_of_light)
305
+
306
+ SI.set_quantity_dimension(planck_angular_frequency, 1 / time)
307
+ SI.set_quantity_scale_factor(planck_angular_frequency, 1 / planck_time)
308
+
309
+ SI.set_quantity_dimension(planck_pressure, pressure)
310
+ SI.set_quantity_scale_factor(planck_pressure, planck_force / planck_length**2)
311
+
312
+ SI.set_quantity_dimension(planck_current, current)
313
+ SI.set_quantity_scale_factor(planck_current, planck_charge / planck_time)
314
+
315
+ SI.set_quantity_dimension(planck_voltage, voltage)
316
+ SI.set_quantity_scale_factor(planck_voltage, planck_energy / planck_charge)
317
+
318
+ SI.set_quantity_dimension(planck_impedance, impedance)
319
+ SI.set_quantity_scale_factor(planck_impedance, planck_voltage / planck_current)
320
+
321
+ SI.set_quantity_dimension(planck_acceleration, acceleration)
322
+ SI.set_quantity_scale_factor(planck_acceleration, speed_of_light / planck_time)
323
+
324
+ # Older units for radioactivity
325
+
326
+ SI.set_quantity_dimension(curie, 1 / time)
327
+ SI.set_quantity_scale_factor(curie, 37000000000*becquerel)
328
+
329
+ SI.set_quantity_dimension(rutherford, 1 / time)
330
+ SI.set_quantity_scale_factor(rutherford, 1000000*becquerel)
331
+
332
+
333
+ # check that scale factors are the right SI dimensions:
334
+ for _scale_factor, _dimension in zip(
335
+ SI._quantity_scale_factors.values(),
336
+ SI._quantity_dimension_map.values()
337
+ ):
338
+ dimex = SI.get_dimensional_expr(_scale_factor)
339
+ if dimex != 1:
340
+ # XXX: equivalent_dims is an instance method taking two arguments in
341
+ # addition to self so this can not work:
342
+ if not DimensionSystem.equivalent_dims(_dimension, Dimension(dimex)): # type: ignore
343
+ raise ValueError("quantity value and dimension mismatch")
344
+ del _scale_factor, _dimension
345
+
346
+ __all__ = [
347
+ 'mmHg', 'atmosphere', 'inductance', 'newton', 'meter',
348
+ 'vacuum_permittivity', 'pascal', 'magnetic_constant', 'voltage',
349
+ 'angular_mil', 'luminous_intensity', 'all_units',
350
+ 'julian_year', 'weber', 'exbibyte', 'liter',
351
+ 'molar_gas_constant', 'faraday_constant', 'avogadro_constant',
352
+ 'lightyear', 'planck_density', 'gee', 'mol', 'bit', 'gray',
353
+ 'planck_momentum', 'bar', 'magnetic_density', 'prefix_unit', 'PREFIXES',
354
+ 'planck_time', 'dimex', 'gram', 'candela', 'force', 'planck_intensity',
355
+ 'energy', 'becquerel', 'planck_acceleration', 'speed_of_light',
356
+ 'conductance', 'frequency', 'coulomb_constant', 'degree', 'lux', 'planck',
357
+ 'current', 'planck_current', 'tebibyte', 'planck_power', 'MKSA', 'power',
358
+ 'K', 'planck_volume', 'quart', 'pressure', 'amount_of_substance',
359
+ 'joule', 'boltzmann_constant', 'Dimension', 'c', 'planck_force', 'length',
360
+ 'watt', 'action', 'hbar', 'gibibyte', 'DimensionSystem', 'cd', 'volt',
361
+ 'planck_charge', 'dioptre', 'vacuum_impedance', 'dimsys_default', 'farad',
362
+ 'charge', 'gravitational_constant', 'temperature', 'u0', 'hertz',
363
+ 'capacitance', 'tesla', 'steradian', 'planck_mass', 'josephson_constant',
364
+ 'planck_area', 'stefan_boltzmann_constant', 'base_dims',
365
+ 'astronomical_unit', 'radian', 'planck_voltage', 'impedance',
366
+ 'planck_energy', 'Da', 'atomic_mass_constant', 'rutherford', 'second', 'inch',
367
+ 'elementary_charge', 'SI', 'electronvolt', 'dimsys_SI', 'henry',
368
+ 'planck_angular_frequency', 'ohm', 'pound', 'planck_pressure', 'G', 'psi',
369
+ 'dHg0', 'von_klitzing_constant', 'planck_length', 'avogadro_number',
370
+ 'mole', 'acceleration', 'information', 'planck_energy_density',
371
+ 'mebibyte', 's', 'acceleration_due_to_gravity', 'electron_rest_mass',
372
+ 'planck_temperature', 'units', 'mass', 'dimsys_MKSA', 'kelvin', 'kPa',
373
+ 'boltzmann', 'milli_mass_unit', 'planck_impedance', 'electric_constant',
374
+ 'derived_dims', 'kg', 'coulomb', 'siemens', 'byte', 'magnetic_flux',
375
+ 'atomic_mass_unit', 'm', 'kibibyte', 'kilogram', 'One', 'curie', 'u',
376
+ 'time', 'pebibyte', 'velocity', 'ampere', 'katal',
377
+ ]
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__init__.py ADDED
File without changes
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (226 Bytes). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_dimensions.cpython-311.pyc ADDED
Binary file (14.1 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_dimensionsystem.cpython-311.pyc ADDED
Binary file (6.02 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_prefixes.cpython-311.pyc ADDED
Binary file (5.32 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_quantities.cpython-311.pyc ADDED
Binary file (38.8 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_unitsystem.cpython-311.pyc ADDED
Binary file (6.96 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/__pycache__/test_util.cpython-311.pyc ADDED
Binary file (20.1 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_dimensions.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.physics.units.systems.si import dimsys_SI
2
+
3
+ from sympy.core.numbers import pi
4
+ from sympy.core.singleton import S
5
+ from sympy.core.symbol import Symbol
6
+ from sympy.functions.elementary.complexes import Abs
7
+ from sympy.functions.elementary.exponential import log
8
+ from sympy.functions.elementary.miscellaneous import sqrt
9
+ from sympy.functions.elementary.trigonometric import (acos, atan2, cos)
10
+ from sympy.physics.units.dimensions import Dimension
11
+ from sympy.physics.units.definitions.dimension_definitions import (
12
+ length, time, mass, force, pressure, angle
13
+ )
14
+ from sympy.physics.units import foot
15
+ from sympy.testing.pytest import raises
16
+
17
+
18
+ def test_Dimension_definition():
19
+ assert dimsys_SI.get_dimensional_dependencies(length) == {length: 1}
20
+ assert length.name == Symbol("length")
21
+ assert length.symbol == Symbol("L")
22
+
23
+ halflength = sqrt(length)
24
+ assert dimsys_SI.get_dimensional_dependencies(halflength) == {length: S.Half}
25
+
26
+
27
+ def test_Dimension_error_definition():
28
+ # tuple with more or less than two entries
29
+ raises(TypeError, lambda: Dimension(("length", 1, 2)))
30
+ raises(TypeError, lambda: Dimension(["length"]))
31
+
32
+ # non-number power
33
+ raises(TypeError, lambda: Dimension({"length": "a"}))
34
+
35
+ # non-number with named argument
36
+ raises(TypeError, lambda: Dimension({"length": (1, 2)}))
37
+
38
+ # symbol should by Symbol or str
39
+ raises(AssertionError, lambda: Dimension("length", symbol=1))
40
+
41
+
42
+ def test_str():
43
+ assert str(Dimension("length")) == "Dimension(length)"
44
+ assert str(Dimension("length", "L")) == "Dimension(length, L)"
45
+
46
+
47
+ def test_Dimension_properties():
48
+ assert dimsys_SI.is_dimensionless(length) is False
49
+ assert dimsys_SI.is_dimensionless(length/length) is True
50
+ assert dimsys_SI.is_dimensionless(Dimension("undefined")) is False
51
+
52
+ assert length.has_integer_powers(dimsys_SI) is True
53
+ assert (length**(-1)).has_integer_powers(dimsys_SI) is True
54
+ assert (length**1.5).has_integer_powers(dimsys_SI) is False
55
+
56
+
57
+ def test_Dimension_add_sub():
58
+ assert length + length == length
59
+ assert length - length == length
60
+ assert -length == length
61
+
62
+ raises(TypeError, lambda: length + foot)
63
+ raises(TypeError, lambda: foot + length)
64
+ raises(TypeError, lambda: length - foot)
65
+ raises(TypeError, lambda: foot - length)
66
+
67
+ # issue 14547 - only raise error for dimensional args; allow
68
+ # others to pass
69
+ x = Symbol('x')
70
+ e = length + x
71
+ assert e == x + length and e.is_Add and set(e.args) == {length, x}
72
+ e = length + 1
73
+ assert e == 1 + length == 1 - length and e.is_Add and set(e.args) == {length, 1}
74
+
75
+ assert dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force) == \
76
+ {length: 1, mass: 1, time: -2}
77
+ assert dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force -
78
+ pressure * length**2) == \
79
+ {length: 1, mass: 1, time: -2}
80
+
81
+ raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + pressure))
82
+
83
+ def test_Dimension_mul_div_exp():
84
+ assert 2*length == length*2 == length/2 == length
85
+ assert 2/length == 1/length
86
+ x = Symbol('x')
87
+ m = x*length
88
+ assert m == length*x and m.is_Mul and set(m.args) == {x, length}
89
+ d = x/length
90
+ assert d == x*length**-1 and d.is_Mul and set(d.args) == {x, 1/length}
91
+ d = length/x
92
+ assert d == length*x**-1 and d.is_Mul and set(d.args) == {1/x, length}
93
+
94
+ velo = length / time
95
+
96
+ assert (length * length) == length ** 2
97
+
98
+ assert dimsys_SI.get_dimensional_dependencies(length * length) == {length: 2}
99
+ assert dimsys_SI.get_dimensional_dependencies(length ** 2) == {length: 2}
100
+ assert dimsys_SI.get_dimensional_dependencies(length * time) == {length: 1, time: 1}
101
+ assert dimsys_SI.get_dimensional_dependencies(velo) == {length: 1, time: -1}
102
+ assert dimsys_SI.get_dimensional_dependencies(velo ** 2) == {length: 2, time: -2}
103
+
104
+ assert dimsys_SI.get_dimensional_dependencies(length / length) == {}
105
+ assert dimsys_SI.get_dimensional_dependencies(velo / length * time) == {}
106
+ assert dimsys_SI.get_dimensional_dependencies(length ** -1) == {length: -1}
107
+ assert dimsys_SI.get_dimensional_dependencies(velo ** -1.5) == {length: -1.5, time: 1.5}
108
+
109
+ length_a = length**"a"
110
+ assert dimsys_SI.get_dimensional_dependencies(length_a) == {length: Symbol("a")}
111
+
112
+ assert dimsys_SI.get_dimensional_dependencies(length**pi) == {length: pi}
113
+ assert dimsys_SI.get_dimensional_dependencies(length**(length/length)) == {length: Dimension(1)}
114
+
115
+ raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(length**length))
116
+
117
+ assert length != 1
118
+ assert length / length != 1
119
+
120
+ length_0 = length ** 0
121
+ assert dimsys_SI.get_dimensional_dependencies(length_0) == {}
122
+
123
+ # issue 18738
124
+ a = Symbol('a')
125
+ b = Symbol('b')
126
+ c = sqrt(a**2 + b**2)
127
+ c_dim = c.subs({a: length, b: length})
128
+ assert dimsys_SI.equivalent_dims(c_dim, length)
129
+
130
+ def test_Dimension_functions():
131
+ raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(cos(length)))
132
+ raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(acos(angle)))
133
+ raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(atan2(length, time)))
134
+ raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(length)))
135
+ raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(100, length)))
136
+ raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(length, 10)))
137
+
138
+ assert dimsys_SI.get_dimensional_dependencies(pi) == {}
139
+
140
+ assert dimsys_SI.get_dimensional_dependencies(cos(1)) == {}
141
+ assert dimsys_SI.get_dimensional_dependencies(cos(angle)) == {}
142
+
143
+ assert dimsys_SI.get_dimensional_dependencies(atan2(length, length)) == {}
144
+
145
+ assert dimsys_SI.get_dimensional_dependencies(log(length / length, length / length)) == {}
146
+
147
+ assert dimsys_SI.get_dimensional_dependencies(Abs(length)) == {length: 1}
148
+ assert dimsys_SI.get_dimensional_dependencies(Abs(length / length)) == {}
149
+
150
+ assert dimsys_SI.get_dimensional_dependencies(sqrt(-1)) == {}
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_prefixes.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.mul import Mul
2
+ from sympy.core.numbers import Rational
3
+ from sympy.core.singleton import S
4
+ from sympy.core.symbol import (Symbol, symbols)
5
+ from sympy.physics.units import Quantity, length, meter, W
6
+ from sympy.physics.units.prefixes import PREFIXES, Prefix, prefix_unit, kilo, \
7
+ kibi
8
+ from sympy.physics.units.systems import SI
9
+
10
+ x = Symbol('x')
11
+
12
+
13
+ def test_prefix_operations():
14
+ m = PREFIXES['m']
15
+ k = PREFIXES['k']
16
+ M = PREFIXES['M']
17
+
18
+ dodeca = Prefix('dodeca', 'dd', 1, base=12)
19
+
20
+ assert m * k is S.One
21
+ assert m * W == W / 1000
22
+ assert k * k == M
23
+ assert 1 / m == k
24
+ assert k / m == M
25
+
26
+ assert dodeca * dodeca == 144
27
+ assert 1 / dodeca == S.One / 12
28
+ assert k / dodeca == S(1000) / 12
29
+ assert dodeca / dodeca is S.One
30
+
31
+ m = Quantity("fake_meter")
32
+ SI.set_quantity_dimension(m, S.One)
33
+ SI.set_quantity_scale_factor(m, S.One)
34
+
35
+ assert dodeca * m == 12 * m
36
+ assert dodeca / m == 12 / m
37
+
38
+ expr1 = kilo * 3
39
+ assert isinstance(expr1, Mul)
40
+ assert expr1.args == (3, kilo)
41
+
42
+ expr2 = kilo * x
43
+ assert isinstance(expr2, Mul)
44
+ assert expr2.args == (x, kilo)
45
+
46
+ expr3 = kilo / 3
47
+ assert isinstance(expr3, Mul)
48
+ assert expr3.args == (Rational(1, 3), kilo)
49
+ assert expr3.args == (S.One/3, kilo)
50
+
51
+ expr4 = kilo / x
52
+ assert isinstance(expr4, Mul)
53
+ assert expr4.args == (1/x, kilo)
54
+
55
+
56
+ def test_prefix_unit():
57
+ m = Quantity("fake_meter", abbrev="m")
58
+ m.set_global_relative_scale_factor(1, meter)
59
+
60
+ pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]}
61
+
62
+ q1 = Quantity("millifake_meter", abbrev="mm")
63
+ q2 = Quantity("centifake_meter", abbrev="cm")
64
+ q3 = Quantity("decifake_meter", abbrev="dm")
65
+
66
+ SI.set_quantity_dimension(q1, length)
67
+
68
+ SI.set_quantity_scale_factor(q1, PREFIXES["m"])
69
+ SI.set_quantity_scale_factor(q1, PREFIXES["c"])
70
+ SI.set_quantity_scale_factor(q1, PREFIXES["d"])
71
+
72
+ res = [q1, q2, q3]
73
+
74
+ prefs = prefix_unit(m, pref)
75
+ assert set(prefs) == set(res)
76
+ assert {v.abbrev for v in prefs} == set(symbols("mm,cm,dm"))
77
+
78
+
79
+ def test_bases():
80
+ assert kilo.base == 10
81
+ assert kibi.base == 2
82
+
83
+
84
+ def test_repr():
85
+ assert eval(repr(kilo)) == kilo
86
+ assert eval(repr(kibi)) == kibi
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_unit_system_cgs_gauss.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.concrete.tests.test_sums_products import NS
2
+
3
+ from sympy.core.singleton import S
4
+ from sympy.functions.elementary.miscellaneous import sqrt
5
+ from sympy.physics.units import convert_to, coulomb_constant, elementary_charge, gravitational_constant, planck
6
+ from sympy.physics.units.definitions.unit_definitions import angstrom, statcoulomb, coulomb, second, gram, centimeter, erg, \
7
+ newton, joule, dyne, speed_of_light, meter, farad, henry, statvolt, volt, ohm
8
+ from sympy.physics.units.systems import SI
9
+ from sympy.physics.units.systems.cgs import cgs_gauss
10
+
11
+
12
+ def test_conversion_to_from_si():
13
+ assert convert_to(statcoulomb, coulomb, cgs_gauss) == coulomb/2997924580
14
+ assert convert_to(coulomb, statcoulomb, cgs_gauss) == 2997924580*statcoulomb
15
+ assert convert_to(statcoulomb, sqrt(gram*centimeter**3)/second, cgs_gauss) == centimeter**(S(3)/2)*sqrt(gram)/second
16
+ assert convert_to(coulomb, sqrt(gram*centimeter**3)/second, cgs_gauss) == 2997924580*centimeter**(S(3)/2)*sqrt(gram)/second
17
+
18
+ # SI units have an additional base unit, no conversion in case of electromagnetism:
19
+ assert convert_to(coulomb, statcoulomb, SI) == coulomb
20
+ assert convert_to(statcoulomb, coulomb, SI) == statcoulomb
21
+
22
+ # SI without electromagnetism:
23
+ assert convert_to(erg, joule, SI) == joule/10**7
24
+ assert convert_to(erg, joule, cgs_gauss) == joule/10**7
25
+ assert convert_to(joule, erg, SI) == 10**7*erg
26
+ assert convert_to(joule, erg, cgs_gauss) == 10**7*erg
27
+
28
+
29
+ assert convert_to(dyne, newton, SI) == newton/10**5
30
+ assert convert_to(dyne, newton, cgs_gauss) == newton/10**5
31
+ assert convert_to(newton, dyne, SI) == 10**5*dyne
32
+ assert convert_to(newton, dyne, cgs_gauss) == 10**5*dyne
33
+
34
+
35
+ def test_cgs_gauss_convert_constants():
36
+
37
+ assert convert_to(speed_of_light, centimeter/second, cgs_gauss) == 29979245800*centimeter/second
38
+
39
+ assert convert_to(coulomb_constant, 1, cgs_gauss) == 1
40
+ assert convert_to(coulomb_constant, newton*meter**2/coulomb**2, cgs_gauss) == 22468879468420441*meter**2*newton/(2500000*coulomb**2)
41
+ assert convert_to(coulomb_constant, newton*meter**2/coulomb**2, SI) == 22468879468420441*meter**2*newton/(2500000*coulomb**2)
42
+ assert convert_to(coulomb_constant, dyne*centimeter**2/statcoulomb**2, cgs_gauss) == centimeter**2*dyne/statcoulomb**2
43
+ assert convert_to(coulomb_constant, 1, SI) == coulomb_constant
44
+ assert NS(convert_to(coulomb_constant, newton*meter**2/coulomb**2, SI)) == '8987551787.36818*meter**2*newton/coulomb**2'
45
+
46
+ assert convert_to(elementary_charge, statcoulomb, cgs_gauss)
47
+ assert convert_to(angstrom, centimeter, cgs_gauss) == 1*centimeter/10**8
48
+ assert convert_to(gravitational_constant, dyne*centimeter**2/gram**2, cgs_gauss)
49
+ assert NS(convert_to(planck, erg*second, cgs_gauss)) == '6.62607015e-27*erg*second'
50
+
51
+ spc = 25000*second/(22468879468420441*centimeter)
52
+ assert convert_to(ohm, second/centimeter, cgs_gauss) == spc
53
+ assert convert_to(henry, second**2/centimeter, cgs_gauss) == spc*second
54
+ assert convert_to(volt, statvolt, cgs_gauss) == 10**6*statvolt/299792458
55
+ assert convert_to(farad, centimeter, cgs_gauss) == 299792458**2*centimeter/10**5
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_unitsystem.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.physics.units import DimensionSystem, joule, second, ampere
2
+
3
+ from sympy.core.numbers import Rational
4
+ from sympy.core.singleton import S
5
+ from sympy.physics.units.definitions import c, kg, m, s
6
+ from sympy.physics.units.definitions.dimension_definitions import length, time
7
+ from sympy.physics.units.quantities import Quantity
8
+ from sympy.physics.units.unitsystem import UnitSystem
9
+ from sympy.physics.units.util import convert_to
10
+
11
+
12
+ def test_definition():
13
+ # want to test if the system can have several units of the same dimension
14
+ dm = Quantity("dm")
15
+ base = (m, s)
16
+ # base_dim = (m.dimension, s.dimension)
17
+ ms = UnitSystem(base, (c, dm), "MS", "MS system")
18
+ ms.set_quantity_dimension(dm, length)
19
+ ms.set_quantity_scale_factor(dm, Rational(1, 10))
20
+
21
+ assert set(ms._base_units) == set(base)
22
+ assert set(ms._units) == {m, s, c, dm}
23
+ # assert ms._units == DimensionSystem._sort_dims(base + (velocity,))
24
+ assert ms.name == "MS"
25
+ assert ms.descr == "MS system"
26
+
27
+
28
+ def test_str_repr():
29
+ assert str(UnitSystem((m, s), name="MS")) == "MS"
30
+ assert str(UnitSystem((m, s))) == "UnitSystem((meter, second))"
31
+
32
+ assert repr(UnitSystem((m, s))) == "<UnitSystem: (%s, %s)>" % (m, s)
33
+
34
+
35
+ def test_convert_to():
36
+ A = Quantity("A")
37
+ A.set_global_relative_scale_factor(S.One, ampere)
38
+
39
+ Js = Quantity("Js")
40
+ Js.set_global_relative_scale_factor(S.One, joule*second)
41
+
42
+ mksa = UnitSystem((m, kg, s, A), (Js,))
43
+ assert convert_to(Js, mksa._base_units) == m**2*kg*s**-1/1000
44
+
45
+
46
+ def test_extend():
47
+ ms = UnitSystem((m, s), (c,))
48
+ Js = Quantity("Js")
49
+ Js.set_global_relative_scale_factor(1, joule*second)
50
+ mks = ms.extend((kg,), (Js,))
51
+
52
+ res = UnitSystem((m, s, kg), (c, Js))
53
+ assert set(mks._base_units) == set(res._base_units)
54
+ assert set(mks._units) == set(res._units)
55
+
56
+
57
+ def test_dim():
58
+ dimsys = UnitSystem((m, kg, s), (c,))
59
+ assert dimsys.dim == 3
60
+
61
+
62
+ def test_is_consistent():
63
+ dimension_system = DimensionSystem([length, time])
64
+ us = UnitSystem([m, s], dimension_system=dimension_system)
65
+ assert us.is_consistent == True
66
+
67
+
68
+ def test_get_units_non_prefixed():
69
+ from sympy.physics.units import volt, ohm
70
+ unit_system = UnitSystem.get_unit_system("SI")
71
+ units = unit_system.get_units_non_prefixed()
72
+ for prefix in ["giga", "tera", "peta", "exa", "zetta", "yotta", "kilo", "hecto", "deca", "deci", "centi", "milli", "micro", "nano", "pico", "femto", "atto", "zepto", "yocto"]:
73
+ for unit in units:
74
+ assert isinstance(unit, Quantity), f"{unit} must be a Quantity, not {type(unit)}"
75
+ assert not unit.is_prefixed, f"{unit} is marked as prefixed"
76
+ assert not unit.is_physical_constant, f"{unit} is marked as physics constant"
77
+ assert not unit.name.name.startswith(prefix), f"Unit {unit.name} has prefix {prefix}"
78
+ assert volt in units
79
+ assert ohm in units
80
+
81
+ def test_derived_units_must_exist_in_unit_system():
82
+ for unit_system in UnitSystem._unit_systems.values():
83
+ for preferred_unit in unit_system.derived_units.values():
84
+ units = preferred_unit.atoms(Quantity)
85
+ for unit in units:
86
+ assert unit in unit_system._units, f"Unit {unit} is not in unit system {unit_system}"
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/tests/test_util.py ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.containers import Tuple
2
+ from sympy.core.numbers import pi
3
+ from sympy.core.power import Pow
4
+ from sympy.core.symbol import symbols
5
+ from sympy.core.sympify import sympify
6
+ from sympy.printing.str import sstr
7
+ from sympy.physics.units import (
8
+ G, centimeter, coulomb, day, degree, gram, hbar, hour, inch, joule, kelvin,
9
+ kilogram, kilometer, length, meter, mile, minute, newton, planck,
10
+ planck_length, planck_mass, planck_temperature, planck_time, radians,
11
+ second, speed_of_light, steradian, time, km)
12
+ from sympy.physics.units.util import convert_to, check_dimensions
13
+ from sympy.testing.pytest import raises
14
+ from sympy.functions.elementary.miscellaneous import sqrt
15
+
16
+
17
+ def NS(e, n=15, **options):
18
+ return sstr(sympify(e).evalf(n, **options), full_prec=True)
19
+
20
+
21
+ L = length
22
+ T = time
23
+
24
+
25
+ def test_dim_simplify_add():
26
+ # assert Add(L, L) == L
27
+ assert L + L == L
28
+
29
+
30
+ def test_dim_simplify_mul():
31
+ # assert Mul(L, T) == L*T
32
+ assert L*T == L*T
33
+
34
+
35
+ def test_dim_simplify_pow():
36
+ assert Pow(L, 2) == L**2
37
+
38
+
39
+ def test_dim_simplify_rec():
40
+ # assert Mul(Add(L, L), T) == L*T
41
+ assert (L + L) * T == L*T
42
+
43
+
44
+ def test_convert_to_quantities():
45
+ assert convert_to(3, meter) == 3
46
+
47
+ assert convert_to(mile, kilometer) == 25146*kilometer/15625
48
+ assert convert_to(meter/second, speed_of_light) == speed_of_light/299792458
49
+ assert convert_to(299792458*meter/second, speed_of_light) == speed_of_light
50
+ assert convert_to(2*299792458*meter/second, speed_of_light) == 2*speed_of_light
51
+ assert convert_to(speed_of_light, meter/second) == 299792458*meter/second
52
+ assert convert_to(2*speed_of_light, meter/second) == 599584916*meter/second
53
+ assert convert_to(day, second) == 86400*second
54
+ assert convert_to(2*hour, minute) == 120*minute
55
+ assert convert_to(mile, meter) == 201168*meter/125
56
+ assert convert_to(mile/hour, kilometer/hour) == 25146*kilometer/(15625*hour)
57
+ assert convert_to(3*newton, meter/second) == 3*newton
58
+ assert convert_to(3*newton, kilogram*meter/second**2) == 3*meter*kilogram/second**2
59
+ assert convert_to(kilometer + mile, meter) == 326168*meter/125
60
+ assert convert_to(2*kilometer + 3*mile, meter) == 853504*meter/125
61
+ assert convert_to(inch**2, meter**2) == 16129*meter**2/25000000
62
+ assert convert_to(3*inch**2, meter) == 48387*meter**2/25000000
63
+ assert convert_to(2*kilometer/hour + 3*mile/hour, meter/second) == 53344*meter/(28125*second)
64
+ assert convert_to(2*kilometer/hour + 3*mile/hour, centimeter/second) == 213376*centimeter/(1125*second)
65
+ assert convert_to(kilometer * (mile + kilometer), meter) == 2609344 * meter ** 2
66
+
67
+ assert convert_to(steradian, coulomb) == steradian
68
+ assert convert_to(radians, degree) == 180*degree/pi
69
+ assert convert_to(radians, [meter, degree]) == 180*degree/pi
70
+ assert convert_to(pi*radians, degree) == 180*degree
71
+ assert convert_to(pi, degree) == 180*degree
72
+
73
+ # https://github.com/sympy/sympy/issues/26263
74
+ assert convert_to(sqrt(meter**2 + meter**2.0), meter) == sqrt(meter**2 + meter**2.0)
75
+ assert convert_to((meter**2 + meter**2.0)**2, meter) == (meter**2 + meter**2.0)**2
76
+
77
+
78
+ def test_convert_to_tuples_of_quantities():
79
+ from sympy.core.symbol import symbols
80
+
81
+ alpha, beta = symbols('alpha beta')
82
+
83
+ assert convert_to(speed_of_light, [meter, second]) == 299792458 * meter / second
84
+ assert convert_to(speed_of_light, (meter, second)) == 299792458 * meter / second
85
+ assert convert_to(speed_of_light, Tuple(meter, second)) == 299792458 * meter / second
86
+ assert convert_to(joule, [meter, kilogram, second]) == kilogram*meter**2/second**2
87
+ assert convert_to(joule, [centimeter, gram, second]) == 10000000*centimeter**2*gram/second**2
88
+ assert convert_to(299792458*meter/second, [speed_of_light]) == speed_of_light
89
+ assert convert_to(speed_of_light / 2, [meter, second, kilogram]) == meter/second*299792458 / 2
90
+ # This doesn't make physically sense, but let's keep it as a conversion test:
91
+ assert convert_to(2 * speed_of_light, [meter, second, kilogram]) == 2 * 299792458 * meter / second
92
+ assert convert_to(G, [G, speed_of_light, planck]) == 1.0*G
93
+
94
+ assert NS(convert_to(meter, [G, speed_of_light, hbar]), n=7) == '6.187142e+34*gravitational_constant**0.5000000*hbar**0.5000000/speed_of_light**1.500000'
95
+ assert NS(convert_to(planck_mass, kilogram), n=7) == '2.176434e-8*kilogram'
96
+ assert NS(convert_to(planck_length, meter), n=7) == '1.616255e-35*meter'
97
+ assert NS(convert_to(planck_time, second), n=6) == '5.39125e-44*second'
98
+ assert NS(convert_to(planck_temperature, kelvin), n=7) == '1.416784e+32*kelvin'
99
+ assert NS(convert_to(convert_to(meter, [G, speed_of_light, planck]), meter), n=10) == '1.000000000*meter'
100
+
101
+ # similar to https://github.com/sympy/sympy/issues/26263
102
+ assert convert_to(sqrt(meter**2 + second**2.0), [meter, second]) == sqrt(meter**2 + second**2.0)
103
+ assert convert_to((meter**2 + second**2.0)**2, [meter, second]) == (meter**2 + second**2.0)**2
104
+
105
+ # similar to https://github.com/sympy/sympy/issues/21463
106
+ assert convert_to(1/(beta*meter + meter), 1/meter) == 1/(beta*meter + meter)
107
+ assert convert_to(1/(beta*meter + alpha*meter), 1/kilometer) == (1/(kilometer*beta/1000 + alpha*kilometer/1000))
108
+
109
+ def test_eval_simplify():
110
+ from sympy.physics.units import cm, mm, km, m, K, kilo
111
+ from sympy.core.symbol import symbols
112
+
113
+ x, y = symbols('x y')
114
+
115
+ assert (cm/mm).simplify() == 10
116
+ assert (km/m).simplify() == 1000
117
+ assert (km/cm).simplify() == 100000
118
+ assert (10*x*K*km**2/m/cm).simplify() == 1000000000*x*kelvin
119
+ assert (cm/km/m).simplify() == 1/(10000000*centimeter)
120
+
121
+ assert (3*kilo*meter).simplify() == 3000*meter
122
+ assert (4*kilo*meter/(2*kilometer)).simplify() == 2
123
+ assert (4*kilometer**2/(kilo*meter)**2).simplify() == 4
124
+
125
+
126
+ def test_quantity_simplify():
127
+ from sympy.physics.units.util import quantity_simplify
128
+ from sympy.physics.units import kilo, foot
129
+ from sympy.core.symbol import symbols
130
+
131
+ x, y = symbols('x y')
132
+
133
+ assert quantity_simplify(x*(8*kilo*newton*meter + y)) == x*(8000*meter*newton + y)
134
+ assert quantity_simplify(foot*inch*(foot + inch)) == foot**2*(foot + foot/12)/12
135
+ assert quantity_simplify(foot*inch*(foot*foot + inch*(foot + inch))) == foot**2*(foot**2 + foot/12*(foot + foot/12))/12
136
+ assert quantity_simplify(2**(foot/inch*kilo/1000)*inch) == 4096*foot/12
137
+ assert quantity_simplify(foot**2*inch + inch**2*foot) == 13*foot**3/144
138
+
139
+ def test_quantity_simplify_across_dimensions():
140
+ from sympy.physics.units.util import quantity_simplify
141
+ from sympy.physics.units import ampere, ohm, volt, joule, pascal, farad, second, watt, siemens, henry, tesla, weber, hour, newton
142
+
143
+ assert quantity_simplify(ampere*ohm, across_dimensions=True, unit_system="SI") == volt
144
+ assert quantity_simplify(6*ampere*ohm, across_dimensions=True, unit_system="SI") == 6*volt
145
+ assert quantity_simplify(volt/ampere, across_dimensions=True, unit_system="SI") == ohm
146
+ assert quantity_simplify(volt/ohm, across_dimensions=True, unit_system="SI") == ampere
147
+ assert quantity_simplify(joule/meter**3, across_dimensions=True, unit_system="SI") == pascal
148
+ assert quantity_simplify(farad*ohm, across_dimensions=True, unit_system="SI") == second
149
+ assert quantity_simplify(joule/second, across_dimensions=True, unit_system="SI") == watt
150
+ assert quantity_simplify(meter**3/second, across_dimensions=True, unit_system="SI") == meter**3/second
151
+ assert quantity_simplify(joule/second, across_dimensions=True, unit_system="SI") == watt
152
+
153
+ assert quantity_simplify(joule/coulomb, across_dimensions=True, unit_system="SI") == volt
154
+ assert quantity_simplify(volt/ampere, across_dimensions=True, unit_system="SI") == ohm
155
+ assert quantity_simplify(ampere/volt, across_dimensions=True, unit_system="SI") == siemens
156
+ assert quantity_simplify(coulomb/volt, across_dimensions=True, unit_system="SI") == farad
157
+ assert quantity_simplify(volt*second/ampere, across_dimensions=True, unit_system="SI") == henry
158
+ assert quantity_simplify(volt*second/meter**2, across_dimensions=True, unit_system="SI") == tesla
159
+ assert quantity_simplify(joule/ampere, across_dimensions=True, unit_system="SI") == weber
160
+
161
+ assert quantity_simplify(5*kilometer/hour, across_dimensions=True, unit_system="SI") == 25*meter/(18*second)
162
+ assert quantity_simplify(5*kilogram*meter/second**2, across_dimensions=True, unit_system="SI") == 5*newton
163
+
164
+ def test_check_dimensions():
165
+ x = symbols('x')
166
+ assert check_dimensions(inch + x) == inch + x
167
+ assert check_dimensions(length + x) == length + x
168
+ # after subs we get 2*length; check will clear the constant
169
+ assert check_dimensions((length + x).subs(x, length)) == length
170
+ assert check_dimensions(newton*meter + joule) == joule + meter*newton
171
+ raises(ValueError, lambda: check_dimensions(inch + 1))
172
+ raises(ValueError, lambda: check_dimensions(length + 1))
173
+ raises(ValueError, lambda: check_dimensions(length + time))
174
+ raises(ValueError, lambda: check_dimensions(meter + second))
175
+ raises(ValueError, lambda: check_dimensions(2 * meter + second))
176
+ raises(ValueError, lambda: check_dimensions(2 * meter + 3 * second))
177
+ raises(ValueError, lambda: check_dimensions(1 / second + 1 / meter))
178
+ raises(ValueError, lambda: check_dimensions(2 * meter*(mile + centimeter) + km))
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/unitsystem.py ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Unit system for physical quantities; include definition of constants.
3
+ """
4
+
5
+ from typing import Dict as tDict, Set as tSet
6
+
7
+ from sympy.core.add import Add
8
+ from sympy.core.function import (Derivative, Function)
9
+ from sympy.core.mul import Mul
10
+ from sympy.core.power import Pow
11
+ from sympy.core.singleton import S
12
+ from sympy.physics.units.dimensions import _QuantityMapper
13
+ from sympy.physics.units.quantities import Quantity
14
+
15
+ from .dimensions import Dimension
16
+
17
+
18
+ class UnitSystem(_QuantityMapper):
19
+ """
20
+ UnitSystem represents a coherent set of units.
21
+
22
+ A unit system is basically a dimension system with notions of scales. Many
23
+ of the methods are defined in the same way.
24
+
25
+ It is much better if all base units have a symbol.
26
+ """
27
+
28
+ _unit_systems = {} # type: tDict[str, UnitSystem]
29
+
30
+ def __init__(self, base_units, units=(), name="", descr="", dimension_system=None, derived_units: tDict[Dimension, Quantity]={}):
31
+
32
+ UnitSystem._unit_systems[name] = self
33
+
34
+ self.name = name
35
+ self.descr = descr
36
+
37
+ self._base_units = base_units
38
+ self._dimension_system = dimension_system
39
+ self._units = tuple(set(base_units) | set(units))
40
+ self._base_units = tuple(base_units)
41
+ self._derived_units = derived_units
42
+
43
+ super().__init__()
44
+
45
+ def __str__(self):
46
+ """
47
+ Return the name of the system.
48
+
49
+ If it does not exist, then it makes a list of symbols (or names) of
50
+ the base dimensions.
51
+ """
52
+
53
+ if self.name != "":
54
+ return self.name
55
+ else:
56
+ return "UnitSystem((%s))" % ", ".join(
57
+ str(d) for d in self._base_units)
58
+
59
+ def __repr__(self):
60
+ return '<UnitSystem: %s>' % repr(self._base_units)
61
+
62
+ def extend(self, base, units=(), name="", description="", dimension_system=None, derived_units: tDict[Dimension, Quantity]={}):
63
+ """Extend the current system into a new one.
64
+
65
+ Take the base and normal units of the current system to merge
66
+ them to the base and normal units given in argument.
67
+ If not provided, name and description are overridden by empty strings.
68
+ """
69
+
70
+ base = self._base_units + tuple(base)
71
+ units = self._units + tuple(units)
72
+
73
+ return UnitSystem(base, units, name, description, dimension_system, {**self._derived_units, **derived_units})
74
+
75
+ def get_dimension_system(self):
76
+ return self._dimension_system
77
+
78
+ def get_quantity_dimension(self, unit):
79
+ qdm = self.get_dimension_system()._quantity_dimension_map
80
+ if unit in qdm:
81
+ return qdm[unit]
82
+ return super().get_quantity_dimension(unit)
83
+
84
+ def get_quantity_scale_factor(self, unit):
85
+ qsfm = self.get_dimension_system()._quantity_scale_factors
86
+ if unit in qsfm:
87
+ return qsfm[unit]
88
+ return super().get_quantity_scale_factor(unit)
89
+
90
+ @staticmethod
91
+ def get_unit_system(unit_system):
92
+ if isinstance(unit_system, UnitSystem):
93
+ return unit_system
94
+
95
+ if unit_system not in UnitSystem._unit_systems:
96
+ raise ValueError(
97
+ "Unit system is not supported. Currently"
98
+ "supported unit systems are {}".format(
99
+ ", ".join(sorted(UnitSystem._unit_systems))
100
+ )
101
+ )
102
+
103
+ return UnitSystem._unit_systems[unit_system]
104
+
105
+ @staticmethod
106
+ def get_default_unit_system():
107
+ return UnitSystem._unit_systems["SI"]
108
+
109
+ @property
110
+ def dim(self):
111
+ """
112
+ Give the dimension of the system.
113
+
114
+ That is return the number of units forming the basis.
115
+ """
116
+ return len(self._base_units)
117
+
118
+ @property
119
+ def is_consistent(self):
120
+ """
121
+ Check if the underlying dimension system is consistent.
122
+ """
123
+ # test is performed in DimensionSystem
124
+ return self.get_dimension_system().is_consistent
125
+
126
+ @property
127
+ def derived_units(self) -> tDict[Dimension, Quantity]:
128
+ return self._derived_units
129
+
130
+ def get_dimensional_expr(self, expr):
131
+ from sympy.physics.units import Quantity
132
+ if isinstance(expr, Mul):
133
+ return Mul(*[self.get_dimensional_expr(i) for i in expr.args])
134
+ elif isinstance(expr, Pow):
135
+ return self.get_dimensional_expr(expr.base) ** expr.exp
136
+ elif isinstance(expr, Add):
137
+ return self.get_dimensional_expr(expr.args[0])
138
+ elif isinstance(expr, Derivative):
139
+ dim = self.get_dimensional_expr(expr.expr)
140
+ for independent, count in expr.variable_count:
141
+ dim /= self.get_dimensional_expr(independent)**count
142
+ return dim
143
+ elif isinstance(expr, Function):
144
+ args = [self.get_dimensional_expr(arg) for arg in expr.args]
145
+ if all(i == 1 for i in args):
146
+ return S.One
147
+ return expr.func(*args)
148
+ elif isinstance(expr, Quantity):
149
+ return self.get_quantity_dimension(expr).name
150
+ return S.One
151
+
152
+ def _collect_factor_and_dimension(self, expr):
153
+ """
154
+ Return tuple with scale factor expression and dimension expression.
155
+ """
156
+ from sympy.physics.units import Quantity
157
+ if isinstance(expr, Quantity):
158
+ return expr.scale_factor, expr.dimension
159
+ elif isinstance(expr, Mul):
160
+ factor = 1
161
+ dimension = Dimension(1)
162
+ for arg in expr.args:
163
+ arg_factor, arg_dim = self._collect_factor_and_dimension(arg)
164
+ factor *= arg_factor
165
+ dimension *= arg_dim
166
+ return factor, dimension
167
+ elif isinstance(expr, Pow):
168
+ factor, dim = self._collect_factor_and_dimension(expr.base)
169
+ exp_factor, exp_dim = self._collect_factor_and_dimension(expr.exp)
170
+ if self.get_dimension_system().is_dimensionless(exp_dim):
171
+ exp_dim = 1
172
+ return factor ** exp_factor, dim ** (exp_factor * exp_dim)
173
+ elif isinstance(expr, Add):
174
+ factor, dim = self._collect_factor_and_dimension(expr.args[0])
175
+ for addend in expr.args[1:]:
176
+ addend_factor, addend_dim = \
177
+ self._collect_factor_and_dimension(addend)
178
+ if not self.get_dimension_system().equivalent_dims(dim, addend_dim):
179
+ raise ValueError(
180
+ 'Dimension of "{}" is {}, '
181
+ 'but it should be {}'.format(
182
+ addend, addend_dim, dim))
183
+ factor += addend_factor
184
+ return factor, dim
185
+ elif isinstance(expr, Derivative):
186
+ factor, dim = self._collect_factor_and_dimension(expr.args[0])
187
+ for independent, count in expr.variable_count:
188
+ ifactor, idim = self._collect_factor_and_dimension(independent)
189
+ factor /= ifactor**count
190
+ dim /= idim**count
191
+ return factor, dim
192
+ elif isinstance(expr, Function):
193
+ fds = [self._collect_factor_and_dimension(arg) for arg in expr.args]
194
+ dims = [Dimension(1) if self.get_dimension_system().is_dimensionless(d[1]) else d[1] for d in fds]
195
+ return (expr.func(*(f[0] for f in fds)), *dims)
196
+ elif isinstance(expr, Dimension):
197
+ return S.One, expr
198
+ else:
199
+ return expr, Dimension(1)
200
+
201
+ def get_units_non_prefixed(self) -> tSet[Quantity]:
202
+ """
203
+ Return the units of the system that do not have a prefix.
204
+ """
205
+ return set(filter(lambda u: not u.is_prefixed and not u.is_physical_constant, self._units))
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/units/util.py ADDED
@@ -0,0 +1,265 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Several methods to simplify expressions involving unit objects.
3
+ """
4
+ from functools import reduce
5
+ from collections.abc import Iterable
6
+ from typing import Optional
7
+
8
+ from sympy import default_sort_key
9
+ from sympy.core.add import Add
10
+ from sympy.core.containers import Tuple
11
+ from sympy.core.mul import Mul
12
+ from sympy.core.power import Pow
13
+ from sympy.core.sorting import ordered
14
+ from sympy.core.sympify import sympify
15
+ from sympy.core.function import Function
16
+ from sympy.matrices.exceptions import NonInvertibleMatrixError
17
+ from sympy.physics.units.dimensions import Dimension, DimensionSystem
18
+ from sympy.physics.units.prefixes import Prefix
19
+ from sympy.physics.units.quantities import Quantity
20
+ from sympy.physics.units.unitsystem import UnitSystem
21
+ from sympy.utilities.iterables import sift
22
+
23
+
24
+ def _get_conversion_matrix_for_expr(expr, target_units, unit_system):
25
+ from sympy.matrices.dense import Matrix
26
+
27
+ dimension_system = unit_system.get_dimension_system()
28
+
29
+ expr_dim = Dimension(unit_system.get_dimensional_expr(expr))
30
+ dim_dependencies = dimension_system.get_dimensional_dependencies(expr_dim, mark_dimensionless=True)
31
+ target_dims = [Dimension(unit_system.get_dimensional_expr(x)) for x in target_units]
32
+ canon_dim_units = [i for x in target_dims for i in dimension_system.get_dimensional_dependencies(x, mark_dimensionless=True)]
33
+ canon_expr_units = set(dim_dependencies)
34
+
35
+ if not canon_expr_units.issubset(set(canon_dim_units)):
36
+ return None
37
+
38
+ seen = set()
39
+ canon_dim_units = [i for i in canon_dim_units if not (i in seen or seen.add(i))]
40
+
41
+ camat = Matrix([[dimension_system.get_dimensional_dependencies(i, mark_dimensionless=True).get(j, 0) for i in target_dims] for j in canon_dim_units])
42
+ exprmat = Matrix([dim_dependencies.get(k, 0) for k in canon_dim_units])
43
+
44
+ try:
45
+ res_exponents = camat.solve(exprmat)
46
+ except NonInvertibleMatrixError:
47
+ return None
48
+
49
+ return res_exponents
50
+
51
+
52
+ def convert_to(expr, target_units, unit_system="SI"):
53
+ """
54
+ Convert ``expr`` to the same expression with all of its units and quantities
55
+ represented as factors of ``target_units``, whenever the dimension is compatible.
56
+
57
+ ``target_units`` may be a single unit/quantity, or a collection of
58
+ units/quantities.
59
+
60
+ Examples
61
+ ========
62
+
63
+ >>> from sympy.physics.units import speed_of_light, meter, gram, second, day
64
+ >>> from sympy.physics.units import mile, newton, kilogram, atomic_mass_constant
65
+ >>> from sympy.physics.units import kilometer, centimeter
66
+ >>> from sympy.physics.units import gravitational_constant, hbar
67
+ >>> from sympy.physics.units import convert_to
68
+ >>> convert_to(mile, kilometer)
69
+ 25146*kilometer/15625
70
+ >>> convert_to(mile, kilometer).n()
71
+ 1.609344*kilometer
72
+ >>> convert_to(speed_of_light, meter/second)
73
+ 299792458*meter/second
74
+ >>> convert_to(day, second)
75
+ 86400*second
76
+ >>> 3*newton
77
+ 3*newton
78
+ >>> convert_to(3*newton, kilogram*meter/second**2)
79
+ 3*kilogram*meter/second**2
80
+ >>> convert_to(atomic_mass_constant, gram)
81
+ 1.660539060e-24*gram
82
+
83
+ Conversion to multiple units:
84
+
85
+ >>> convert_to(speed_of_light, [meter, second])
86
+ 299792458*meter/second
87
+ >>> convert_to(3*newton, [centimeter, gram, second])
88
+ 300000*centimeter*gram/second**2
89
+
90
+ Conversion to Planck units:
91
+
92
+ >>> convert_to(atomic_mass_constant, [gravitational_constant, speed_of_light, hbar]).n()
93
+ 7.62963087839509e-20*hbar**0.5*speed_of_light**0.5/gravitational_constant**0.5
94
+
95
+ """
96
+ from sympy.physics.units import UnitSystem
97
+ unit_system = UnitSystem.get_unit_system(unit_system)
98
+
99
+ if not isinstance(target_units, (Iterable, Tuple)):
100
+ target_units = [target_units]
101
+
102
+ def handle_Adds(expr):
103
+ return Add.fromiter(convert_to(i, target_units, unit_system)
104
+ for i in expr.args)
105
+
106
+ if isinstance(expr, Add):
107
+ return handle_Adds(expr)
108
+ elif isinstance(expr, Pow) and isinstance(expr.base, Add):
109
+ return handle_Adds(expr.base) ** expr.exp
110
+
111
+ expr = sympify(expr)
112
+ target_units = sympify(target_units)
113
+
114
+ if isinstance(expr, Function):
115
+ expr = expr.together()
116
+
117
+ if not isinstance(expr, Quantity) and expr.has(Quantity):
118
+ expr = expr.replace(lambda x: isinstance(x, Quantity),
119
+ lambda x: x.convert_to(target_units, unit_system))
120
+
121
+ def get_total_scale_factor(expr):
122
+ if isinstance(expr, Mul):
123
+ return reduce(lambda x, y: x * y,
124
+ [get_total_scale_factor(i) for i in expr.args])
125
+ elif isinstance(expr, Pow):
126
+ return get_total_scale_factor(expr.base) ** expr.exp
127
+ elif isinstance(expr, Quantity):
128
+ return unit_system.get_quantity_scale_factor(expr)
129
+ return expr
130
+
131
+ depmat = _get_conversion_matrix_for_expr(expr, target_units, unit_system)
132
+ if depmat is None:
133
+ return expr
134
+
135
+ expr_scale_factor = get_total_scale_factor(expr)
136
+ return expr_scale_factor * Mul.fromiter(
137
+ (1/get_total_scale_factor(u)*u)**p for u, p in
138
+ zip(target_units, depmat))
139
+
140
+
141
+ def quantity_simplify(expr, across_dimensions: bool=False, unit_system=None):
142
+ """Return an equivalent expression in which prefixes are replaced
143
+ with numerical values and all units of a given dimension are the
144
+ unified in a canonical manner by default. `across_dimensions` allows
145
+ for units of different dimensions to be simplified together.
146
+
147
+ `unit_system` must be specified if `across_dimensions` is True.
148
+
149
+ Examples
150
+ ========
151
+
152
+ >>> from sympy.physics.units.util import quantity_simplify
153
+ >>> from sympy.physics.units.prefixes import kilo
154
+ >>> from sympy.physics.units import foot, inch, joule, coulomb
155
+ >>> quantity_simplify(kilo*foot*inch)
156
+ 250*foot**2/3
157
+ >>> quantity_simplify(foot - 6*inch)
158
+ foot/2
159
+ >>> quantity_simplify(5*joule/coulomb, across_dimensions=True, unit_system="SI")
160
+ 5*volt
161
+ """
162
+
163
+ if expr.is_Atom or not expr.has(Prefix, Quantity):
164
+ return expr
165
+
166
+ # replace all prefixes with numerical values
167
+ p = expr.atoms(Prefix)
168
+ expr = expr.xreplace({p: p.scale_factor for p in p})
169
+
170
+ # replace all quantities of given dimension with a canonical
171
+ # quantity, chosen from those in the expression
172
+ d = sift(expr.atoms(Quantity), lambda i: i.dimension)
173
+ for k in d:
174
+ if len(d[k]) == 1:
175
+ continue
176
+ v = list(ordered(d[k]))
177
+ ref = v[0]/v[0].scale_factor
178
+ expr = expr.xreplace({vi: ref*vi.scale_factor for vi in v[1:]})
179
+
180
+ if across_dimensions:
181
+ # combine quantities of different dimensions into a single
182
+ # quantity that is equivalent to the original expression
183
+
184
+ if unit_system is None:
185
+ raise ValueError("unit_system must be specified if across_dimensions is True")
186
+
187
+ unit_system = UnitSystem.get_unit_system(unit_system)
188
+ dimension_system: DimensionSystem = unit_system.get_dimension_system()
189
+ dim_expr = unit_system.get_dimensional_expr(expr)
190
+ dim_deps = dimension_system.get_dimensional_dependencies(dim_expr, mark_dimensionless=True)
191
+
192
+ target_dimension: Optional[Dimension] = None
193
+ for ds_dim, ds_dim_deps in dimension_system.dimensional_dependencies.items():
194
+ if ds_dim_deps == dim_deps:
195
+ target_dimension = ds_dim
196
+ break
197
+
198
+ if target_dimension is None:
199
+ # if we can't find a target dimension, we can't do anything. unsure how to handle this case.
200
+ return expr
201
+
202
+ target_unit = unit_system.derived_units.get(target_dimension)
203
+ if target_unit:
204
+ expr = convert_to(expr, target_unit, unit_system)
205
+
206
+ return expr
207
+
208
+
209
+ def check_dimensions(expr, unit_system="SI"):
210
+ """Return expr if units in addends have the same
211
+ base dimensions, else raise a ValueError."""
212
+ # the case of adding a number to a dimensional quantity
213
+ # is ignored for the sake of SymPy core routines, so this
214
+ # function will raise an error now if such an addend is
215
+ # found.
216
+ # Also, when doing substitutions, multiplicative constants
217
+ # might be introduced, so remove those now
218
+
219
+ from sympy.physics.units import UnitSystem
220
+ unit_system = UnitSystem.get_unit_system(unit_system)
221
+
222
+ def addDict(dict1, dict2):
223
+ """Merge dictionaries by adding values of common keys and
224
+ removing keys with value of 0."""
225
+ dict3 = {**dict1, **dict2}
226
+ for key, value in dict3.items():
227
+ if key in dict1 and key in dict2:
228
+ dict3[key] = value + dict1[key]
229
+ return {key:val for key, val in dict3.items() if val != 0}
230
+
231
+ adds = expr.atoms(Add)
232
+ DIM_OF = unit_system.get_dimension_system().get_dimensional_dependencies
233
+ for a in adds:
234
+ deset = set()
235
+ for ai in a.args:
236
+ if ai.is_number:
237
+ deset.add(())
238
+ continue
239
+ dims = []
240
+ skip = False
241
+ dimdict = {}
242
+ for i in Mul.make_args(ai):
243
+ if i.has(Quantity):
244
+ i = Dimension(unit_system.get_dimensional_expr(i))
245
+ if i.has(Dimension):
246
+ dimdict = addDict(dimdict, DIM_OF(i))
247
+ elif i.free_symbols:
248
+ skip = True
249
+ break
250
+ dims.extend(dimdict.items())
251
+ if not skip:
252
+ deset.add(tuple(sorted(dims, key=default_sort_key)))
253
+ if len(deset) > 1:
254
+ raise ValueError(
255
+ "addends have incompatible dimensions: {}".format(deset))
256
+
257
+ # clear multiplicative constants on Dimensions which may be
258
+ # left after substitution
259
+ reps = {}
260
+ for m in expr.atoms(Mul):
261
+ if any(isinstance(i, Dimension) for i in m.args):
262
+ reps[m] = m.func(*[
263
+ i for i in m.args if not i.is_number])
264
+
265
+ return expr.xreplace(reps)
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/__pycache__/test_functions.cpython-311.pyc ADDED
Binary file (67.2 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/__pycache__/test_printing.cpython-311.pyc ADDED
Binary file (19.1 kB). View file
 
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/physics/vector/tests/test_vector.py ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from sympy.core.numbers import (Float, pi)
2
+ from sympy.core.symbol import symbols
3
+ from sympy.core.sorting import ordered
4
+ from sympy.functions.elementary.trigonometric import (cos, sin)
5
+ from sympy.matrices.immutable import ImmutableDenseMatrix as Matrix
6
+ from sympy.physics.vector import ReferenceFrame, Vector, dynamicsymbols, dot
7
+ from sympy.physics.vector.vector import VectorTypeError
8
+ from sympy.abc import x, y, z
9
+ from sympy.testing.pytest import raises
10
+
11
+ A = ReferenceFrame('A')
12
+
13
+
14
+ def test_free_dynamicsymbols():
15
+ A, B, C, D = symbols('A, B, C, D', cls=ReferenceFrame)
16
+ a, b, c, d, e, f = dynamicsymbols('a, b, c, d, e, f')
17
+ B.orient_axis(A, a, A.x)
18
+ C.orient_axis(B, b, B.y)
19
+ D.orient_axis(C, c, C.x)
20
+
21
+ v = d*D.x + e*D.y + f*D.z
22
+
23
+ assert set(ordered(v.free_dynamicsymbols(A))) == {a, b, c, d, e, f}
24
+ assert set(ordered(v.free_dynamicsymbols(B))) == {b, c, d, e, f}
25
+ assert set(ordered(v.free_dynamicsymbols(C))) == {c, d, e, f}
26
+ assert set(ordered(v.free_dynamicsymbols(D))) == {d, e, f}
27
+
28
+
29
+ def test_Vector():
30
+ assert A.x != A.y
31
+ assert A.y != A.z
32
+ assert A.z != A.x
33
+
34
+ assert A.x + 0 == A.x
35
+
36
+ v1 = x*A.x + y*A.y + z*A.z
37
+ v2 = x**2*A.x + y**2*A.y + z**2*A.z
38
+ v3 = v1 + v2
39
+ v4 = v1 - v2
40
+
41
+ assert isinstance(v1, Vector)
42
+ assert dot(v1, A.x) == x
43
+ assert dot(v1, A.y) == y
44
+ assert dot(v1, A.z) == z
45
+
46
+ assert isinstance(v2, Vector)
47
+ assert dot(v2, A.x) == x**2
48
+ assert dot(v2, A.y) == y**2
49
+ assert dot(v2, A.z) == z**2
50
+
51
+ assert isinstance(v3, Vector)
52
+ # We probably shouldn't be using simplify in dot...
53
+ assert dot(v3, A.x) == x**2 + x
54
+ assert dot(v3, A.y) == y**2 + y
55
+ assert dot(v3, A.z) == z**2 + z
56
+
57
+ assert isinstance(v4, Vector)
58
+ # We probably shouldn't be using simplify in dot...
59
+ assert dot(v4, A.x) == x - x**2
60
+ assert dot(v4, A.y) == y - y**2
61
+ assert dot(v4, A.z) == z - z**2
62
+
63
+ assert v1.to_matrix(A) == Matrix([[x], [y], [z]])
64
+ q = symbols('q')
65
+ B = A.orientnew('B', 'Axis', (q, A.x))
66
+ assert v1.to_matrix(B) == Matrix([[x],
67
+ [ y * cos(q) + z * sin(q)],
68
+ [-y * sin(q) + z * cos(q)]])
69
+
70
+ #Test the separate method
71
+ B = ReferenceFrame('B')
72
+ v5 = x*A.x + y*A.y + z*B.z
73
+ assert Vector(0).separate() == {}
74
+ assert v1.separate() == {A: v1}
75
+ assert v5.separate() == {A: x*A.x + y*A.y, B: z*B.z}
76
+
77
+ #Test the free_symbols property
78
+ v6 = x*A.x + y*A.y + z*A.z
79
+ assert v6.free_symbols(A) == {x,y,z}
80
+
81
+ raises(TypeError, lambda: v3.applyfunc(v1))
82
+
83
+
84
+ def test_Vector_diffs():
85
+ q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4')
86
+ q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1)
87
+ q1dd, q2dd, q3dd, q4dd = dynamicsymbols('q1 q2 q3 q4', 2)
88
+ N = ReferenceFrame('N')
89
+ A = N.orientnew('A', 'Axis', [q3, N.z])
90
+ B = A.orientnew('B', 'Axis', [q2, A.x])
91
+ v1 = q2 * A.x + q3 * N.y
92
+ v2 = q3 * B.x + v1
93
+ v3 = v1.dt(B)
94
+ v4 = v2.dt(B)
95
+ v5 = q1*A.x + q2*A.y + q3*A.z
96
+
97
+ assert v1.dt(N) == q2d * A.x + q2 * q3d * A.y + q3d * N.y
98
+ assert v1.dt(A) == q2d * A.x + q3 * q3d * N.x + q3d * N.y
99
+ assert v1.dt(B) == (q2d * A.x + q3 * q3d * N.x + q3d *
100
+ N.y - q3 * cos(q3) * q2d * N.z)
101
+ assert v2.dt(N) == (q2d * A.x + (q2 + q3) * q3d * A.y + q3d * B.x + q3d *
102
+ N.y)
103
+ assert v2.dt(A) == q2d * A.x + q3d * B.x + q3 * q3d * N.x + q3d * N.y
104
+ assert v2.dt(B) == (q2d * A.x + q3d * B.x + q3 * q3d * N.x + q3d * N.y -
105
+ q3 * cos(q3) * q2d * N.z)
106
+ assert v3.dt(N) == (q2dd * A.x + q2d * q3d * A.y + (q3d**2 + q3 * q3dd) *
107
+ N.x + q3dd * N.y + (q3 * sin(q3) * q2d * q3d -
108
+ cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z)
109
+ assert v3.dt(A) == (q2dd * A.x + (2 * q3d**2 + q3 * q3dd) * N.x + (q3dd -
110
+ q3 * q3d**2) * N.y + (q3 * sin(q3) * q2d * q3d -
111
+ cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z)
112
+ assert (v3.dt(B) - (q2dd*A.x - q3*cos(q3)*q2d**2*A.y + (2*q3d**2 +
113
+ q3*q3dd)*N.x + (q3dd - q3*q3d**2)*N.y + (2*q3*sin(q3)*q2d*q3d -
114
+ 2*cos(q3)*q2d*q3d - q3*cos(q3)*q2dd)*N.z)).express(B).simplify() == 0
115
+ assert v4.dt(N) == (q2dd * A.x + q3d * (q2d + q3d) * A.y + q3dd * B.x +
116
+ (q3d**2 + q3 * q3dd) * N.x + q3dd * N.y + (q3 *
117
+ sin(q3) * q2d * q3d - cos(q3) * q2d * q3d - q3 *
118
+ cos(q3) * q2dd) * N.z)
119
+ assert v4.dt(A) == (q2dd * A.x + q3dd * B.x + (2 * q3d**2 + q3 * q3dd) *
120
+ N.x + (q3dd - q3 * q3d**2) * N.y + (q3 * sin(q3) *
121
+ q2d * q3d - cos(q3) * q2d * q3d - q3 * cos(q3) *
122
+ q2dd) * N.z)
123
+ assert (v4.dt(B) - (q2dd*A.x - q3*cos(q3)*q2d**2*A.y + q3dd*B.x +
124
+ (2*q3d**2 + q3*q3dd)*N.x + (q3dd - q3*q3d**2)*N.y +
125
+ (2*q3*sin(q3)*q2d*q3d - 2*cos(q3)*q2d*q3d -
126
+ q3*cos(q3)*q2dd)*N.z)).express(B).simplify() == 0
127
+ assert v5.dt(B) == q1d*A.x + (q3*q2d + q2d)*A.y + (-q2*q2d + q3d)*A.z
128
+ assert v5.dt(A) == q1d*A.x + q2d*A.y + q3d*A.z
129
+ assert v5.dt(N) == (-q2*q3d + q1d)*A.x + (q1*q3d + q2d)*A.y + q3d*A.z
130
+ assert v3.diff(q1d, N) == 0
131
+ assert v3.diff(q2d, N) == A.x - q3 * cos(q3) * N.z
132
+ assert v3.diff(q3d, N) == q3 * N.x + N.y
133
+ assert v3.diff(q1d, A) == 0
134
+ assert v3.diff(q2d, A) == A.x - q3 * cos(q3) * N.z
135
+ assert v3.diff(q3d, A) == q3 * N.x + N.y
136
+ assert v3.diff(q1d, B) == 0
137
+ assert v3.diff(q2d, B) == A.x - q3 * cos(q3) * N.z
138
+ assert v3.diff(q3d, B) == q3 * N.x + N.y
139
+ assert v4.diff(q1d, N) == 0
140
+ assert v4.diff(q2d, N) == A.x - q3 * cos(q3) * N.z
141
+ assert v4.diff(q3d, N) == B.x + q3 * N.x + N.y
142
+ assert v4.diff(q1d, A) == 0
143
+ assert v4.diff(q2d, A) == A.x - q3 * cos(q3) * N.z
144
+ assert v4.diff(q3d, A) == B.x + q3 * N.x + N.y
145
+ assert v4.diff(q1d, B) == 0
146
+ assert v4.diff(q2d, B) == A.x - q3 * cos(q3) * N.z
147
+ assert v4.diff(q3d, B) == B.x + q3 * N.x + N.y
148
+
149
+ # diff() should only express vector components in the derivative frame if
150
+ # the orientation of the component's frame depends on the variable
151
+ v6 = q2**2*N.y + q2**2*A.y + q2**2*B.y
152
+ # already expressed in N
153
+ n_measy = 2*q2
154
+ # A_C_N does not depend on q2, so don't express in N
155
+ a_measy = 2*q2
156
+ # B_C_N depends on q2, so express in N
157
+ b_measx = (q2**2*B.y).dot(N.x).diff(q2)
158
+ b_measy = (q2**2*B.y).dot(N.y).diff(q2)
159
+ b_measz = (q2**2*B.y).dot(N.z).diff(q2)
160
+ n_comp, a_comp = v6.diff(q2, N).args
161
+ assert len(v6.diff(q2, N).args) == 2 # only N and A parts
162
+ assert n_comp[1] == N
163
+ assert a_comp[1] == A
164
+ assert n_comp[0] == Matrix([b_measx, b_measy + n_measy, b_measz])
165
+ assert a_comp[0] == Matrix([0, a_measy, 0])
166
+
167
+
168
+ def test_vector_var_in_dcm():
169
+
170
+ N = ReferenceFrame('N')
171
+ A = ReferenceFrame('A')
172
+ B = ReferenceFrame('B')
173
+ u1, u2, u3, u4 = dynamicsymbols('u1 u2 u3 u4')
174
+
175
+ v = u1 * u2 * A.x + u3 * N.y + u4**2 * N.z
176
+
177
+ assert v.diff(u1, N, var_in_dcm=False) == u2 * A.x
178
+ assert v.diff(u1, A, var_in_dcm=False) == u2 * A.x
179
+ assert v.diff(u3, N, var_in_dcm=False) == N.y
180
+ assert v.diff(u3, A, var_in_dcm=False) == N.y
181
+ assert v.diff(u3, B, var_in_dcm=False) == N.y
182
+ assert v.diff(u4, N, var_in_dcm=False) == 2 * u4 * N.z
183
+
184
+ raises(ValueError, lambda: v.diff(u1, N))
185
+
186
+
187
+ def test_vector_simplify():
188
+ x, y, z, k, n, m, w, f, s, A = symbols('x, y, z, k, n, m, w, f, s, A')
189
+ N = ReferenceFrame('N')
190
+
191
+ test1 = (1 / x + 1 / y) * N.x
192
+ assert (test1 & N.x) != (x + y) / (x * y)
193
+ test1 = test1.simplify()
194
+ assert (test1 & N.x) == (x + y) / (x * y)
195
+
196
+ test2 = (A**2 * s**4 / (4 * pi * k * m**3)) * N.x
197
+ test2 = test2.simplify()
198
+ assert (test2 & N.x) == (A**2 * s**4 / (4 * pi * k * m**3))
199
+
200
+ test3 = ((4 + 4 * x - 2 * (2 + 2 * x)) / (2 + 2 * x)) * N.x
201
+ test3 = test3.simplify()
202
+ assert (test3 & N.x) == 0
203
+
204
+ test4 = ((-4 * x * y**2 - 2 * y**3 - 2 * x**2 * y) / (x + y)**2) * N.x
205
+ test4 = test4.simplify()
206
+ assert (test4 & N.x) == -2 * y
207
+
208
+
209
+ def test_vector_evalf():
210
+ a, b = symbols('a b')
211
+ v = pi * A.x
212
+ assert v.evalf(2) == Float('3.1416', 2) * A.x
213
+ v = pi * A.x + 5 * a * A.y - b * A.z
214
+ assert v.evalf(3) == Float('3.1416', 3) * A.x + Float('5', 3) * a * A.y - b * A.z
215
+ assert v.evalf(5, subs={a: 1.234, b:5.8973}) == Float('3.1415926536', 5) * A.x + Float('6.17', 5) * A.y - Float('5.8973', 5) * A.z
216
+
217
+
218
+ def test_vector_angle():
219
+ A = ReferenceFrame('A')
220
+ v1 = A.x + A.y
221
+ v2 = A.z
222
+ assert v1.angle_between(v2) == pi/2
223
+ B = ReferenceFrame('B')
224
+ B.orient_axis(A, A.x, pi)
225
+ v3 = A.x
226
+ v4 = B.x
227
+ assert v3.angle_between(v4) == 0
228
+
229
+
230
+ def test_vector_xreplace():
231
+ x, y, z = symbols('x y z')
232
+ v = x**2 * A.x + x*y * A.y + x*y*z * A.z
233
+ assert v.xreplace({x : cos(x)}) == cos(x)**2 * A.x + y*cos(x) * A.y + y*z*cos(x) * A.z
234
+ assert v.xreplace({x*y : pi}) == x**2 * A.x + pi * A.y + x*y*z * A.z
235
+ assert v.xreplace({x*y*z : 1}) == x**2*A.x + x*y*A.y + A.z
236
+ assert v.xreplace({x:1, z:0}) == A.x + y * A.y
237
+ raises(TypeError, lambda: v.xreplace())
238
+ raises(TypeError, lambda: v.xreplace([x, y]))
239
+
240
+ def test_issue_23366():
241
+ u1 = dynamicsymbols('u1')
242
+ N = ReferenceFrame('N')
243
+ N_v_A = u1*N.x
244
+ raises(VectorTypeError, lambda: N_v_A.diff(N, u1))
245
+
246
+
247
+ def test_vector_outer():
248
+ a, b, c, d, e, f = symbols('a, b, c, d, e, f')
249
+ N = ReferenceFrame('N')
250
+ v1 = a*N.x + b*N.y + c*N.z
251
+ v2 = d*N.x + e*N.y + f*N.z
252
+ v1v2 = Matrix([[a*d, a*e, a*f],
253
+ [b*d, b*e, b*f],
254
+ [c*d, c*e, c*f]])
255
+ assert v1.outer(v2).to_matrix(N) == v1v2
256
+ assert (v1 | v2).to_matrix(N) == v1v2
257
+ v2v1 = Matrix([[d*a, d*b, d*c],
258
+ [e*a, e*b, e*c],
259
+ [f*a, f*b, f*c]])
260
+ assert v2.outer(v1).to_matrix(N) == v2v1
261
+ assert (v2 | v1).to_matrix(N) == v2v1
262
+
263
+
264
+ def test_overloaded_operators():
265
+ a, b, c, d, e, f = symbols('a, b, c, d, e, f')
266
+ N = ReferenceFrame('N')
267
+ v1 = a*N.x + b*N.y + c*N.z
268
+ v2 = d*N.x + e*N.y + f*N.z
269
+
270
+ assert v1 + v2 == v2 + v1
271
+ assert v1 - v2 == -v2 + v1
272
+ assert v1 & v2 == v2 & v1
273
+ assert v1 ^ v2 == v1.cross(v2)
274
+ assert v2 ^ v1 == v2.cross(v1)
tuning-competition-baseline/.venv/lib/python3.11/site-packages/sympy/polys/__pycache__/appellseqs.cpython-311.pyc ADDED
Binary file (11 kB). View file