Repository: sympy/sympy
File: sympy/functions/special/bsplines.py (Python)

Code before:
    This function returns a piecewise function such that each part is a polynomial of degree
    at most ``d`` and the value at each number in X is the corresponding number in Y.
    The degree ``d`` must be at least 1. The values listed in X must be strictly increasing.

    Examples
    ========

    >>> from sympy import interpolating_spline
    >>> from sympy.abc import x
    >>> interpolating_spline(1, x, [1, 2, 4, 7], [3, 6, 5, 7])
    Piecewise((3*x, (x >= 1) & (x <= 2)), (-x/2 + 7, (x >= 2) & (x <= 4)), (2*x/3 + 7/3, (x >= 4) & (x <= 7)))
    >>> interpolating_spline(3, x, [-2, 0, 1, 3, 4], [4, 2, 1, 1, 3])
    Piecewise((-x**3/36 - x**2/36 - 17*x/18 + 2, (x >= -2) & (x <= 1)), (5*x**3/36 - 13*x**2/36 - 11*x/18 + 7/3, (x >= 1) & (x <= 4)))

    See Also
    ========

    bsplines_basis_set, sympy.polys.specialpolys.interpolating_poly
    """
    from sympy import symbols, Number, Dummy, Rational
    from sympy.solvers.solveset import linsolve
    from sympy.matrices.dense import Matrix

    # Input sanitization
    d = sympify(d)
    if not(d.is_integer and d.is_positive):
        raise ValueError("Spline degree must be a positive integer, not %s" % d)
    if len(X) != len(Y):
        raise ValueError('Number of X and Y co-ordinates passed not equal')
    if len(X) < d+1:
        raise ValueError('Degree must be less than the number of control points')
    if not all(a < b for a, b in zip(X, X[1:])):
        raise ValueError('The x-coordinates must be strictly increasing')

    # Evaluating knots value
    if d.is_odd:
        j = (d+1) // 2
        interior_knots = X[j:-j]
    else:
        j = d // 2
        interior_knots = [Rational(a+b, 2) for a, b in zip(X[j:-j-1], X[j+1:-j])]

    knots = [X[0]] * (d+1) + list(interior_knots) + [X[-1]] * (d+1)

    basis = bspline_basis_set(d, knots, x)

    A = [[b.subs(x, v) for b in basis] for v in X]

    coeff = linsolve((Matrix(A), Matrix(Y)), symbols('c0:{}'.format(len(X)), cls=Dummy))
    coeff = list(coeff)[0]
    intervals = set([c for b in basis for (e, c) in b.args if c != True])

Review comment (suggestion):
I suspect that you intend d to be an Integer...`var('x', integer=True, positive=True)` would pass these tests.

Code after:

    This function returns a piecewise function such that each part is
    a polynomial of degreeat most ``d`` .
    The degree ``d`` must be at least 1. The values listed in X must
    be strictly increasing.

    Examples
    ========

    >>> from sympy import interpolating_spline
    >>> from sympy.abc import x
    >>> interpolating_spline(1, x, [1, 2, 4, 7], [3, 6, 5, 7])
    Piecewise((3*x, (x >= 1) & (x <= 2)),
            (-x/2 + 7, (x >= 2) & (x <= 4)),
            (2*x/3 + 7/3, (x >= 4) & (x <= 7)))
    >>> interpolating_spline(3, x, [-2, 0, 1, 3, 4], [4, 2, 1, 1, 3])
    Piecewise((-x**3/36 - x**2/36 - 17*x/18 + 2, (x >= -2) & (x <= 1)),
            (5*x**3/36 - 13*x**2/36 - 11*x/18 + 7/3, (x >= 1) & (x <= 4)))

    See Also
    ========

    bsplines_basis_set, sympy.polys.specialpolys.interpolating_poly
    """
    from sympy import symbols, Number, Dummy, Rational
    from sympy.solvers.solveset import linsolve
    from sympy.matrices.dense import Matrix

    # Input sanitization
    d = sympify(d)
    if not(d.is_Integer and d.is_positive):
        raise ValueError("Spline degree must be a positive integer, not %s" % d)
    if len(X) != len(Y):
        raise ValueError('Number of X and Y coordinates passed not equal')
    if len(X) < d + 1:
        raise ValueError('Degree must be less than the number of control points')
    if not all(a < b for a, b in zip(X, X[1:])):
        raise ValueError('The x-coordinates must be strictly increasing')

    # Evaluating knots value
    if d.is_odd:
        j = (d + 1) // 2
        interior_knots = X[j:-j]
    else:
        j = d // 2
        interior_knots = [Rational(a + b, 2) for a, b in zip(X[j:-j - 1], X[j + 1:-j])]

    knots = [X[0]] * (d + 1) + list(interior_knots) + [X[-1]] * (d + 1)

    basis = bspline_basis_set(d, knots, x)