Example #1
0
    def centroid(self):
        """The centroid of the polygon.

        Returns
        -------
        centroid : Point

        See Also
        --------
        Point

        Examples
        --------
        >>> from sympy import Point, Polygon
        >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)])
        >>> poly = Polygon(p1, p2, p3, p4)
        >>> poly.centroid
        Point(31/18, 11/18)

        """
        A = 1/(6*self.area)
        cx, cy = 0, 0
        for i in xrange(len(self)):
            pt1 = self[i - 1]
            pt2 = self[i]
            v = pt1[0]*pt2[1] - pt2[0]*pt1[1]
            cx += v*(pt1[0] + pt2[0])
            cy += v*(pt1[1] + pt2[1])
        return Point(simplify(A*cx), simplify(A*cy))
Example #2
0
    def centroid(self):
        """The centroid of the polygon.

        Returns
        -------
        centroid : Point

        See Also
        --------
        Point

        Examples
        --------
        >>> from sympy import Point, Polygon
        >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)])
        >>> poly = Polygon(p1, p2, p3, p4)
        >>> poly.centroid
        Point(31/18, 11/18)

        """
        A = 1 / (6*self.area)
        cx,cy = 0,0
        for ind in xrange(-1, len(self.vertices)-1):
            pi = self.vertices[ind]
            pii = self.vertices[ind+1]
            v = pi[0]*pii[1]-pii[0]*pi[1]
            cx += v*(pi[0] + pii[0])
            cy += v*(pi[1] + pii[1])
        return Point(simplify(A*cx), simplify(A*cy))
Example #3
0
def test_reciprocal_frame_test():
    with GA_Printer():
        metric = '1 # #,' + \
                 '# 1 #,' + \
                 '# # 1,'

        (e1, e2, e3) = MV.setup('e1 e2 e3', metric)

        E = e1 ^ e2 ^ e3
        Esq = (E*E).scalar()
        assert str(E) == 'e1^e2^e3'
        assert str(Esq) == '(e1.e2)**2 - 2*(e1.e2)*(e1.e3)*(e2.e3) + (e1.e3)**2 + (e2.e3)**2 - 1'
        Esq_inv = 1/Esq

        E1 = (e2 ^ e3)*E
        E2 = (-1)*(e1 ^ e3)*E
        E3 = (e1 ^ e2)*E

        assert str(E1) == '((e2.e3)**2 - 1)*e1 + ((e1.e2) - (e1.e3)*(e2.e3))*e2 + (-(e1.e2)*(e2.e3) + (e1.e3))*e3'
        assert str(E2) == '((e1.e2) - (e1.e3)*(e2.e3))*e1 + ((e1.e3)**2 - 1)*e2 + (-(e1.e2)*(e1.e3) + (e2.e3))*e3'
        assert str(E3) == '(-(e1.e2)*(e2.e3) + (e1.e3))*e1 + (-(e1.e2)*(e1.e3) + (e2.e3))*e2 + ((e1.e2)**2 - 1)*e3'

        w = (E1 | e2)
        w = w.expand()
        assert str(w) == '0'

        w = (E1 | e3)
        w = w.expand()
        assert str(w) == '0'

        w = (E2 | e1)
        w = w.expand()
        assert str(w) == '0'

        w = (E2 | e3)
        w = w.expand()
        assert str(w) == '0'

        w = (E3 | e1)
        w = w.expand()
        assert str(w) == '0'

        w = (E3 | e2)
        w = w.expand()
        assert str(w) == '0'

        w = (E1 | e1)
        w = (w.expand()).scalar()
        Esq = expand(Esq)
        assert str(simplify(w/Esq)) == '1'

        w = (E2 | e2)
        w = (w.expand()).scalar()
        assert str(simplify(w/Esq)) == '1'

        w = (E3 | e3)
        w = (w.expand()).scalar()
        assert str(simplify(w/Esq)) == '1'

    return
Example #4
0
def custom_intersection(c1,c2):
    #check if they are the same circle
    if c1.center == c2.center:
        if c2.radius == c1.radius:
            return c2
        return []

    dx, dy = (c2.center - c1.center).args
    d = (dy**2 + dx**2)**(.5)
    a = (c1.radius**2 - c2.radius**2 + d**2) / (2*d)

    x2 = c1.center.x + (dx * a/d)
    y2 = c1.center.y + (dy * a/d)

    h = (c1.radius**2 - a**2)**(.5)
    rx = -dy * (h/d)
    ry = dx * (h/d)

    xi_1 = simplify(x2 + rx)
    xi_2 = simplify(x2 - rx)
    yi_1 = simplify(y2 + ry)
    yi_2 = simplify(y2 - ry)

    ret = [Point(xi_1, yi_1)]
    if xi_1 != xi_2 or yi_1 != yi_2:
        ret.append(Point(xi_2, yi_2))
    return ret
Example #5
0
File: point.py Project: haz/sympy
    def is_collinear(*points):
        """Is a sequence of points collinear?

        Test whether or not a set of points are collinear. Returns True if
        the set of points are collinear, or False otherwise.

        Parameters
        ----------
        points : sequence of Point

        Returns
        -------
        is_collinear : boolean

        Notes
        --------------------------
        Slope is preserved everywhere on a line, so the slope between
        any two points on the line should be the same. Take the first
        two points, p1 and p2, and create a translated point v1
        with p1 as the origin. Now for every other point we create
        a translated point, vi with p1 also as the origin. Note that
        these translations preserve slope since everything is
        consistently translated to a new origin of p1. Since slope
        is preserved then we have the following equality:
                v1_slope = vi_slope
          =>    v1.y/v1.x = vi.y/vi.x (due to translation)
          =>    v1.y*vi.x = vi.y*v1.x
          =>    v1.y*vi.x - vi.y*v1.x = 0           (*)
        Hence, if we have a vi such that the equality in (*) is False
        then the points are not collinear. We do this test for every
        point in the list, and if all pass then they are collinear.

        Examples
        --------
        >>> from sympy import Point
        >>> from sympy.abc import x
        >>> p1, p2 = Point(0, 0), Point(1, 1)
        >>> p3, p4, p5 = Point(2, 2), Point(x, x), Point(1, 2)
        >>> Point.is_collinear(p1, p2, p3, p4)
        True
        >>> Point.is_collinear(p1, p2, p3, p5)
        False

        """
        points = GeometryEntity.extract_entities(points)
        if len(points) == 0: return False
        if len(points) <= 2: return True # two points always form a line

        # XXX Cross product is used now, but that only extends to three
        #     dimensions. If the concept needs to extend to greater
        #     dimensions then another method would have to be used
        p1 = points[0]
        p2 = points[1]
        v1 = p2 - p1
        for p3 in points[2:]:
            v2 = p3 - p1
            test = simplify(v1[0]*v2[1] - v1[1]*v2[0])
            if simplify(test) != 0:
                return False
        return True
Example #6
0
def test_reciprocal_frame():
    """
    Test of formula for general reciprocal frame of three vectors.
    Let three independent vectors be e1, e2, and e3. The reciprocal
    vectors E1, E2, and E3 obey the relations:

    e_i.E_j = delta_ij*(e1^e2^e3)**2
    """
    g = '1 # #,'+ \
        '# 1 #,'+ \
        '# # 1'

    g3dn = Ga('e1 e2 e3',g=g)

    (e1,e2,e3) = g3dn.mv()

    E = e1^e2^e3
    Esq = (E*E).scalar()
    Esq_inv = 1 / Esq

    E1 = (e2^e3)*E
    E2 = (-1)*(e1^e3)*E
    E3 = (e1^e2)*E

    w = (E1|e2)
    w = w.expand()
    assert w.scalar() == 0

    w = (E1|e3)
    w = w.expand()
    assert w.scalar() == 0

    w = (E2|e1)
    w = w.expand()
    assert w.scalar() == 0

    w = (E2|e3)
    w = w.expand()
    assert w.scalar() == 0

    w = (E3|e1)
    w = w.expand()
    assert w.scalar() == 0

    w = (E3|e2)
    w = w.expand()
    assert w.scalar() == 0

    w = (E1|e1)
    w = (w.expand()).scalar()
    Esq = expand(Esq)
    assert simplify(w/Esq) == 1

    w = (E2|e2)
    w = (w.expand()).scalar()
    assert simplify(w/Esq) == 1

    w = (E3|e3)
    w = (w.expand()).scalar()
    assert simplify(w/Esq) == 1
Example #7
0
    def tangent_line(self, p):
        """
        If p is on the ellipse, returns the tangent line through point p.
        Otherwise, returns the tangent line(s) from p to the ellipse, or
        None if no tangent line is possible (e.g., p inside ellipse).

        Example:

        In [1]: e = Ellipse(Point(0,0), 3, 2)

        In [2]: t = e.tangent_line(e.random_point())

        In [3]: p = Plot()

        In [4]: p[0] = e

        In [5]: p[1] = t

        The above will plot an ellipse together with a tangent line.
        """
        if p in self:
            rise = (self.vradius ** 2)*(self.center[0] - p[0])
            run = (self.hradius ** 2)*(p[1] - self.center[1])
            p2 = Point(simplify(p[0] + run),
                       simplify(p[1] + rise))
            return Line(p, p2)
        else:
            # TODO If p is not on the ellipse, attempt to create the
            #      tangent(s) from point p to the ellipse..?
            raise NotImplementedError("Cannot find tangent lines when p is not on the ellipse")
Example #8
0
    def arbitrary_point(self, parameter_name='t'):
        """A parametrised point on the Line.

        Parameters
        ----------
        parameter_name : str, optional
            The name of the parameter which will be used for the parametric
            point. The default value is 't'.

        Returns
        -------
        point : Point

        See Also
        --------
        Point

        Examples
        --------
        >>> from sympy import Point, Line
        >>> p1, p2 = Point(1, 0), Point(5, 3)
        >>> l1 = Line(p1, p2)
        >>> l1.arbitrary_point()
        Point(1 + 4*t, 3*t)

        """
        t = C.Symbol(parameter_name, real=True)
        x = simplify(self.p1[0] + t*(self.p2[0] - self.p1[0]))
        y = simplify(self.p1[1] + t*(self.p2[1] - self.p1[1]))
        return Point(x, y)
Example #9
0
    def incenter(self):
        """The center of the incircle.

        The incircle is the circle which lies inside the triangle and touches
        all three sides.

        Returns
        -------
        incenter : Point

        See Also
        --------
        incircle
        Point

        Examples
        --------
        >>> from sympy.geometry import Point, Triangle
        >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1)
        >>> t = Triangle(p1, p2, p3)
        >>> t.incenter
        Point(-sqrt(2)/2 + 1, -sqrt(2)/2 + 1)

        """
        s = self.sides
        v = self.vertices
        A,B,C = v[0],v[1],v[2]
        a,b,c = s[1].length,s[2].length,s[0].length
        x = simplify((a*A[0] + b*B[0] + c*C[0]) / (a+b+c))
        y = simplify((a*A[1] + b*B[1] + c*C[1]) / (a+b+c))
        return Point(x, y)
