Repository: sympy/sympy

Issue:
Dimensional analysis: AttributeError in get_dimensional_dependencies with simple example
Hi all, 

I am trying to get a simple example of a dimensional analysis (as described in [this tutorial](https://docs.sympy.org/latest/modules/physics/units/examples.html#dimensional-analysis) ) to work. Unfortunately, an AttributeError is raised inside the method `get_dimensional_dependencies`.

Here is a minimal example:
```
from sympy import init_printing, symbols, sqrt
from sympy.physics.units.systems.si import dimsys_SI
from sympy.physics.units import length
init_printing()

a, b = symbols("a b")
c = sqrt(a**2 + b**2)
c_dim = c.subs({a: length, b: length})

print(c_dim) 
# >> sqrt(2)*Dimension(sqrt(length**2))

dimsys_SI.equivalent_dims(c_dim, length) 
# >> AttributeError: 'NoneType' object has no attribute 'items' 
```

It seems that `get_dimensional_dependencies` has problems handling non-dimensional terms (i.e. the `sqrt(2)` term in `c_dim` in the above example). Oddly, when I try to do the substitution 'manually', this term is eliminated:
```
c_dim = sqrt(length**2 + length**2)
print(c_dim) 
# >> Dimension(sqrt(length**2))
```

Is this intended behavior? It does make sense that multiplying a dimension with a dimensionless value should just give back the dimension as result. However, how come the `sqrt(2)`-term is not eliminated when substituting symbols for dimensions using `subs`?

I hope I haven't just misunderstood the tutorial/docs. Happy for any help or hints. Also, I would be willing to dive into the code if someone would point me into the right direction.

This may be related to the bug discussed [here](https://gitter.im/sympy/sympy?at=5dc0c052fb4dab784a65dfb1).

The above example was tested with Python 2.7 and 3.7 and sympy 1.5.1.

Discussion:

Patch:
diff --git a/sympy/physics/units/dimensions.py b/sympy/physics/units/dimensions.py
index 8b52ac7025..74e0a2e399 100644
--- a/sympy/physics/units/dimensions.py
+++ b/sympy/physics/units/dimensions.py
@@ -411,6 +411,11 @@ def dimensional_dependencies(self):
         return self.args[2]
 
     def _get_dimensional_dependencies_for_name(self, name):
+        if isinstance(name, Dimension):
+            name = name.name
+
+        if isinstance(name, str):
+            name = Symbol(name)
 
         if name.is_Symbol:
             # Dimensions not included in the dependencies are considered
@@ -430,6 +435,12 @@ def _get_dimensional_dependencies_for_name(self, name):
                     ret[k] += v
             return {k: v for (k, v) in ret.items() if v != 0}
 
+        if name.is_Add:
+            dicts = [get_for_name(i) for i in name.args]
+            if all([d == dicts[0] for d in dicts[1:]]):
+                return dicts[0]
+            raise TypeError("Only equivalent dimensions can be added or subtracted.")
+
         if name.is_Pow:
             dim = get_for_name(name.base)
             return {k: v*name.exp for (k, v) in dim.items()}
@@ -446,12 +457,9 @@ def _get_dimensional_dependencies_for_name(self, name):
             else:
                 return get_for_name(result)
 
-    def get_dimensional_dependencies(self, name, mark_dimensionless=False):
-        if isinstance(name, Dimension):
-            name = name.name
-        if isinstance(name, str):
-            name = Symbol(name)
+        raise TypeError("Type {0} not implemented for get_dimensional_dependencies".format(type(name)))
 
+    def get_dimensional_dependencies(self, name, mark_dimensionless=False):
         dimdep = self._get_dimensional_dependencies_for_name(name)
         if mark_dimensionless and dimdep == {}:
             return {'dimensionless': 1}
diff --git a/sympy/printing/printer.py b/sympy/printing/printer.py
index c1adf8e110..8098ef5ad7 100644
--- a/sympy/printing/printer.py
+++ b/sympy/printing/printer.py
@@ -5,10 +5,9 @@
 adequate representation of that expression.
 
 **The basic concept is the following:**
-
-1.  Let the object print itself if it knows how.
-2.  Take the best fitting method defined in the printer.
-3.  As fall-back use the emptyPrinter method for the printer.
+  1. Let the object print itself if it knows how.
+  2. Take the best fitting method defined in the printer.
+  3. As fall-back use the emptyPrinter method for the printer.
 
 Which Method is Responsible for Printing?
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -18,7 +17,7 @@
 print the given expression in the given style that the printer defines.
 While looking for the method, it follows these steps:
 
-1.  **Let the object print itself if it knows how.**
+1. **Let the object print itself if it knows how.**
 
     The printer looks for a specific method in every object. The name of that method
     depends on the specific printer and is defined under ``Printer.printmethod``.
@@ -34,7 +33,7 @@
     good for user defined classes where it is inconvenient to patch the
     printers.
 
-2.  **Take the best fitting method defined in the printer.**
+2. **Take the best fitting method defined in the printer.**
 
     The printer loops through expr classes (class + its bases), and tries
     to dispatch the work to ``_print_<EXPR_CLASS>``
@@ -66,7 +65,7 @@
     and the result is returned back. Otherwise, the printer tries to call
     ``._print_Number`` and so on.
 
-3.  **As a fall-back use the emptyPrinter method for the printer.**
+3. **As a fall-back use the emptyPrinter method for the printer.**
 
     As fall-back ``self.emptyPrinter`` will be called with the expression. If
     not defined in the Printer subclass this will be the same as ``str(expr)``.
@@ -156,7 +155,7 @@ def print_my_latex(expr):
 It's important to always use ``self._print(obj)`` to print subcomponents of
 an expression when customizing a printer. Mistakes include:
 
-1.  Using ``self.doprint(obj)`` instead:
+1. Using ``self.doprint(obj)`` instead:
 
     >>> # This example does not work properly, as only the outermost call may use
     >>> # doprint.
@@ -172,7 +171,7 @@ def print_my_latex(expr):
     >>> print_latex(ModOpModeWrong(x, m), mode='inline')  # bad
     $\\operatorname{Mod}{\\left( $x$,$m$ \\right)}$
 
-2.  Using ``str(obj)`` instead:
+2. Using ``str(obj)`` instead:
 
     >>> class ModOpNestedWrong(Mod):
     ...     def _latex(self, printer):
@@ -187,7 +186,7 @@ def print_my_latex(expr):
     >>> print_latex(ModOpNestedWrong(ModOpNestedWrong(x, m), Integer(7)))  # bad
     \\operatorname{Mod}{\\left( ModOpNestedWrong(x, m),7 \\right)}
 
-3.  Using ``LatexPrinter()._print(obj)`` instead.
+3. Using ``LatexPrinter()._print(obj)`` instead.
 
     >>> from sympy.printing.latex import LatexPrinter
     >>> class ModOpSettingsWrong(Mod):
diff --git a/sympy/vector/__init__.py b/sympy/vector/__init__.py
index 718cb9575c..1353d561b8 100644
--- a/sympy/vector/__init__.py
+++ b/sympy/vector/__init__.py
@@ -14,7 +14,7 @@
 from sympy.vector.orienters import (AxisOrienter, BodyOrienter,
                                     SpaceOrienter, QuaternionOrienter)
 from sympy.vector.operators import Gradient, Divergence, Curl, Laplacian, gradient, curl, divergence
-from sympy.vector.parametricregion import (ParametricRegion, parametric_region_list)
+from sympy.vector.parametricregion import ParametricRegion
 from sympy.vector.integrals import (ParametricIntegral, vector_integrate)
 
 __all__ = [
@@ -40,5 +40,5 @@
     'Gradient', 'Divergence', 'Curl', 'Laplacian', 'gradient', 'curl',
     'divergence',
 
-    'ParametricRegion', 'parametric_region_list', 'ParametricIntegral', 'vector_integrate',
+    'ParametricRegion', 'ParametricIntegral', 'vector_integrate',
 ]
diff --git a/sympy/vector/integrals.py b/sympy/vector/integrals.py
index 586cc19d98..cbc256b2ad 100644
--- a/sympy/vector/integrals.py
+++ b/sympy/vector/integrals.py
@@ -1,12 +1,11 @@
-from sympy import S, simplify
-from sympy.core import Basic, diff
+from sympy.core.basic import Basic
+from sympy import simplify
 from sympy.matrices import Matrix
-from sympy.vector import CoordSys3D, Vector, ParametricRegion, parametric_region_list
+from sympy.vector import CoordSys3D, Vector, ParametricRegion
 from sympy.vector.operators import _get_coord_sys_from_expr
 from sympy.integrals import Integral, integrate
+from sympy.core.function import diff
 from sympy.utilities.iterables import topological_sort, default_sort_key
-from sympy.geometry.entity import GeometryEntity
-
 
 class ParametricIntegral(Basic):
     """
@@ -33,7 +32,7 @@ class ParametricIntegral(Basic):
     8*pi
 
     >>> ParametricIntegral(C.j + C.k, ParametricRegion((r*cos(theta), r*sin(theta)), r, theta))
-    0
+    ParametricIntegral(C.j + C.k, ParametricRegion((r*cos(theta), r*sin(theta)), r, theta))
 
     """
 
@@ -49,7 +48,7 @@ def __new__(cls, field, parametricregion):
             coord_sys = next(iter(coord_set))
 
         if parametricregion.dimensions == 0:
-            return S.Zero
+            return super().__new__(cls, field, parametricregion)
 
         base_vectors = coord_sys.base_vectors()
         base_scalars = coord_sys.base_scalars()
@@ -136,7 +135,6 @@ def field(self):
     def parametricregion(self):
         return self.args[1]
 
-
 def vector_integrate(field, *region):
     """
     Compute the integral of a vector/scalar field
@@ -152,31 +150,10 @@ def vector_integrate(field, *region):
     >>> vector_integrate(C.x*C.i, region)
     12
 
-    Integrals over special regions can also be calculated using geometry module.
-    >>> from sympy.geometry import Point, Circle, Triangle
-    >>> c = Circle(Point(0, 2), 5)
-    >>> vector_integrate(C.x**2 + C.y**2, c)
-    290*pi
-    >>> triangle = Triangle(Point(-2, 3), Point(2, 3), Point(0, 5))
-    >>> vector_integrate(3*C.x**2*C.y*C.i + C.j, triangle)
-    -8
-
-    >>> vector_integrate(12*C.y**3, (C.y, 1, 3))
-    240
     >>> vector_integrate(C.x**2*C.z, C.x)
     C.x**3*C.z/3
-
     """
     if len(region) == 1:
         if isinstance(region[0], ParametricRegion):
             return ParametricIntegral(field, region[0])
-
-        if isinstance(region[0], GeometryEntity):
-            regions_list = parametric_region_list(region[0])
-
-            result = 0
-            for reg in regions_list:
-                result += vector_integrate(field, reg)
-            return result
-
     return integrate(field, *region)
diff --git a/sympy/vector/parametricregion.py b/sympy/vector/parametricregion.py
index 1ced7aa0d1..9dea6b4a7c 100644
--- a/sympy/vector/parametricregion.py
+++ b/sympy/vector/parametricregion.py
@@ -1,10 +1,5 @@
-from functools import singledispatch
-from sympy import pi
-from sympy.core import Basic, Tuple
-from sympy.core.symbol import _symbol
-from sympy.solvers import solve
-from sympy.geometry import Point, Segment, Curve, Ellipse, Polygon
-
+from sympy.core.basic import Basic
+from sympy.core.containers import Tuple
 
 class ParametricRegion(Basic):
     """
@@ -87,84 +82,3 @@ def parameters(self):
     @property
     def dimensions(self):
         return len(self.limits)
-
-
-@singledispatch
-def parametric_region_list(reg):
-    """
-    Returns a list of ParametricRegion objects representing the geometric region.
-
-    Examples
-    ========
-
-    >>> from sympy.abc import t
-    >>> from sympy.vector import parametric_region_list
-    >>> from sympy.geometry import Point, Curve, Ellipse, Segment, Polygon
-
-    >>> p = Point(2, 5)
-    >>> parametric_region_list(p)
-    [ParametricRegion((2, 5))]
-
-    >>> c = Curve((t**3, 4*t), (t, -3, 4))
-    >>> parametric_region_list(c)
-    [ParametricRegion((t**3, 4*t), (t, -3, 4))]
-
-    >>> e = Ellipse(Point(1, 3), 2, 3)
-    >>> parametric_region_list(e)
-    [ParametricRegion((2*cos(t) + 1, 3*sin(t) + 3), (t, 0, 2*pi))]
-
-    >>> s = Segment(Point(1, 3), Point(2, 6))
-    >>> parametric_region_list(s)
-    [ParametricRegion((t + 1, 3*t + 3), (t, 0, 1))]
-
-    >>> p1, p2, p3, p4 = [(0, 1), (2, -3), (5, 3), (-2, 3)]
-    >>> poly = Polygon(p1, p2, p3, p4)
-    >>> parametric_region_list(poly)
-    [ParametricRegion((2*t, 1 - 4*t), (t, 0, 1)), ParametricRegion((3*t + 2, 6*t - 3), (t, 0, 1)),\
-     ParametricRegion((5 - 7*t, 3), (t, 0, 1)), ParametricRegion((2*t - 2, 3 - 2*t),  (t, 0, 1))]
-
-    """
-    raise ValueError("SymPy cannot determine parametric representation of the region.")
-
-
-@parametric_region_list.register(Point)
-def _(obj):
-    return [ParametricRegion(obj.args)]
-
-
-@parametric_region_list.register(Curve)
-def _(obj):
-    definition = obj.arbitrary_point(obj.parameter).args
-    bounds = obj.limits
-    return [ParametricRegion(definition, bounds)]
-
-
-@parametric_region_list.register(Ellipse)
-def _(obj, parameter='t'):
-    definition = obj.arbitrary_point(parameter).args
-    t = _symbol(parameter, real=True)
-    bounds = (t, 0, 2*pi)
-    return [ParametricRegion(definition, bounds)]
-
-
-@parametric_region_list.register(Segment)
-def _(obj, parameter='t'):
-    t = _symbol(parameter, real=True)
-    definition = obj.arbitrary_point(t).args
-
-    for i in range(0, 3):
-        lower_bound = solve(definition[i] - obj.points[0].args[i], t)
-        upper_bound = solve(definition[i] - obj.points[1].args[i], t)
-
-        if len(lower_bound) == 1 and len(upper_bound) == 1:
-            bounds = t, lower_bound[0], upper_bound[0]
-            break
-
-    definition_tuple = obj.arbitrary_point(parameter).args
-    return [ParametricRegion(definition_tuple, bounds)]
-
-
-@parametric_region_list.register(Polygon)
-def _(obj, parameter='t'):
-    l = [parametric_region_list(side, parameter)[0] for side in obj.sides]
-    return l


Test patch:
diff --git a/sympy/physics/units/tests/test_dimensions.py b/sympy/physics/units/tests/test_dimensions.py
index 5f1bf6ac78..b0ccdda4cf 100644
--- a/sympy/physics/units/tests/test_dimensions.py
+++ b/sympy/physics/units/tests/test_dimensions.py
@@ -3,7 +3,7 @@
 from sympy import S, Symbol, sqrt
 from sympy.physics.units.dimensions import Dimension
 from sympy.physics.units.definitions.dimension_definitions import (
-    length, time
+    length, time, mass, force, pressure
 )
 from sympy.physics.units import foot
 from sympy.testing.pytest import raises
@@ -66,6 +66,13 @@ def test_Dimension_add_sub():
     e = length + 1
     assert e == 1 + length == 1 - length and e.is_Add and set(e.args) == {length, 1}
 
+    assert  dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force) == \
+            {'length': 1, 'mass': 1, 'time': -2}
+    assert  dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force -
+                                                   pressure * length**2) == \
+            {'length': 1, 'mass': 1, 'time': -2}
+
+    raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + pressure))
 
 def test_Dimension_mul_div_exp():
     assert 2*length == length*2 == length/2 == length
@@ -101,3 +108,10 @@ def test_Dimension_mul_div_exp():
 
     length_0 = length ** 0
     assert dimsys_SI.get_dimensional_dependencies(length_0) == {}
+
+    # issue 18738
+    a = Symbol('a')
+    b = Symbol('b')
+    c = sqrt(a**2 + b**2)
+    c_dim = c.subs({a: length, b: length})
+    assert dimsys_SI.equivalent_dims(c_dim, length)
diff --git a/sympy/vector/tests/test_integrals.py b/sympy/vector/tests/test_integrals.py
index 7dbe1d3c4c..c80b21ac60 100644
--- a/sympy/vector/tests/test_integrals.py
+++ b/sympy/vector/tests/test_integrals.py
@@ -1,14 +1,12 @@
 from sympy import sin, cos, pi, S, sqrt
-from sympy.testing.pytest import raises
 from sympy.vector.coordsysrect import CoordSys3D
-from sympy.vector.integrals import ParametricIntegral, vector_integrate
+from sympy.vector.integrals import ParametricIntegral
 from sympy.vector.parametricregion import ParametricRegion
 from sympy.abc import x, y, z, u, v, r, t, theta, phi
-from sympy.geometry import Point, Segment, Curve, Circle, Polygon, Plane
 
 C = CoordSys3D('C')
 
-def test_parametric_lineintegrals():
+def test_lineintegrals():
     halfcircle = ParametricRegion((4*cos(theta), 4*sin(theta)), (theta, -pi/2, pi/2))
     assert ParametricIntegral(C.x*C.y**4, halfcircle) == S(8192)/5
 
@@ -26,7 +24,7 @@ def test_parametric_lineintegrals():
     field2 = C.y*C.i + C.z*C.j + C.z*C.k
     assert ParametricIntegral(field2, ParametricRegion((cos(t), sin(t), t**2), (t, 0, pi))) == -5*pi/2 + pi**4/2
 
-def test_parametric_surfaceintegrals():
+def test_surfaceintegrals():
 
     semisphere = ParametricRegion((2*sin(phi)*cos(theta), 2*sin(phi)*sin(theta), 2*cos(phi)),\
                             (theta, 0, 2*pi), (phi, 0, pi/2))
@@ -43,7 +41,7 @@ def test_parametric_surfaceintegrals():
     assert ParametricIntegral(-15.6*C.y*C.k, triangle1) == ParametricIntegral(-15.6*C.y*C.k, triangle2)
     assert ParametricIntegral(C.z, triangle1) == 10*C.z
 
-def test_parametric_volumeintegrals():
+def test_volumeintegrals():
 
     cube = ParametricRegion((x, y, z), (x, 0, 1), (y, 0, 1), (z, 0, 1))
     assert ParametricIntegral(1, cube) == 1
@@ -60,35 +58,3 @@ def test_parametric_volumeintegrals():
     assert ParametricIntegral(C.x*C.i + C.j - 100*C.k, region_under_plane1) == \
         ParametricIntegral(C.x*C.i + C.j - 100*C.k, region_under_plane2)
     assert ParametricIntegral(2*C.x, region_under_plane2) == -9
-
-def test_vector_integrate():
-    halfdisc = ParametricRegion((r*cos(theta), r* sin(theta)), (r, -2, 2), (theta, 0, pi))
-    assert vector_integrate(C.x**2, halfdisc) == 4*pi
-    vector_integrate(C.x, ParametricRegion((t, t**2), (t, 2, 3))) == -17*sqrt(17)/12 + 37*sqrt(37)/12
-
-    assert  vector_integrate(C.y**3*C.z, (C.x, 0, 3), (C.y, -1, 4)) == 765*C.z/4
-
-    s1 = Segment(Point(0, 0), Point(0, 1))
-    assert vector_integrate(-15*C.y, s1) == S(-15)/2
-    s2 = Segment(Point(4, 3, 9), Point(1, 1, 7))
-    assert vector_integrate(C.y*C.i, s2) == -6
-
-    curve = Curve((sin(t), cos(t)), (t, 0, 2))
-    assert vector_integrate(5*C.z, curve) == 10*C.z
-
-    c1 = Circle(Point(2, 3), 6)
-    assert vector_integrate(C.x*C.y, c1) == 72*pi
-    c2 = Circle(Point(0, 0), Point(1, 1), Point(1, 0))
-    assert vector_integrate(1, c2) == c2.circumference
-
-    triangle = Polygon((0, 0), (1, 0), (1, 1))
-    assert vector_integrate(C.x*C.i - 14*C.y*C.j, triangle) == 0
-    p1, p2, p3, p4 = [(0, 0), (1, 0), (5, 1), (0, 1)]
-    poly = Polygon(p1, p2, p3, p4)
-    assert vector_integrate(-23*C.z, poly) == -161*C.z - 23*sqrt(17)*C.z
-
-    point = Point(2, 3)
-    assert vector_integrate(C.i*C.y - C.z, point) == ParametricIntegral(C.y*C.i, ParametricRegion((2, 3)))
-
-    pl = Plane(Point(1, 1, 1), Point(2, 3, 4), Point(2, 2, 2))
-    raises(ValueError, lambda: vector_integrate(C.x*C.z*C.i + C.k, pl))
diff --git a/sympy/vector/tests/test_parametricregion.py b/sympy/vector/tests/test_parametricregion.py
index 68cd82db55..10889a66b3 100644
--- a/sympy/vector/tests/test_parametricregion.py
+++ b/sympy/vector/tests/test_parametricregion.py
@@ -1,14 +1,12 @@
 from sympy import sin, cos, pi
 from sympy.vector.coordsysrect import CoordSys3D
-from sympy.vector.parametricregion import ParametricRegion, parametric_region_list
-from sympy.geometry import Point, Segment, Curve, Ellipse, Line, Parabola, Polygon
+from sympy.vector.parametricregion import ParametricRegion
 from sympy.testing.pytest import raises
 from sympy.abc import a, b, r, t, x, y, z, theta, phi
 
-
 C = CoordSys3D('C')
 
-def test_ParametricRegion():
+def test_parametricregion():
 
     point = ParametricRegion((3, 4))
     assert point.definition == (3, 4)
@@ -44,7 +42,7 @@ def test_ParametricRegion():
     assert circle.definition == (r*cos(theta), r*sin(theta))
     assert circle.dimensions == 1
 
-    halfdisc = ParametricRegion((r*cos(theta), r*sin(theta)), (r, -2, 2), (theta, 0, pi))
+    halfdisc = ParametricRegion((r*cos(theta), r* sin(theta)), (r, -2, 2), (theta, 0, pi))
     assert halfdisc.definition == (r*cos(theta), r*sin(theta))
     assert halfdisc.parameters == (r, theta)
     assert halfdisc.limits == {r: (-2, 2), theta: (0, pi)}
@@ -67,30 +65,3 @@ def test_ParametricRegion():
 
     raises(ValueError, lambda: ParametricRegion((a*t**2, 2*a*t), (a, -2)))
     raises(ValueError, lambda: ParametricRegion((a, b), (a**2, sin(b)), (a, 2, 4, 6)))
-
-
-def test_parametric_region_list():
-
-    point = Point(-5, 12)
-    assert parametric_region_list(point) == [ParametricRegion((-5, 12))]
-
-    e = Ellipse(Point(2, 8), 2, 6)
-    assert parametric_region_list(e, t) == [ParametricRegion((2*cos(t) + 2, 6*sin(t) + 8), (t, 0, 2*pi))]
-
-    c = Curve((t, t**3), (t, 5, 3))
-    assert parametric_region_list(c) == [ParametricRegion((t, t**3), (t, 5, 3))]
-
-    s = Segment(Point(2, 11, -6), Point(0, 2, 5))
-    assert parametric_region_list(s, t) == [ParametricRegion((2 - 2*t, 11 - 9*t, 11*t - 6), (t, 0, 1))]
-    s1 = Segment(Point(0, 0), (1, 0))
-    assert parametric_region_list(s1, t) == [ParametricRegion((t, 0), (t, 0, 1))]
-    s2 = Segment(Point(1, 2, 3), Point(1, 2, 5))
-    assert parametric_region_list(s2, t) == [ParametricRegion((1, 2, 2*t + 3), (t, 0, 1))]
-    s3 = Segment(Point(12, 56), Point(12, 56))
-    assert parametric_region_list(s3) == [ParametricRegion((12, 56))]
-
-    poly = Polygon((1,3), (-3, 8), (2, 4))
-    assert parametric_region_list(poly, t) == [ParametricRegion((1 - 4*t, 5*t + 3), (t, 0, 1)), ParametricRegion((5*t - 3, 8 - 4*t), (t, 0, 1)), ParametricRegion((2 - t, 4 - t), (t, 0, 1))]
-
-    p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7,8)))
-    raises(ValueError, lambda: parametric_region_list(p1))