Example #10
0
 def __new__(cls, radius=1, center=[0,0,0], direction=[0,0,1], closed=False, **kwargs):
     """
     >>> from sympy import *
     >>> from symplus.strplus import init_mprinting
     >>> init_mprinting()
     >>> InfiniteCylinder()
     InfiniteCylinder(1, [0 0 0]', [0 0 1]', False)
     >>> InfiniteCylinder(2, [0,0,0], [0,1,1])
     InfiniteCylinder(2, [0 0 0]', [0 -sqrt(2)/2 -sqrt(2)/2]', False)
     >>> InfiniteCylinder().contains((1,1,1))
     False
     >>> InfiniteCylinder(2, [0,0,0], [0,1,1]).contains((1,1,1))
     True
     """
     normalization = kwargs.pop("normalization", True)
     radius = sympify(abs(radius))
     direction = Mat(direction)
     if normalization:
         if norm(direction) == 0:
             raise ValueError
         direction = simplify(normalize(direction))
     direction = max(direction, -direction, key=hash)
     center = Mat(center)
     if normalization:
         center = simplify(center - project(center, direction))
     closed = sympify(bool(closed))
     return Basic.__new__(cls, radius, center, direction, closed)
Example #11
0
def _separate(eq, dep, others):
    """Separate expression into two parts based on dependencies of variables."""

    # FIRST PASS
    # Extract derivatives depending our separable variable...
    terms = set()
    for term in eq.args:
        if term.is_Mul:
            for i in term.args:
                if i.is_Derivative and not i.has_any_symbols(*others):
                    terms.add(term)
                    continue
        elif term.is_Derivative and not term.has_any_symbols(*others):
            terms.add(term)
    # Find the factor that we need to divide by
    div = set()
    for term in terms:
        ext, sep = term.expand().as_independent(dep)
        # Failed?
        if sep.has_any_symbols(*others):
            return None
        div.add(ext)
    # FIXME: Find lcm() of all the divisors and divide with it, instead of
    # current hack :(
    # http://code.google.com/p/sympy/issues/detail?id=1498
    if len(div) > 0:
        final = 0
        for term in eq.args:
            eqn = 0
            for i in div:
                eqn += term / i
            final += simplify(eqn)
        eq = final

    # SECOND PASS - separate the derivatives
    div = set()
    lhs = rhs = 0
    for term in eq.args:
        # Check, whether we have already term with independent variable...
        if not term.has_any_symbols(*others):
            lhs += term
            continue
        # ...otherwise, try to separate
        temp, sep = term.expand().as_independent(dep)
        # Failed?
        if sep.has_any_symbols(*others):
            return None
        # Extract the divisors
        div.add(sep)
        rhs -= term.expand()
    # Do the division
    fulldiv = reduce(operator.add, div)
    lhs = simplify(lhs/fulldiv).expand()
    rhs = simplify(rhs/fulldiv).expand()
    # ...and check whether we were successful :)
    if lhs.has_any_symbols(*others) or rhs.has_any_symbols(dep):
        return None
    return [lhs, rhs]
Example #12
0
def test_reciprocal_frame_test():
    with GA_Printer():
        metric = "1 # #," + "# 1 #," + "# # 1,"

        (e1, e2, e3) = MV.setup("e1 e2 e3", metric)

        E = e1 ^ e2 ^ e3
        Esq = (E * E).scalar()
        assert str(E) == "e1^e2^e3"
        assert str(Esq) == "(e1.e2)**2 - 2*(e1.e2)*(e1.e3)*(e2.e3) + (e1.e3)**2 + (e2.e3)**2 - 1"
        Esq_inv = 1 / Esq

        E1 = (e2 ^ e3) * E
        E2 = (-1) * (e1 ^ e3) * E
        E3 = (e1 ^ e2) * E

        assert str(E1) == "((e2.e3)**2 - 1)*e1 + ((e1.e2) - (e1.e3)*(e2.e3))*e2 + (-(e1.e2)*(e2.e3) + (e1.e3))*e3"
        assert str(E2) == "((e1.e2) - (e1.e3)*(e2.e3))*e1 + ((e1.e3)**2 - 1)*e2 + (-(e1.e2)*(e1.e3) + (e2.e3))*e3"
        assert str(E3) == "(-(e1.e2)*(e2.e3) + (e1.e3))*e1 + (-(e1.e2)*(e1.e3) + (e2.e3))*e2 + ((e1.e2)**2 - 1)*e3"

        w = E1 | e2
        w = w.expand()
        assert str(w) == "0"

        w = E1 | e3
        w = w.expand()
        assert str(w) == "0"

        w = E2 | e1
        w = w.expand()
        assert str(w) == "0"

        w = E2 | e3
        w = w.expand()
        assert str(w) == "0"

        w = E3 | e1
        w = w.expand()
        assert str(w) == "0"

        w = E3 | e2
        w = w.expand()
        assert str(w) == "0"

        w = E1 | e1
        w = (w.expand()).scalar()
        Esq = expand(Esq)
        assert str(simplify(w / Esq)) == "1"

        w = E2 | e2
        w = (w.expand()).scalar()
        assert str(simplify(w / Esq)) == "1"

        w = E3 | e3
        w = (w.expand()).scalar()
        assert str(simplify(w / Esq)) == "1"

    return
Example #13
0
def test_simplify():
    x, y = R2_r.coord_functions()
    dx, dy = R2_r.base_oneforms()
    ex, ey = R2_r.base_vectors()
    assert simplify(x) == x
    assert simplify(x*y) == x*y
    assert simplify(dx*dy) == dx*dy
    assert simplify(ex*ey) == ex*ey
    assert ((1-x)*dx)/(1-x)**2 == dx/(1-x)
Example #14
0
 def incenter(self):
     """The incenter of the triangle."""
     s = self.sides
     v = self.vertices
     A,B,C = v[0],v[1],v[2]
     a,b,c = s[1].length,s[2].length,s[0].length
     x = simplify( (a*A[0] + b*B[0] + c*C[0]) / (a+b+c) )
     y = simplify( (a*A[1] + b*B[1] + c*C[1]) / (a+b+c) )
     return Point(x, y)
 def _eval_rewrite_as_cos(self, n, m, theta, phi):
     # This method can be expensive due to extensive use of simplification!
     from sympy.simplify import simplify, trigsimp
     # TODO: Make sure n \in N
     # TODO: Assert |m| <= n ortherwise we should return 0
     term = simplify(self.expand(func=True))
     # We can do this because of the range of theta
     term = term.xreplace({Abs(sin(theta)):sin(theta)})
     return simplify(trigsimp(term))
Example #16
0
 def _image(self, func):
     if isinstance(func, EuclideanTransformation):
         direction = simplify(qrotate(func.rquat, func.parity*self.direction))
         offset = simplify(self.offset + dot(func.tvec, direction))
         closed = self.closed
         return Halfspace(
             offset=offset,
             direction=direction,
             closed=closed,
             normalization=False)
Example #17
0
	def cleanup(self):
		self.cleanState           = symbols(self.dofNames)
		self.cleanVelocity        = symbols(['d'+name for name in self.dofNames])
		symdict                   = dict(zip(self.state+self.velocity, self.cleanState+self.cleanVelocity))
		cleanMatrix               = Matrix([simplify(element).subs(symdict) for element in  self.mass])
		self.cleanMass            = list([cleanMatrix.reshape(self.degreesOfFreedom, self.degreesOfFreedom)])
		self.cleanForce           = [simplify(element).subs(symdict) for element in self.force]
		self.cleanConstraint      = simplify(self.constraint_equation.subs(symdict))
		self.cleanConstraintForce = [simplify(element).subs(symdict) for element in self.virtualForce]
		self.cleanNullForce       = self.nullForce
Example #18
0
	def cleanup(self):
		symbolDictionary = dict(zip(self.state + self.velocity, self.cleanState + self.cleanVelocity))
		N                = len(self._fullCoordinate)
		cleanMatrix      = Matrix([simplify(element).subs(symbolDictionary) for element in  self.mass])
		self._cleanMass  = list([cleanMatrix.reshape(N, N)])
		self._cleanForce = [simplify(element).subs(symbolDictionary) for element in self.force]
		self.SpecialFunctions(symbolDictionary)
		self.cleanConstraint      = simplify(self.constraint_equation.subs(symbolDictionary))
		self.cleanConstraintForce = [simplify(element).subs(symbolDictionary) for element in self.virtualForce]
		self.cleanNullForce       = self.nullForce
Example #19
0
File: point.py Project: haz/sympy
 def __add__(self, other):
     """Add two points, or add a factor to this point's coordinates."""
     if isinstance(other, Point):
         if len(other) == len(self):
             return Point([simplify(a + b) for a, b in zip(self, other)])
         else:
             raise TypeError("Points must have the same number of dimensions")
     else:
         other = sympify(other)
         return Point([simplify(a + other) for a in self])
Example #20
0
    def intersection(self, o):
        if isinstance(o, Circle):
            dx,dy = o.center - self.center
            d = sqrt( simplify(dy**2 + dx**2) )
            a = simplify((self.radius**2 - o.radius**2 + d**2) / (2*d))

            x2 = self.center[0] + (dx * a/d)
            y2 = self.center[1] + (dy * a/d)

            h = sqrt( simplify(self.radius**2 - a**2) )
            rx = -dy * (h/d)
            ry =  dx * (h/d)

            xi_1 = simplify(x2 + rx)
            xi_2 = simplify(x2 - rx)
            yi_1 = simplify(y2 + ry)
            yi_2 = simplify(y2 - ry)

            ret = [Point(xi_1, yi_1)]
            if xi_1 != xi_2 or yi_1 != yi_2:
                ret.append(Point(xi_2, yi_2))
            return ret
        elif isinstance(o, Ellipse):
            a, b, r = o.hradius, o.vradius, self.radius
            x = a*sqrt(simplify((r**2 - b**2)/(a**2 - b**2)))
            y = b*sqrt(simplify((a**2 - r**2)/(a**2 - b**2)))
            return list(set([Point(x,y), Point(x,-y), Point(-x,y), Point(-x,-y)]))

        return Ellipse.intersection(self, o)
Example #21
0
    def arbitrary_point(self, parameter='t'):
        """A parameterized point on the Segment.

        Parameters
        ==========

        parameter : str, optional
            The name of the parameter which will be used for the parametric
            point. The default value is 't'.

        Returns
        =======

        point : Point


        Parameters
        ==========

        parameter : str, optional
            The name of the parameter which will be used for the parametric
            point. The default value is 't'.

        Returns
        =======

        point : Point

        Raises
        ======

        ValueError
            When ``parameter`` already appears in the Segment's definition.

        See Also
        ========

        sympy.geometry.point.Point

        Examples
        ========

        >>> from sympy import Point, Segment
        >>> p1, p2 = Point(1, 0), Point(5, 3)
        >>> s1 = Segment(p1, p2)
        >>> s1.arbitrary_point()
        Point(4*t + 1, 3*t)

        """
        t = _symbol(parameter)
        if t.name in (f.name for f in self.free_symbols):
            raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name)
        x = simplify(self.p1.x + t*(self.p2.x - self.p1.x))
        y = simplify(self.p1.y + t*(self.p2.y - self.p1.y))
        return Point(x, y)
Example #22
0
def create_klann_geometry(orientation = 1, phase = 1, evaluate= True):
    O = Point(0,0)
    mOA = 60
    OA = Point(0,-mOA)
    rotA = orientation*66.28*np.pi/180
    A = OA.rotate(rotA)

    OB = Point(0,1.121*mOA) #.611
    rotB = orientation*-41.76*np.pi/180 # -63.76
    B = simplify(OB.rotate(rotB))

    M_circ = Circle(O, .412*mOA)
    M = M_circ.arbitrary_point()
    if evaluate:
        st = {M.free_symbols.pop():phase}
        M = M.evalf(subs=st)
    C_circ1 = Circle(M,1.143*mOA)
    C_circ2 = Circle(A, .909*mOA)
    C_ints = custom_intersection(C_circ1,C_circ2)
    i= 0
    if orientation == -1:
        i = 1
    C = C_ints[i] #the circles have two intersections, check its the right value
    C = simplify(C)

    MC_length = M.distance(C)
    CD_length = .726*mOA
    Dx = C.x + ((C.x - M.x)/ MC_length)*CD_length
    Dy = C.y + ((C.y - M.y)/ MC_length)*CD_length
    D = Point(Dx, Dy)
    D = simplify(D)

    D_circ = Circle(D, .93*mOA) #.93
    B_circ = Circle(B, .8*mOA) # 1.323 #.8
    E_ints = custom_intersection(B_circ, D_circ)

    E=E_ints[i] #same deal
    E = simplify(E)

    ED_length = E.distance(D)
    DF_length = 2.577*mOA
    Fx = D.x + ((D.x - E.x)/ ED_length)*DF_length
    Fy = D.y + ((D.y - E.y)/ ED_length)*DF_length
    F = Point(Fx, Fy)
    F = simplify(F)

    b1 = Segment(M,D)
    b2 = Segment(B,E)
    b3 = Segment(A,C)
    b4 = Segment(E,F)
    conn = Segment(O,M)

    items = [O,A,B, C, D, E, F,M, b1,b2,b3,b4,conn]
    return items
Example #23
0
 def centroid(self):
     """The centroid of the polygon."""
     A = 1 / (6*self.area)
     cx,cy = 0,0
     for ind in xrange(-1, len(self.vertices)-1):
         pi = self.vertices[ind]
         pii = self.vertices[ind+1]
         v = pi[0]*pii[1]-pii[0]*pi[1]
         cx += v*(pi[0] + pii[0])
         cy += v*(pi[1] + pii[1])
     return Point(simplify(A*cx), simplify(A*cy))
Example #24
0
 def __contains__(self, o):
     """Return True if o is on this Line, or False otherwise."""
     if isinstance(o, Line):
         return self.__eq__(o)
     elif isinstance(o, Point):
         x = C.Symbol('x', real=True)
         y = C.Symbol('y', real=True)
         r = self.equation().subs({x: o[0], y: o[1]})
         x = simplify(r)
         return simplify(x) == 0
     else:
         return False
Example #25
0
 def _image(self, func):
     if isinstance(func, EuclideanTransformation):
         radius = self.radius
         direction = simplify(qrotate(func.rquat, func.parity*self.direction))
         center = simplify(qrotate(func.rquat, func.parity*self.center))
         center = simplify(center + func.tvec - project(func.tvec, direction))
         closed = self.closed
         return InfiniteCylinder(
             radius=radius,
             center=center,
             direction=direction,
             closed=closed,
             normalization=False)
Example #26
0
 def __add__(self, other):
     """
     Create a new point where each coordinate in this point is
     increased by the corresponding coordinate in other.
     """
     if isinstance(other, Point):
         if len(other) == len(self):
             return Point( [simplify(a+b) for a,b in zip(self, other)] )
         else:
             raise TypeError("Points must have the same number of dimensions")
     else:
         other = sympify(other)
         return Point( [simplify(a+other) for a in self] )
Example #27
0
    def tangent_line(self, p):
        """Tangent lines between `p` and the ellipse.

        If `p` is on the ellipse, returns the tangent line through point `p`.
        Otherwise, returns the tangent line(s) from `p` to the ellipse, or
        None if no tangent line is possible (e.g., `p` inside ellipse).

        Parameters
        ----------
        p : Point

        Returns
        -------
        tangent_line : Line

        Raises
        ------
        NotImplementedError
            Can only find tangent lines for a point, `p`, on the ellipse.

        See Also
        --------
        Point
        Line

        Examples
        --------
        >>> from sympy import Point, Ellipse
        >>> e1 = Ellipse(Point(0, 0), 3, 2)
        >>> e1.tangent_line(Point(3, 0))
        Line(Point(3, 0), Point(3, -12))

        >>> # This will plot an ellipse together with a tangent line.
        >>> from sympy import Point, Ellipse, Plot
        >>> e = Ellipse(Point(0,0), 3, 2)
        >>> t = e.tangent_line(e.random_point()) # doctest: +SKIP
        >>> p = Plot() # doctest: +SKIP
        >>> p[0] = e # doctest: +SKIP
        >>> p[1] = t # doctest: +SKIP

        """
        if p in self:
            rise = (self.vradius ** 2)*(self.center[0] - p[0])
            run = (self.hradius ** 2)*(p[1] - self.center[1])
            p2 = Point(simplify(p[0] + run),
                       simplify(p[1] + rise))
            return Line(p, p2)
        else:
            # TODO If p is not on the ellipse, attempt to create the
            #      tangent(s) from point p to the ellipse..?
            raise NotImplementedError("Cannot find tangent lines when p is not on the ellipse")
Example #28
0
    def arbitrary_point(self, parameter='t'):
        """A parameterized point on the Segment.

        Parameters
        ----------
        parameter : str, optional
            The name of the parameter which will be used for the parametric
            point. The default value is 't'.

        Returns
        -------
        point : Point


        Parameters
        ----------
        parameter : str, optional
            The name of the parameter which will be used for the parametric
            point. The default value is 't'.

        Returns
        -------
        point : Point

        Raises
        ------
        ValueError
            When `parameter` already appears in the Segment's definition.

        See Also
        --------
        Point

        Examples
        --------
        >>> from sympy import Point, Segment
        >>> p1, p2 = Point(1, 0), Point(5, 3)
        >>> s1 = Segment(p1, p2)
        >>> s1.arbitrary_point()
        Point(1 + 4*t, 3*t)

        """
        t = _symbol(parameter)
        if t.name in (f.name for f in self.free_symbols):
            raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name)
        x = simplify(self.p1[0] + t*(self.p2[0] - self.p1[0]))
        y = simplify(self.p1[1] + t*(self.p2[1] - self.p1[1]))
        return Point(x, y)
Example #29
0
    def midpoint(self, p):
        """The midpoint between self and point p.

        Parameters
        ==========

        p : Point

        Returns
        =======

        midpoint : Point

        See Also
        ========

        sympy.geometry.line.Segment.midpoint

        Examples
        ========

        >>> from sympy import Point3D
        >>> p1, p2 = Point3D(1, 1, 1), Point3D(13, 5, 1)
        >>> p1.midpoint(p2)
        Point3D(7, 3, 1)

        """
        p = Point3D(p)
        return Point3D([simplify((a + b)*S.Half) for a, b in
            zip(self.args, p.args)])
Example #30
0
    def midpoint(self, p):
        """The midpoint between self and point p.

        Parameters
        ==========

        p : Point

        Returns
        =======

        midpoint : Point

        See Also
        ========

        sympy.geometry.line.Segment.midpoint

        Examples
        ========

        >>> from sympy.geometry import Point
        >>> p1, p2 = Point(1, 1), Point(13, 5)
        >>> p1.midpoint(p2)
        Point2D(7, 3)

        """
        s, p = Point._normalize_dimension(self, Point(p))
        return Point([simplify((a + b)*S.Half) for a, b in zip(s, p)])
Example #31
0
def rsolve(f, y, init=None):
    """
    Solve univariate recurrence with rational coefficients.

    Given `k`-th order linear recurrence `\operatorname{L} y = f`,
    or equivalently:

    .. math:: a_{k}(n) y(n+k) + a_{k-1}(n) y(n+k-1) +
              \dots + a_{0}(n) y(n) = f(n)

    where `a_{i}(n)`, for `i=0, \dots, k`, are polynomials or rational
    functions in `n`, and `f` is a hypergeometric function or a sum
    of a fixed number of pairwise dissimilar hypergeometric terms in
    `n`, finds all solutions or returns ``None``, if none were found.

    Initial conditions can be given as a dictionary in two forms:

        (1) ``{   n_0  : v_0,   n_1  : v_1, ...,   n_m  : v_m }``
        (2) ``{ y(n_0) : v_0, y(n_1) : v_1, ..., y(n_m) : v_m }``

    or as a list ``L`` of values:

        ``L = [ v_0, v_1, ..., v_m ]``

    where ``L[i] = v_i``, for `i=0, \dots, m`, maps to `y(n_i)`.

    Examples
    ========

    Lets consider the following recurrence:

    .. math:: (n - 1) y(n + 2) - (n^2 + 3 n - 2) y(n + 1) +
              2 n (n + 1) y(n) = 0

    >>> from sympy import Function, rsolve
    >>> from sympy.abc import n
    >>> y = Function('y')

    >>> f = (n - 1)*y(n + 2) - (n**2 + 3*n - 2)*y(n + 1) + 2*n*(n + 1)*y(n)

    >>> rsolve(f, y(n))
    2**n*C0 + C1*factorial(n)

    >>> rsolve(f, y(n), { y(0):0, y(1):3 })
    3*2**n - 3*factorial(n)

    See Also
    ========

    rsolve_poly, rsolve_ratio, rsolve_hyper

    """
    if isinstance(f, Equality):
        f = f.lhs - f.rhs

    n = y.args[0]
    k = Wild('k', exclude=(n, ))

    # Preprocess user input to allow things like
    # y(n) + a*(y(n + 1) + y(n - 1))/2
    f = f.expand().collect(y.func(Wild('m', integer=True)))

    h_part = defaultdict(lambda: S.Zero)
    i_part = S.Zero
    for g in Add.make_args(f):
        coeff = S.One
        kspec = None
        for h in Mul.make_args(g):
            if h.is_Function:
                if h.func == y.func:
                    result = h.args[0].match(n + k)

                    if result is not None:
                        kspec = int(result[k])
                    else:
                        raise ValueError("'%s(%s+k)' expected, got '%s'" %
                                         (y.func, n, h))
                else:
                    raise ValueError("'%s' expected, got '%s'" %
                                     (y.func, h.func))
            else:
                coeff *= h

        if kspec is not None:
            h_part[kspec] += coeff
        else:
            i_part += coeff

    for k, coeff in h_part.items():
        h_part[k] = simplify(coeff)

    common = S.One

    for coeff in h_part.values():
        if coeff.is_rational_function(n):
            if not coeff.is_polynomial(n):
                common = lcm(common, coeff.as_numer_denom()[1], n)
        else:
            raise ValueError(
                "Polynomial or rational function expected, got '%s'" % coeff)

    i_numer, i_denom = i_part.as_numer_denom()

    if i_denom.is_polynomial(n):
        common = lcm(common, i_denom, n)

    if common is not S.One:
        for k, coeff in h_part.items():
            numer, denom = coeff.as_numer_denom()
            h_part[k] = numer * quo(common, denom, n)

        i_part = i_numer * quo(common, i_denom, n)

    K_min = min(h_part.keys())

    if K_min < 0:
        K = abs(K_min)

        H_part = defaultdict(lambda: S.Zero)
        i_part = i_part.subs(n, n + K).expand()
        common = common.subs(n, n + K).expand()

        for k, coeff in h_part.items():
            H_part[k + K] = coeff.subs(n, n + K).expand()
    else:
        H_part = h_part

    K_max = max(H_part.keys())
    coeffs = [H_part[i] for i in xrange(K_max + 1)]

    result = rsolve_hyper(coeffs, -i_part, n, symbols=True)

    if result is None:
        return None

    solution, symbols = result

    if init == {} or init == []:
        init = None

    if symbols and init is not None:
        if type(init) is list:
            init = dict([(i, init[i]) for i in xrange(len(init))])

        equations = []

        for k, v in init.items():
            try:
                i = int(k)
            except TypeError:
                if k.is_Function and k.func == y.func:
                    i = int(k.args[0])
                else:
                    raise ValueError("Integer or term expected, got '%s'" % k)
            try:
                eq = solution.limit(n, i) - v
            except NotImplementedError:
                eq = solution.subs(n, i) - v
            equations.append(eq)

        result = solve(equations, *symbols)

        if not result:
            return None
        else:
            solution = solution.subs(result)

    return solution
Example #32
0
def hodge_star(T, g):
    """The calculation actions on the forms of the Hodge operator's.

    Examples:
    =========
    >>> from sympy import symbols, Matrix
    >>> from sympy.tensor.arraypy import Arraypy, TensorArray
    >>> from sympy.tensor.tensor_fields import hodge_star

    >>> x1, x2, x3 = symbols('x1 x2 x3')
    >>> y3 = TensorArray(Arraypy((3, 3, 3)), (-1, -1, -1))
    >>> y3[0, 1, 2] = 3
    >>> y3[0, 2, 1] = -3
    >>> y3[1, 0, 2] = -3
    >>> y3[1, 2, 0] = 3
    >>> y3[2, 0, 1] = 3
    >>> y3[2, 1, 0] = -3
    >>> g = Matrix([[2,1,0],[1,3,0],[0,0,1]])
    >>> print(hodge_star(y3,g))
    96*sqrt(5)/5

    """

    if not isinstance(T, (TensorArray)):
        raise ValueError("The type of tensor must be TensorArray")

    if (len(T.type_pq) == 1 and T.type_pq[0] != 1) or (len(T.type_pq) > 1
                                                       and T.type_pq[0] != 0):
        raise ValueError("The valency of tensor must be (0,q)")
    if T.rank > 1:
        if not is_asymmetric(T):
            raise ValueError("The tensor must be a skew-symmetric")

    # Handling of the metric tensor
    check_metric_tensor(g)
    if isinstance(g, (TensorArray, Arraypy)):
        idx_start_g = g.start_index[0]
        det_g = det(g.to_matrix())
    else:
        idx_start_g = 0
        det_g = det(g)
        g = matrix2tensor(g)

    # The definition of the start index
    idx_start_T = T.start_index[0]

    if idx_start_T != idx_start_g:
        raise ValueError(
            "The start index of the tensor and metric must be equal")

    # 1. Calculating of tensor mu
    n = T.shape[0]  # the dimension of the input array
    k = T.rank
    sqrt_det_g = simplify(sqrt(abs(det_g)))

    valence_list_mu = [(-1) for i in range(n)]
    mu = Arraypy([n, n, idx_start_g]).to_tensor(valence_list_mu)

    for idx in mu.index_list:
        mu[idx] = simplify(sqrt_det_g * sign_permutations(list(idx)))

    # 2. Tensor product mu and T
    uT = tensor_product(mu, T)

    # 3.Convolution by the first k-index and the last k-index
    # low_idx_numbers it is a list with the positions on which are the lower
    # indices
    low_idx_numbers = [i + 1 for i in range(k)]
    # Upping of the first k-lower indices of a tensor
    for position in low_idx_numbers:
        uT = raise_index(uT, g, position)

    # Convolution
    for i in range(k):
        uT = uT.contract(1, k + 1)
        k = k - 1

    return uT
Example #33
0
def diverg(X, args, g=None):
    """Return the divergence of a vector field X. Compute divergence of vector
    field consisting of N elements.

    Examples:
    =========

    >>> from sympy.tensor.tensor_fields import diverg
    >>> from sympy import symbols, cos
    >>> from sympy.matrices import Matrix
    >>> x1, x2, x3 = symbols('x1 x2 x3')

    X is a vector field, args it's a list of symbol arguments of the vector
    field X. It's can be in list, array of arraypy or contravariant tensor:

    >>> X = [x1*x2**3,x2-cos(x3),x3**3-x1]
    >>> arg = [x1, x2, x3]

    g - optional parameter, metric tensor, which can be a matrix "Matrix",
    array of arraypy or covariant tensor:

    >>> g = Matrix([[2,1,0],[1,3,0],[0,0,1]])

    >>> dv = diverg(X,arg,g)
    >>> print(dv)
    x2**3 + 3*x3**2 + 1

    """
    # Handling of a vector of arguments
    check_vector_of_arguments(args)
    if isinstance(args, list):
        idx_args = 0
    else:
        idx_args = args.start_index[0]

    # Handling of the first vector field
    check_the_vector_field(X)
    if isinstance(X, (TensorArray, Arraypy)):
        idx_X = X.start_index[0]
    else:
        idx_X = 0

    if idx_args != idx_X:
        raise ValueError(
            "The start index of vector field and vector of arguments must be \
                    equal")

    # Handling of the metric tensor
    if g is not None:
        if isinstance(g, (TensorArray, Arraypy)):
            g = g.to_matrix()
    else:
        g = eye(len(args))

    # Calculation
    sq = sqrt(abs(det(g)))
    diver = 0
    for k in range(len(args)):
        diver += simplify(1 / sq *
                          sum([diff(X[k + idx_X] * sq, args[k + idx_X])]))
    # Output
    return diver
Example #34
0
    def tangent_lines(self, p):
        """Tangent lines between `p` and the ellipse.

        If `p` is on the ellipse, returns the tangent line through point `p`.
        Otherwise, returns the tangent line(s) from `p` to the ellipse, or
        None if no tangent line is possible (e.g., `p` inside ellipse).

        Parameters
        ==========

        p : Point

        Returns
        =======

        tangent_lines : list with 1 or 2 Lines

        Raises
        ======

        NotImplementedError
            Can only find tangent lines for a point, `p`, on the ellipse.

        See Also
        ========

        sympy.geometry.point.Point, sympy.geometry.line.Line

        Examples
        ========

        >>> from sympy import Point, Ellipse
        >>> e1 = Ellipse(Point(0, 0), 3, 2)
        >>> e1.tangent_lines(Point(3, 0))
        [Line2D(Point2D(3, 0), Point2D(3, -12))]

        """
        p = Point(p, dim=2)
        if self.encloses_point(p):
            return []

        if p in self:
            delta = self.center - p
            rise = (self.vradius**2) * delta.x
            run = -(self.hradius**2) * delta.y
            p2 = Point(simplify(p.x + run), simplify(p.y + rise))
            return [Line(p, p2)]
        else:
            if len(self.foci) == 2:
                f1, f2 = self.foci
                maj = self.hradius
                test = (2 * maj - Point.distance(f1, p) -
                        Point.distance(f2, p))
            else:
                test = self.radius - Point.distance(self.center, p)
            if test.is_number and test.is_positive:
                return []
            # else p is outside the ellipse or we can't tell. In case of the
            # latter, the solutions returned will only be valid if
            # the point is not inside the ellipse; if it is, nan will result.
            x, y = Dummy('x'), Dummy('y')
            eq = self.equation(x, y)
            dydx = idiff(eq, y, x)
            slope = Line(p, Point(x, y)).slope

            # TODO: Replace solve with solveset, when this line is tested
            tangent_points = solve([slope - dydx, eq], [x, y])

            # handle horizontal and vertical tangent lines
            if len(tangent_points) == 1:
                assert tangent_points[0][0] == p.x or tangent_points[0][
                    1] == p.y
                return [Line(p, p + Point(1, 0)), Line(p, p + Point(0, 1))]

            # others
            return [Line(p, tangent_points[0]), Line(p, tangent_points[1])]
Example #35
0
def rsolve_ratio(coeffs, f, n, **hints):
    """
    Given linear recurrence operator `\operatorname{L}` of order `k`
    with polynomial coefficients and inhomogeneous equation
    `\operatorname{L} y = f`, where `f` is a polynomial, we seek
    for all rational solutions over field `K` of characteristic zero.

    This procedure accepts only polynomials, however if you are
    interested in solving recurrence with rational coefficients
    then use ``rsolve`` which will pre-process the given equation
    and run this procedure with polynomial arguments.

    The algorithm performs two basic steps:

        (1) Compute polynomial `v(n)` which can be used as universal
            denominator of any rational solution of equation
            `\operatorname{L} y = f`.

        (2) Construct new linear difference equation by substitution
            `y(n) = u(n)/v(n)` and solve it for `u(n)` finding all its
            polynomial solutions. Return ``None`` if none were found.

    Algorithm implemented here is a revised version of the original
    Abramov's algorithm, developed in 1989. The new approach is much
    simpler to implement and has better overall efficiency. This
    method can be easily adapted to q-difference equations case.

    Besides finding rational solutions alone, this functions is
    an important part of Hyper algorithm were it is used to find
    particular solution of inhomogeneous part of a recurrence.

    Examples
    ========

    >>> from sympy.abc import x
    >>> from sympy.solvers.recurr import rsolve_ratio
    >>> rsolve_ratio([-2*x**3 + x**2 + 2*x - 1, 2*x**3 + x**2 - 6*x,
    ... - 2*x**3 - 11*x**2 - 18*x - 9, 2*x**3 + 13*x**2 + 22*x + 8], 0, x)
    C2*(2*x - 3)/(2*(x**2 - 1))

    References
    ==========

    .. [1] S. A. Abramov, Rational solutions of linear difference
           and q-difference equations with polynomial coefficients,
           in: T. Levelt, ed., Proc. ISSAC '95, ACM Press, New York,
           1995, 285-289

    See Also
    ========

    rsolve_hyper
    """
    f = sympify(f)

    if not f.is_polynomial(n):
        return None

    coeffs = list(map(sympify, coeffs))

    r = len(coeffs) - 1

    A, B = coeffs[r], coeffs[0]
    A = A.subs(n, n - r).expand()

    h = Dummy('h')

    res = resultant(A, B.subs(n, n + h), n)

    if not res.is_polynomial(h):
        p, q = res.as_numer_denom()
        res = quo(p, q, h)

    nni_roots = list(
        roots(res, h, filter='Z', predicate=lambda r: r >= 0).keys())

    if not nni_roots:
        return rsolve_poly(coeffs, f, n, **hints)
    else:
        C, numers = S.One, [S.Zero] * (r + 1)

        for i in xrange(int(max(nni_roots)), -1, -1):
            d = gcd(A, B.subs(n, n + i), n)

            A = quo(A, d, n)
            B = quo(B, d.subs(n, n - i), n)

            C *= Mul(*[d.subs(n, n - j) for j in xrange(0, i + 1)])

        denoms = [C.subs(n, n + i) for i in range(0, r + 1)]

        for i in range(0, r + 1):
            g = gcd(coeffs[i], denoms[i], n)

            numers[i] = quo(coeffs[i], g, n)
            denoms[i] = quo(denoms[i], g, n)

        for i in xrange(0, r + 1):
            numers[i] *= Mul(*(denoms[:i] + denoms[i + 1:]))

        result = rsolve_poly(numers, f * Mul(*denoms), n, **hints)

        if result is not None:
            if hints.get('symbols', False):
                return (simplify(result[0] / C), result[1])
            else:
                return simplify(result / C)
        else:
            return None
Example #36
0
def test_matmul_simplify():
    A = MatrixSymbol('A', 1, 1)
    assert simplify(MatMul(A, ImmutableMatrix([[sin(x)**2 + cos(x)**2]]))) == \
        MatMul(A, ImmutableMatrix([[1]]))
Example #37
0
    def arbitrary_point(self, parameter='t'):
        """A parameterized point on the Ray.

        Parameters
        ==========

        parameter : str, optional
            The name of the parameter which will be used for the parametric
            point. The default value is 't'.

        Returns
        =======

        point : Point

        Raises
        ======

        ValueError
            When `parameter` already appears in the Ray's definition.

        See Also
        ========

        sympy.geometry.point.Point

        Examples
        ========

        >>> from sympy import Ray, Point, Segment, S, simplify, solve
        >>> from sympy.abc import t
        >>> r = Ray(Point(0, 0), Point(2, 3))

        >>> p = r.arbitrary_point(t)

        The parameter `t` used in the arbitrary point maps 0 to the
        origin of the ray and 1 to the end of the ray at infinity
        (which will show up as NaN).

        >>> p.subs(t, 0), p.subs(t, 1)
        (Point(0, 0), Point(oo, oo))

        The unit that `t` moves you is based on the spacing of the
        points used to define the ray.

        >>> p.subs(t, 1/(S(1) + 1)) # one unit
        Point(2, 3)
        >>> p.subs(t, 2/(S(1) + 2)) # two units out
        Point(4, 6)
        >>> p.subs(t, S.Half/(S(1) + S.Half)) # half a unit out
        Point(1, 3/2)

        If you want to be located a distance of 1 from the origin of the
        ray, what value of `t` is needed?

        a) find the unit length and pick t accordingly
        >>> u = Segment(r[0], p.subs(t, S.Half)).length # S.Half = 1/(1 + 1)
        >>> want = 1
        >>> t_need = want/u
        >>> p_want = p.subs(t, t_need/(1 + t_need))
        >>> simplify(Segment(r[0], p_want).length)
        1

        b) find the t that makes the length from origin to p equal to 1
        >>> l = Segment(r[0], p).length
        >>> t_need = solve(l**2 - want**2, t) # use the square to remove abs() if it is there
        >>> t_need = [w for w in t_need if w.n() > 0][0] # take positive t
        >>> p_want = p.subs(t, t_need)
        >>> simplify(Segment(r[0], p_want).length)
        1

        """
        t = _symbol(parameter)
        if t.name in (f.name for f in self.free_symbols):
            raise ValueError(
                'Symbol %s already appears in object and cannot be used as a parameter.'
                % t.name)
        x = simplify(self.p1[0] + t / (1 - t) * (self.p2[0] - self.p1[0]))
        y = simplify(self.p1[1] + t / (1 - t) * (self.p2[1] - self.p1[1]))
        return Point(x, y)
Example #38
0
    def intersection(self, o):
        """The intersection with another geometrical entity.

        Parameters
        ==========

        o : Point or LinearEntity

        Returns
        =======

        intersection : list of geometrical entities

        See Also
        ========

        sympy.geometry.point.Point

        Examples
        ========

        >>> from sympy import Point, Line, Segment
        >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(7, 7)
        >>> l1 = Line(p1, p2)
        >>> l1.intersection(p3)
        [Point(7, 7)]

        >>> p4, p5 = Point(5, 0), Point(0, 3)
        >>> l2 = Line(p4, p5)
        >>> l1.intersection(l2)
        [Point(15/8, 15/8)]

        >>> p6, p7 = Point(0, 5), Point(2, 6)
        >>> s1 = Segment(p6, p7)
        >>> l1.intersection(s1)
        []

        """
        if isinstance(o, Point):
            if o in self:
                return [o]
            else:
                return []
        elif isinstance(o, LinearEntity):
            a1, b1, c1 = self.coefficients
            a2, b2, c2 = o.coefficients
            t = simplify(a1 * b2 - a2 * b1)
            if t == 0:  # are parallel?
                if isinstance(self, Line):
                    if o.p1 in self:
                        return [o]
                    return []
                elif isinstance(o, Line):
                    if self.p1 in o:
                        return [self]
                    return []
                elif isinstance(self, Ray):
                    if isinstance(o, Ray):
                        # case 1, rays in the same direction
                        if self.xdirection == o.xdirection:
                            if self.source[0] < o.source[0]:
                                return [o]
                            return [self]
                        # case 2, rays in the opposite directions
                        else:
                            if o.source in self:
                                if self.source == o.source:
                                    return [self.source]
                                return [Segment(o.source, self.source)]
                            return []
                    elif isinstance(o, Segment):
                        if o.p1 in self:
                            if o.p2 in self:
                                return [o]
                            return [Segment(o.p1, self.source)]
                        elif o.p2 in self:
                            return [Segment(o.p2, self.source)]
                        return []
                elif isinstance(self, Segment):
                    if isinstance(o, Ray):
                        return o.intersection(self)
                    elif isinstance(o, Segment):
                        # A reminder that the points of Segments are ordered
                        # in such a way that the following works. See
                        # Segment.__new__ for details on the ordering.
                        if self.p1 not in o:
                            if self.p2 not in o:
                                # Neither of the endpoints are in o so either
                                # o is contained in this segment or it isn't
                                if o in self:
                                    return [self]
                                return []
                            else:
                                # p1 not in o but p2 is. Either there is a
                                # segment as an intersection, or they only
                                # intersect at an endpoint
                                if self.p2 == o.p1:
                                    return [o.p1]
                                return [Segment(o.p1, self.p2)]
                        elif self.p2 not in o:
                            # p2 not in o but p1 is. Either there is a
                            # segment as an intersection, or they only
                            # intersect at an endpoint
                            if self.p1 == o.p2:
                                return [o.p2]
                            return [Segment(o.p2, self.p1)]

                        # Both points of self in o so the whole segment
                        # is in o
                        return [self]

                # Unknown linear entity
                return []

            # Not parallel, so find the point of intersection
            px = simplify((b1 * c2 - c1 * b2) / t)
            py = simplify((a2 * c1 - a1 * c2) / t)
            inter = Point(px, py)
            if inter in self and inter in o:
                return [inter]
            return []

        return o.intersection(self)
Example #39
0
 def _eval_simplify(self, **kwargs):
     if self.is_Atom:
         return self
     else:
         return self.__class__(*[simplify(x, **kwargs) for x in self.args])
Example #40
0
def linodesolve(A, t, b=None, B=None, type="auto", doit=False):
    r"""
    System of n equations linear first-order differential equations

    Explanation
    ===========

    This solver solves the system of ODEs of the follwing form:

    .. math::
        X'(t) = A(t) X(t) +  b(t)

    Here, $A(t)$ is the coefficient matrix, $X(t)$ is the vector of n independent variables,
    $b(t)$ is the non-homogeneous term and $X'(t)$ is the derivative of $X(t)$

    Depending on the properties of $A(t)$ and $b(t)$, this solver evaluates the solution
    differently.

    When $A(t)$ is constant coefficient matrix and $b(t)$ is zero vector i.e. system is homogeneous,
    the solution is:

    .. math::
        X(t) = \exp(A t) C

    Here, $C$ is a vector of constants and $A$ is the constant coefficient matrix.

    When $A(t)$ is constant coefficient matrix and $b(t)$ is non-zero i.e. system is non-homogeneous,
    the solution is:

    .. math::
        X(t) = e^{A t} ( \int e^{- A t} b \,dt + C)

    When $A(t)$ is coefficient matrix such that its commutative with its antiderivative $B(t)$ and
    $b(t)$ is a zero vector i.e. system is homogeneous, the solution is:

    .. math::
        X(t) = \exp(B(t)) C

    When $A(t)$ is commutative with its antiderivative $B(t)$ and $b(t)$ is non-zero i.e. system is
    non-homogeneous, the solution is:

    .. math::
        X(t) =  e^{B(t)} ( \int e^{-B(t)} b(t) \,dt + C)

    The final solution is the general solution for all the four equations since a constant coefficient
    matrix is always commutative with its antidervative.

    Parameters
    ==========

    A : Matrix
        Coefficient matrix of the system of linear first order ODEs.
    t : Symbol
        Independent variable in the system of ODEs.
    b : Matrix or None
        Non-homogeneous term in the system of ODEs. If None is passed,
        a homogeneous system of ODEs is assumed.
    B : Matrix or None
        Antiderivative of the coefficient matrix. If the antiderivative
        is not passed and the solution requires the term, then the solver
        would compute it internally.
    type : String
        Type of the system of ODEs passed. Depending on the type, the
        solution is evaluated. The type values allowed and the corresponding
        system it solves are: "type1" for constant coefficient homogeneous
        "type2" for constant coefficient non-homogeneous, "type3" for non-constant
        coefficient homogeneous and "type4" for non-constant coefficient non-homogeneous.
        The default value is "auto" which will let the solver decide the correct type of
        the system passed.
    doit : Boolean
        Evaluate the solution if True, default value is False

    Examples
    ========

    To solve the system of ODEs using this function directly, several things must be
    done in the right order. Wrong inputs to the function will lead to incorrect results.

    >>> from sympy import symbols, Function, Eq
    >>> from sympy.solvers.ode.systems import canonical_odes, linear_ode_to_matrix, linodesolve, linodesolve_type
    >>> from sympy.solvers.ode.subscheck import checksysodesol
    >>> f, g = symbols("f, g", cls=Function)
    >>> x, a = symbols("x, a")
    >>> funcs = [f(x), g(x)]
    >>> eqs = [Eq(f(x).diff(x) - f(x), a*g(x) + 1), Eq(g(x).diff(x) + g(x), a*f(x))]

    Here, it is important to note that before we derive the coefficient matrix, it is
    important to get the system of ODEs into the desired form. For that we will use
    :obj:`sympy.solvers.ode.systems.canonical_odes()`.

    >>> eqs = canonical_odes(eqs, funcs, x)
    >>> eqs
    [Eq(Derivative(f(x), x), a*g(x) + f(x) + 1), Eq(Derivative(g(x), x), a*f(x) - g(x))]

    Now, we will use :obj:`sympy.solvers.ode.systems.linear_ode_to_matrix()` to get the coefficient matrix and the
    non-homogeneous term if it is there.

    >>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, x, 1)
    >>> A = -A0

    We have the coefficient matrices and the non-homogeneous term ready. Now, we can use
    :obj:`sympy.solvers.ode.systems.linodesolve_type()` to get the information for the system of ODEs
    to finally pass it to the solver.

    >>> system_info = linodesolve_type(A, x, b=b)
    >>> sol_vector = linodesolve(A, x, b=b, B=system_info['antiderivative'], type=system_info['type'])

    Now, we can prove if the solution is correct or not by using :obj:`sympy.solvers.ode.subscheck.checksysodesol()`

    >>> sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)]
    >>> checksysodesol(eqs, sol)
    (True, [0, 0])

    We can also use the doit method to evaluate the solutions passed by the function.

    >>> sol_vector_evaluated = linodesolve(A, x, b=b, type="type2", doit=True)

    Now, we will look at a system of ODEs which is non-constant.

    >>> eqs = [Eq(f(x).diff(x), f(x) + x*g(x)), Eq(g(x).diff(x), -x*f(x) + g(x))]

    The system defined above is already in the desired form, so we don't have to convert it.

    >>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, x, 1)
    >>> A = -A0

    A user can also pass the commutative antidervative required for type3 and type4 system of ODEs.
    Passing an incorrect one will lead to incorrect results. If the coefficient matrix is not commutative
    with its antiderivative, then :obj:`sympy.solvers.ode.systems.linodesolve_type()` raises a NotImplementedError.
    If it does have a commutative antiderivative, then the function just returns the information about the system.

    >>> system_info = linodesolve_type(A, x, b=b)

    Now, we can pass the antiderivative as an argument to get the solution. If the system information is not
    passed, then the solver will compute the required arguments internally.

    >>> sol_vector = linodesolve(A, x, b=b)

    Once again, we can verify the solution obtained.

    >>> sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)]
    >>> checksysodesol(eqs, sol)
    (True, [0, 0])

    Returns
    =======

    List

    Raises
    ======

    ValueError
        This error is raised when the coefficient matrix, non-homogeneous term
        or the antiderivative, if passed, aren't a matrix or
        don't have correct dimensions
    NonSquareMatrixError
        When the coefficient matrix or its antiderivative, if passed isn't a square
        matrix
    NotImplementedError
        If the coefficient matrix doesn't have a commutative antiderivative

    See Also
    ========

    linear_ode_to_matrix: Coefficient matrix computation function
    canonical_odes: System of ODEs representation change
    linodesolve_type: Getting information about systems of ODEs to pass in this solver

    """

    if not isinstance(A, MatrixBase):
        raise ValueError(
            filldedent('''\
            The coefficients of the system of ODEs should be of type Matrix
        '''))

    if not A.is_square:
        raise NonSquareMatrixError(
            filldedent('''\
            The coefficient matrix must be a square
        '''))

    if b is not None:
        if not isinstance(b, MatrixBase):
            raise ValueError(
                filldedent('''\
                The non-homogeneous terms of the system of ODEs should be of type Matrix
            '''))

        if A.rows != b.rows:
            raise ValueError(
                filldedent('''\
                The system of ODEs should have the same number of non-homogeneous terms and the number of
                equations
            '''))

    if B is not None:
        if not isinstance(B, MatrixBase):
            raise ValueError(
                filldedent('''\
                The antiderivative of coefficients of the system of ODEs should be of type Matrix
            '''))

        if not B.is_square:
            raise NonSquareMatrixError(
                filldedent('''\
                The antiderivative of the coefficient matrix must be a square
            '''))

        if A.rows != B.rows:
            raise ValueError(
                filldedent('''\
                        The coefficient matrix and its antiderivative should have same dimensions
                    '''))

    if not any(type == "type{}".format(i)
               for i in range(1, 5)) and not type == "auto":
        raise ValueError(
            filldedent('''\
                    The input type should be a valid one
                '''))

    n = A.rows

    constants = numbered_symbols(prefix='C', cls=Symbol, start=1)
    Cvect = Matrix(list(next(constants) for _ in range(n)))

    if (type == "type2" or type == "type4") and b is None:
        b = zeros(n, 1)

    if type == "auto":
        system_info = linodesolve_type(A, t, b=b)
        type = system_info["type"]
        B = system_info["antiderivative"]

    if type == "type1" or type == "type2":
        P, J = matrix_exp_jordan_form(A, t)
        P = simplify(P)

        if type == "type1":
            sol_vector = P * (J * Cvect)
        else:
            sol_vector = P * J * (
                (J.inv() * P.inv() * b).applyfunc(lambda x: Integral(x, t)) +
                Cvect)

    else:
        if B is None:
            B, _ = _is_commutative_anti_derivative(A, t)

        if type == "type3":
            sol_vector = B.exp() * Cvect
        else:
            sol_vector = B.exp() * ((
                (-B).exp() * b).applyfunc(lambda x: Integral(x, t)) + Cvect)

    gens = sol_vector.atoms(exp)

    if type != "type1":
        sol_vector = [expand_mul(s) for s in sol_vector]

    sol_vector = [collect(s, ordered(gens), exact=True) for s in sol_vector]

    if doit:
        sol_vector = [s.doit() for s in sol_vector]

    return sol_vector
Example #41
0
def rsolve_hyper(coeffs, f, n, **hints):
    """
    Given linear recurrence operator `\operatorname{L}` of order `k`
    with polynomial coefficients and inhomogeneous equation
    `\operatorname{L} y = f` we seek for all hypergeometric solutions
    over field `K` of characteristic zero.

    The inhomogeneous part can be either hypergeometric or a sum
    of a fixed number of pairwise dissimilar hypergeometric terms.

    The algorithm performs three basic steps:

        (1) Group together similar hypergeometric terms in the
            inhomogeneous part of `\operatorname{L} y = f`, and find
            particular solution using Abramov's algorithm.

        (2) Compute generating set of `\operatorname{L}` and find basis
            in it, so that all solutions are linearly independent.

        (3) Form final solution with the number of arbitrary
            constants equal to dimension of basis of `\operatorname{L}`.

    Term `a(n)` is hypergeometric if it is annihilated by first order
    linear difference equations with polynomial coefficients or, in
    simpler words, if consecutive term ratio is a rational function.

    The output of this procedure is a linear combination of fixed
    number of hypergeometric terms. However the underlying method
    can generate larger class of solutions - D'Alembertian terms.

    Note also that this method not only computes the kernel of the
    inhomogeneous equation, but also reduces in to a basis so that
    solutions generated by this procedure are linearly independent

    Examples
    ========

    >>> from sympy.solvers import rsolve_hyper
    >>> from sympy.abc import x

    >>> rsolve_hyper([-1, -1, 1], 0, x)
    C0*(1/2 + sqrt(5)/2)**x + C1*(-sqrt(5)/2 + 1/2)**x

    >>> rsolve_hyper([-1, 1], 1 + x, x)
    C0 + x*(x + 1)/2

    References
    ==========

    .. [1] M. Petkovsek, Hypergeometric solutions of linear recurrences
           with polynomial coefficients, J. Symbolic Computation,
           14 (1992), 243-264.

    .. [2] M. Petkovsek, H. S. Wilf, D. Zeilberger, A = B, 1996.
    """
    coeffs = list(map(sympify, coeffs))

    f = sympify(f)

    r, kernel, symbols = len(coeffs) - 1, [], set()

    if not f.is_zero:
        if f.is_Add:
            similar = {}

            for g in f.expand().args:
                if not g.is_hypergeometric(n):
                    return None

                for h in similar.keys():
                    if hypersimilar(g, h, n):
                        similar[h] += g
                        break
                else:
                    similar[g] = S.Zero

            inhomogeneous = []

            for g, h in similar.items():
                inhomogeneous.append(g + h)
        elif f.is_hypergeometric(n):
            inhomogeneous = [f]
        else:
            return None

        for i, g in enumerate(inhomogeneous):
            coeff, polys = S.One, coeffs[:]
            denoms = [S.One] * (r + 1)

            s = hypersimp(g, n)

            for j in xrange(1, r + 1):
                coeff *= s.subs(n, n + j - 1)

                p, q = coeff.as_numer_denom()

                polys[j] *= p
                denoms[j] = q

            for j in xrange(0, r + 1):
                polys[j] *= Mul(*(denoms[:j] + denoms[j + 1:]))

            R = rsolve_poly(polys, Mul(*denoms), n)

            if not (R is None or R is S.Zero):
                inhomogeneous[i] *= R
            else:
                return None

            result = Add(*inhomogeneous)
    else:
        result = S.Zero

    Z = Dummy('Z')

    p, q = coeffs[0], coeffs[r].subs(n, n - r + 1)

    p_factors = [z for z in roots(p, n).keys()]
    q_factors = [z for z in roots(q, n).keys()]

    factors = [(S.One, S.One)]

    for p in p_factors:
        for q in q_factors:
            if p.is_integer and q.is_integer and p <= q:
                continue
            else:
                factors += [(n - p, n - q)]

    p = [(n - p, S.One) for p in p_factors]
    q = [(S.One, n - q) for q in q_factors]

    factors = p + factors + q

    for A, B in factors:
        polys, degrees = [], []
        D = A * B.subs(n, n + r - 1)

        for i in xrange(0, r + 1):
            a = Mul(*[A.subs(n, n + j) for j in xrange(0, i)])
            b = Mul(*[B.subs(n, n + j) for j in xrange(i, r)])

            poly = quo(coeffs[i] * a * b, D, n)
            polys.append(poly.as_poly(n))

            if not poly.is_zero:
                degrees.append(polys[i].degree())

        d, poly = max(degrees), S.Zero

        for i in xrange(0, r + 1):
            coeff = polys[i].nth(d)

            if coeff is not S.Zero:
                poly += coeff * Z**i

        for z in roots(poly, Z).keys():
            if z.is_zero:
                continue

            (C, s) = rsolve_poly([polys[i] * z**i for i in xrange(r + 1)],
                                 0,
                                 n,
                                 symbols=True)

            if C is not None and C is not S.Zero:
                symbols |= set(s)

                ratio = z * A * C.subs(n, n + 1) / B / C
                ratio = simplify(ratio)
                # If there is a nonnegative root in the denominator of the ratio,
                # this indicates that the term y(n_root) is zero, and one should
                # start the product with the term y(n_root + 1).
                n0 = 0
                for n_root in roots(ratio.as_numer_denom()[1], n).keys():
                    if (n0 < (n_root + 1)) is True:
                        n0 = n_root + 1
                K = product(ratio, (n, n0, n - 1))
                if K.has(factorial, FallingFactorial, RisingFactorial):
                    K = simplify(K)

                if casoratian(kernel + [K], n, zero=False) != 0:
                    kernel.append(K)

    kernel.sort(key=default_sort_key)
    sk = list(zip(numbered_symbols('C'), kernel))

    if sk:
        for C, ker in sk:
            result += C * ker
    else:
        return None

    if hints.get('symbols', False):
        symbols |= set([s for s, k in sk])
        return (result, list(symbols))
    else:
        return result
Example #42
0
 def _simplify(expr):
     if dom.is_Composite:
         return factor(expr)
     else:
         return simplify(expr)
Example #43
0
def equivalence_hypergeometric(A, B, func):
    # This method for finding the equivalence is only for 2F1 type.
    # We can extend it for 1F1 and 0F1 type also.
    x = func.args[0]

    # making given equation in normal form
    I1 = factor(cancel(A.diff(x) / 2 + A**2 / 4 - B))

    # computing shifted invariant(J1) of the equation
    J1 = factor(cancel(x**2 * I1 + S(1) / 4))
    num, dem = J1.as_numer_denom()
    num = powdenest(expand(num))
    dem = powdenest(expand(dem))

    # this function will compute the different powers of variable(x) in J1.
    # then it will help in finding value of k. k is power of x such that we can express
    # J1 = x**k * J0(x**k) then all the powers in J0 become integers.
    def _power_counting(num):
        _pow = {0}
        for val in num:
            if val.has(x):
                if isinstance(val, Pow) and val.as_base_exp()[0] == x:
                    _pow.add(val.as_base_exp()[1])
                elif val == x:
                    _pow.add(val.as_base_exp()[1])
                else:
                    _pow.update(_power_counting(val.args))
        return _pow

    pow_num = _power_counting((num, ))
    pow_dem = _power_counting((dem, ))
    pow_dem.update(pow_num)

    _pow = pow_dem
    k = gcd(_pow)

    # computing I0 of the given equation
    I0 = powdenest(simplify(factor(((J1 / k**2) - S(1) / 4) / ((x**k)**2))),
                   force=True)
    I0 = factor(cancel(powdenest(I0.subs(x, x**(S(1) / k)), force=True)))
    num, dem = I0.as_numer_denom()

    max_num_pow = max(_power_counting((num, )))
    dem_args = dem.args
    sing_point = []
    dem_pow = []
    # calculating singular point of I0.
    for arg in dem_args:
        if arg.has(x):
            if isinstance(arg, Pow):
                # (x-a)**n
                dem_pow.append(arg.as_base_exp()[1])
                sing_point.append(
                    list(roots(arg.as_base_exp()[0], x).keys())[0])
            else:
                # (x-a) type
                dem_pow.append(arg.as_base_exp()[1])
                sing_point.append(list(roots(arg, x).keys())[0])

    dem_pow.sort()
    # checking if equivalence is exists or not.

    if equivalence(max_num_pow, dem_pow) == "2F1":
        return {'I0': I0, 'k': k, 'sing_point': sing_point, 'type': "2F1"}
    else:
        return None
Example #44
0
def match_2nd_2F1_hypergeometric(I, k, sing_point, func):
    x = func.args[0]
    a = Wild("a")
    b = Wild("b")
    c = Wild("c")
    t = Wild("t")
    s = Wild("s")
    r = Wild("r")
    alpha = Wild("alpha")
    beta = Wild("beta")
    gamma = Wild("gamma")
    delta = Wild("delta")
    # I0 of the standerd 2F1 equation.
    I0 = ((a - b + 1) * (a - b - 1) * x**2 + 2 *
          ((1 - a - b) * c + 2 * a * b) * x + c * (c - 2)) / (4 * x**2 *
                                                              (x - 1)**2)
    if sing_point != [0, 1]:
        # If singular point is [0, 1] then we have standerd equation.
        eqs = []
        sing_eqs = [
            -beta / alpha, -delta / gamma, (delta - beta) / (alpha - gamma)
        ]
        # making equations for the finding the mobius transformation
        for i in range(3):
            if i < len(sing_point):
                eqs.append(Eq(sing_eqs[i], sing_point[i]))
            else:
                eqs.append(Eq(1 / sing_eqs[i], 0))
        # solving above equations for the mobius transformation
        _beta = -alpha * sing_point[0]
        _delta = -gamma * sing_point[1]
        _gamma = alpha
        if len(sing_point) == 3:
            _gamma = (_beta + sing_point[2] * alpha) / (sing_point[2] -
                                                        sing_point[1])
        mob = (alpha * x + beta) / (gamma * x + delta)
        mob = mob.subs(beta, _beta)
        mob = mob.subs(delta, _delta)
        mob = mob.subs(gamma, _gamma)
        mob = cancel(mob)
        t = (beta - delta * x) / (gamma * x - alpha)
        t = cancel(((t.subs(beta, _beta)).subs(delta,
                                               _delta)).subs(gamma, _gamma))
    else:
        mob = x
        t = x

    # applying mobius transformation in I to make it into I0.
    I = I.subs(x, t)
    I = I * (t.diff(x))**2
    I = factor(I)
    dict_I = {x**2: 0, x: 0, 1: 0}
    I0_num, I0_dem = I0.as_numer_denom()
    # collecting coeff of (x**2, x), of the standerd equation.
    # substituting (a-b) = s, (a+b) = r
    dict_I0 = {
        x**2: s**2 - 1,
        x: (2 * (1 - r) * c + (r + s) * (r - s)),
        1: c * (c - 2)
    }
    # collecting coeff of (x**2, x) from I0 of the given equation.
    dict_I.update(
        collect(expand(cancel(I * I0_dem)), [x**2, x], evaluate=False))
    eqs = []
    # We are comparing the coeff of powers of different x, for finding the values of
    # parameters of standerd equation.
    for key in [x**2, x, 1]:
        eqs.append(Eq(dict_I[key], dict_I0[key]))

    # We can have many possible roots for the equation.
    # I am selecting the root on the basis that when we have
    # standard equation eq = x*(x-1)*f(x).diff(x, 2) + ((a+b+1)*x-c)*f(x).diff(x) + a*b*f(x)
    # then root should be a, b, c.

    _c = 1 - factor(sqrt(1 + eqs[2].lhs))
    if not _c.has(Symbol):
        _c = min(list(roots(eqs[2], c)))
    _s = factor(sqrt(eqs[0].lhs + 1))
    _r = _c - factor(sqrt(_c**2 + _s**2 + eqs[1].lhs - 2 * _c))
    _a = (_r + _s) / 2
    _b = (_r - _s) / 2

    rn = {
        'a': simplify(_a),
        'b': simplify(_b),
        'c': simplify(_c),
        'k': k,
        'mobius': mob,
        'type': "2F1"
    }
    return rn
Example #45
0
def solve_linear_system(system, *symbols, **flags):
    """Solve system of N linear equations with M variables, which means
       both Cramer and over defined systems are supported. The possible
       number of solutions is zero, one or infinite. Respectively this
       procedure will return None or dictionary with solutions. In the
       case of over-defined systems all arbitrary parameters are skipped.
       This may cause situation in which an empty dictionary is returned.
       In this case it means all symbols can be assigned arbitrary values.

       Input to this functions is a Nx(M+1) matrix, which means it has
       to be in augmented form. If you prefer to enter N equations and M
       unknowns then use 'solve(Neqs, *Msymbols)' instead. Note: a local
       copy of the matrix is made by this routine so the matrix that is
       passed will not be modified.

       The algorithm used here is fraction-free Gaussian elimination,
       which results, after elimination, in an upper-triangular matrix.
       Then solutions are found using back-substitution. This approach
       is more efficient and compact than the Gauss-Jordan method.

       >>> from sympy import Matrix, solve_linear_system
       >>> from sympy.abc import x, y

       Solve the following system:

              x + 4 y ==  2
           -2 x +   y == 14

       >>> system = Matrix(( (1, 4, 2), (-2, 1, 14)))
       >>> solve_linear_system(system, x, y)
       {x: -6, y: 2}

    """
    matrix = system[:,:]
    syms = list(symbols)

    i, m = 0, matrix.cols-1  # don't count augmentation

    while i < matrix.rows:
        if i == m:
            # an overdetermined system
            if any(matrix[i:,m]):
                return None   # no solutions
            else:
                # remove trailing rows
                matrix = matrix[:i,:]
                break

        if not matrix[i, i]:
            # there is no pivot in current column
            # so try to find one in other columns
            for k in xrange(i+1, m):
                if matrix[i, k]:
                    break
            else:
                if matrix[i, m]:
                    return None   # no solutions
                else:
                    # zero row or was a linear combination of
                    # other rows so now we can safely skip it
                    matrix.row_del(i)
                    continue

            # we want to change the order of colums so
            # the order of variables must also change
            syms[i], syms[k] = syms[k], syms[i]
            matrix.col_swap(i, k)

        pivot_inv = S.One / matrix [i, i]

        # divide all elements in the current row by the pivot
        matrix.row(i, lambda x, _: x * pivot_inv)

        for k in xrange(i+1, matrix.rows):
            if matrix[k, i]:
                coeff = matrix[k, i]

                # subtract from the current row the row containing
                # pivot and multiplied by extracted coefficient
                matrix.row(k, lambda x, j: simplify(x - matrix[i, j]*coeff))

        i += 1

    # if there weren't any problems, augmented matrix is now
    # in row-echelon form so we can check how many solutions
    # there are and extract them using back substitution

    simplified = flags.get('simplified', True)

    if len(syms) == matrix.rows:
        # this system is Cramer equivalent so there is
        # exactly one solution to this system of equations
        k, solutions = i-1, {}

        while k >= 0:
            content = matrix[k, m]

            # run back-substitution for variables
            for j in xrange(k+1, m):
                content -= matrix[k, j]*solutions[syms[j]]

            if simplified:
                solutions[syms[k]] = simplify(content)
            else:
                solutions[syms[k]] = content

            k -= 1

        return solutions
    elif len(syms) > matrix.rows:
        # this system will have infinite number of solutions
        # dependent on exactly len(syms) - i parameters
        k, solutions = i-1, {}

        while k >= 0:
            content = matrix[k, m]

            # run back-substitution for variables
            for j in xrange(k+1, i):
                content -= matrix[k, j]*solutions[syms[j]]

            # run back-substitution for parameters
            for j in xrange(i, m):
                content -= matrix[k, j]*syms[j]

            if simplified:
                solutions[syms[k]] = simplify(content)
            else:
                solutions[syms[k]] = content

            k -= 1

        return solutions
    else:
        return None   # no solutions
Example #46
0
def singularities(expression, symbol):
    """
    Find singularities of a given function.

    Parameters
    ==========

    expression : Expr
        The target function in which singularities need to be found.
    symbol : Symbol
        The symbol over the values of which the singularity in
        expression in being searched for.

    Returns
    =======

    Set
        A set of values for ``symbol`` for which ``expression`` has a
        singularity. An ``EmptySet`` is returned if ``expression`` has no
        singularities for any given value of ``Symbol``.

    Raises
    ======

    NotImplementedError
        The algorithm to find singularities for irrational functions
        has not been implemented yet.

    Notes
    =====

    This function does not find non-isolated singularities
    nor does it find branch points of the expression.

    Currently supported functions are:
        - univariate rational (real or complex) functions

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Mathematical_singularity

    Examples
    ========

    >>> from sympy.calculus.singularities import singularities
    >>> from sympy import Symbol
    >>> x = Symbol('x', real=True)
    >>> y = Symbol('y', real=False)
    >>> singularities(x**2 + x + 1, x)
    EmptySet()
    >>> singularities(1/(x + 1), x)
    {-1}
    >>> singularities(1/(y**2 + 1), y)
    {-I, I}
    >>> singularities(1/(y**3 + 1), y)
    {-1, 1/2 - sqrt(3)*I/2, 1/2 + sqrt(3)*I/2}

    """
    if not expression.is_rational_function(symbol):
        raise NotImplementedError(
            "Algorithms finding singularities for non-rational"
            " functions are not yet implemented.")
    else:
        domain = S.Reals if symbol.is_real else S.Complexes
        return solveset(simplify(1 / expression), symbol, domain)
Example #47
0
def _solve(f, *symbols, **flags):
    """ Return a checked solution for f in terms of one or more of the symbols."""

    if not iterable(f):

        if len(symbols) != 1:
            soln = None
            free = f.free_symbols
            ex = free - set(symbols)
            if len(ex) == 1:
                ex = ex.pop()
                try:
                    # may come back as dict or list (if non-linear)
                    soln = solve_undetermined_coeffs(f, symbols, ex)
                except NotImplementedError:
                    pass
            if not soln is None:
                return soln
            # find first successful solution
            failed = []
            for s in symbols:
                n, d = solve_linear(f, x=[s])
                if n.is_Symbol:
                    soln = {n: cancel(d)}
                    return soln
                failed.append(s)
            for s in failed:
                try:
                    soln = _solve(f, s, **flags)
                    return soln
                except NotImplementedError:
                    pass
            else:
                msg = "No algorithms are implemented to solve equation %s"
                raise NotImplementedError(msg % f)

        symbol = symbols[0]

        # first see if it really depends on symbol and whether there
        # is a linear solution
        f_num, sol = solve_linear(f, x=symbols)
        if not symbol in f_num.free_symbols:
            return []
        elif f_num.is_Symbol:
            return [cancel(sol)]

        strategy = guess_solve_strategy(f, symbol)
        result = False # no solution was obtained

        if strategy == GS_POLY:
            poly = f.as_poly(symbol)
            if poly is None:
                msg = "Cannot solve equation %s for %s" % (f, symbol)
            else:
                # for cubics and quartics, if the flag wasn't set, DON'T do it
                # by default since the results are quite long. Perhaps one could
                # base this decision on a certain critical length of the roots.
                if poly.degree() > 2:
                    flags['simplified'] = flags.get('simplified', False)
                result = roots(poly, cubics=True, quartics=True).keys()

        elif strategy == GS_RATIONAL:
            P, _ = f.as_numer_denom()
            dens = denoms(f, x=symbols)
            try:
                soln = _solve(P, symbol, **flags)
            except NotImplementedError:
                msg = "Cannot solve equation %s for %s" % (P, symbol)
                result = []
            else:
                if dens:
                    # reject any result that makes any denom. affirmatively 0;
                    # if in doubt, keep it
                    result = [s for s in soln if all(not checksol(den, {symbol: s}) for den in dens)]
                else:
                    result = soln

        elif strategy == GS_POLY_CV_1:
            args = list(f.args)
            if isinstance(f, Pow):
                result = _solve(args[0], symbol, **flags)
            elif isinstance(f, Add):
                # we must search for a suitable change of variables
                # collect exponents
                exponents_denom = list()
                for arg in args:
                    if isinstance(arg, Pow):
                        exponents_denom.append(arg.exp.q)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                exponents_denom.append(mul_arg.exp.q)
                assert len(exponents_denom) > 0
                if len(exponents_denom) == 1:
                    m = exponents_denom[0]
                else:
                    # get the LCM of the denominators
                    m = reduce(ilcm, exponents_denom)
                # x -> y**m.
                # we assume positive for simplification purposes
                t = Dummy('t', positive=True)
                f_ = f.subs(symbol, t**m)
                if guess_solve_strategy(f_, t) != GS_POLY:
                    msg = "Could not convert to a polynomial equation: %s" % f_
                    result = []
                else:
                    soln = [s**m for s in _solve(f_, t)]
                    # we might have introduced solutions from another branch
                    # when changing variables; check and keep solutions
                    # unless they definitely aren't a solution
                    result = [s for s in soln if checksol(f, {symbol: s}) is not False]

            elif isinstance(f, Mul):
                result = []
                for m in f.args:
                    result.extend(_solve(m, symbol, **flags) or [])

        elif strategy == GS_POLY_CV_2:
            m = 0
            args = list(f.args)
            if isinstance(f, Add):
                for arg in args:
                    if isinstance(arg, Pow):
                        m = min(m, arg.exp)
                    elif isinstance(arg, Mul):
                        for mul_arg in arg.args:
                            if isinstance(mul_arg, Pow):
                                m = min(m, mul_arg.exp)
            elif isinstance(f, Mul):
                for mul_arg in args:
                    if isinstance(mul_arg, Pow):
                        m = min(m, mul_arg.exp)

            if m and m != 1:
                f_ = simplify(f*symbol**(-m))
                try:
                    sols = _solve(f_, symbol)
                except NotImplementedError:
                    msg = 'Could not solve %s for %s' % (f_, symbol)
                else:
                    # we might have introduced unwanted solutions
                    # when multiplying by x**-m; check and keep solutions
                    # unless they definitely aren't a solution
                    if sols:
                        result = [s for s in sols if checksol(f, {symbol: s}) is not False]
            else:
                msg = 'CV_2 calculated %d but it should have been other than 0 or 1' % m

        elif strategy == GS_PIECEWISE:
            result = set()
            for expr, cond in f.args:
                candidates = _solve(expr, *symbols)
                if isinstance(cond, bool) or cond.is_Number:
                    if not cond:
                        continue

                    # Only include solutions that do not match the condition
                    # of any of the other pieces.
                    for candidate in candidates:
                        matches_other_piece = False
                        for other_expr, other_cond in f.args:
                            if isinstance(other_cond, bool) \
                               or other_cond.is_Number:
                                continue
                            if bool(other_cond.subs(symbol, candidate)):
                                matches_other_piece = True
                                break
                        if not matches_other_piece:
                            result.add(candidate)
                else:
                    for candidate in candidates:
                        if bool(cond.subs(symbol, candidate)):
                            result.add(candidate)

            result = list(result)

        elif strategy == -1:
            raise ValueError('Could not parse expression %s' % f)

        # this is the fallback for not getting any other solution
        if result is False or strategy == GS_TRANSCENDENTAL:
            soln = tsolve(f_num, symbol)
            dens = denoms(f, x=symbols)
            if not dens:
                result = soln
            else:
                # reject any result that makes any denom. affirmatively 0;
                # if in doubt, keep it
                result = [s for s in soln if all(not checksol(den, {symbol: s}) for den in dens)]

        if result is False:
            raise NotImplementedError(msg + "\nNo algorithms are implemented to solve equation %s" % f)

        if flags.get('simplified', True) and strategy != GS_RATIONAL:
            result = map(simplify, result)

        return result
    else:
        if not f:
            return []
        else:

            polys = []

            for g in f:

                poly = g.as_poly(*symbols, **{'extension': True})

                if poly is not None:
                    polys.append(poly)
                else:
                    raise NotImplementedError()

            if all(p.is_linear for p in polys):
                n, m = len(f), len(symbols)
                matrix = zeros((n, m + 1))

                for i, poly in enumerate(polys):
                    for monom, coeff in poly.terms():
                        try:
                            j = list(monom).index(1)
                            matrix[i, j] = coeff
                        except ValueError:
                            matrix[i, m] = -coeff

                # a dictionary of symbols: values or None
                result = solve_linear_system(matrix, *symbols, **flags)
                return result
            else:
                # a list of tuples, T, where T[i] [j] corresponds to the ith solution for symbols[j]
                result = solve_poly_system(polys)
                return result
Example #48
0
def checksol(f, symbol, sol=None, **flags):
    """Checks whether sol is a solution of equation f == 0.

    Input can be either a single symbol and corresponding value
    or a dictionary of symbols and values.

    Examples:
    ---------

       >>> from sympy import symbols
       >>> from sympy.solvers import checksol
       >>> x, y = symbols('x,y')
       >>> checksol(x**4-1, x, 1)
       True
       >>> checksol(x**4-1, x, 0)
       False
       >>> checksol(x**2 + y**2 - 5**2, {x:3, y: 4})
       True

       None is returned if checksol() could not conclude.

       flags:
           'numerical=True (default)'
               do a fast numerical check if f has only one symbol.
           'minimal=True (default is False)'
               a very fast, minimal testing.
           'warning=True (default is False)'
               print a warning if checksol() could not conclude.
           'simplified=True (default)'
               solution should be simplified before substituting into function
               and function should be simplified after making substitution.
           'force=True (default is False)'
               make positive all symbols without assumptions regarding sign.
    """

    if sol is not None:
        sol = {symbol: sol}
    elif isinstance(symbol, dict):
        sol = symbol
    else:
        msg = 'Expecting sym, val or {sym: val}, None but got %s, %s'
        raise ValueError(msg % (symbol, sol))

    if hasattr(f, '__iter__') and hasattr(f, '__len__'):
        if not f:
            raise ValueError('no functions to check')
        rv = set()
        for fi in f:
            check = checksol(fi, sol, **flags)
            if check is False:
                return False
            rv.add(check)
        if None in rv: # rv might contain True and/or None
            return None
        assert len(rv) == 1 # True
        return True

    if isinstance(f, Poly):
        f = f.as_expr()
    elif isinstance(f, Equality):
        f = f.lhs - f.rhs

    if not f:
        return True

    if not f.has(*sol.keys()):
        return False

    attempt = -1
    numerical = flags.get('numerical', True)
    while 1:
        attempt += 1
        if attempt == 0:
            val = f.subs(sol)
        elif attempt == 1:
            if not val.atoms(Symbol) and numerical:
                # val is a constant, so a fast numerical test may suffice
                if val not in [S.Infinity, S.NegativeInfinity]:
                    # issue 2088 shows that +/-oo chops to 0
                    val = val.evalf(36).n(30, chop=True)
        elif attempt == 2:
            if flags.get('minimal', False):
                return
            # the flag 'simplified=False' is used in solve to avoid
            # simplifying the solution. So if it is set to False there
            # the simplification will not be attempted here, either. But
            # if the simplification is done here then the flag should be
            # set to False so it isn't done again there.
            if flags.get('simplified', True):
                for k in sol:
                    sol[k] = simplify(sympify(sol[k]))
                flags['simplified'] = False
                val = simplify(f.subs(sol))
            if flags.get('force', False):
                val = posify(val)[0]
        elif attempt == 3:
            val = powsimp(val)
        elif attempt == 4:
            val = cancel(val)
        elif attempt == 5:
            val = val.expand()
        elif attempt == 6:
            val = together(val)
        elif attempt == 7:
            val = powsimp(val)
        else:
            break
        if val.is_zero:
            return True
        elif attempt > 0 and numerical and val.is_nonzero:
            return False

    if flags.get('warning', False):
        print("Warning: could not verify solution %s." % sol)