Beispiel #1
0
def test_grad_gtnsr():
    x1, x2, x3 = symbols('x1 x2 x3')
    f = x1**2 * x2 + sin(x2 * x3 - x2)
    var1 = [x1, x2, x3]

    k1 = Arraypy([1, 3, 0]).to_tensor(1)
    k1[0] = x1
    k1[1] = x2
    k1[2] = x3

    # g задано tensor, индекс с 1 и var-list
    a = Arraypy([2, 3, 1])
    b = a.to_tensor((-1, -1))
    b[1, 1] = 2
    b[1, 2] = 1
    b[1, 3] = 0
    b[2, 1] = 1
    b[2, 2] = 3
    b[2, 3] = 0
    b[3, 1] = 0
    b[3, 2] = 0
    b[3, 3] = 1

    res_ar = Arraypy([1, 3, 1])
    res_ar[1] = -x1**2 / 5 + 6 * x1 * x2 / 5 - (x3 - 1) * cos(x2 * x3 - x2) / 5
    res_ar[2] = 2 * x1**2 / 5 - 2 * x1 * x2 / \
        5 + cos(x2 * x3 - x2) * 2 * (x3 - 1) / 5
    res_ar[3] = x2 * cos(x2 * x3 - x2)
    res_ten = res_ar.to_tensor(1)

    res_ar1 = Arraypy([1, 3, 0])
    res_ar1[0] = 2 * x1 * x2
    res_ar1[1] = x1**2 + (x3 - 1) * cos(x2 * x3 - x2)
    res_ar1[2] = x2 * cos(x2 * x3 - x2)

    assert str(
        grad(f, var1, b, 'l')
    ) == '[-x1**2/5 + 6*x1*x2/5 - (x3 - 1)*cos(x2*x3 - x2)/5, 2*x1**2/5 - 2*x1*x2/5 + 2*(x3 - 1)*cos(x2*x3 - x2)/5, x2*cos(x2*x3 - x2)]'
    assert isinstance(grad(f, var1, b, 'l'), list)

    assert grad(f, var1, b, 'a') == res_ar
    assert isinstance(grad(f, var1, b, 'a'), Arraypy)
    assert grad(f, k1, output_type='a') == res_ar1
    assert isinstance(grad(f, k1, output_type='a'), Arraypy)

    assert grad(f, var1, b, 't') == res_ten
    assert isinstance(grad(f, var1, b, 't'), TensorArray)
    assert grad(f, var1, b, 't').type_pq == (1, 0)
    assert grad(f, var1, b) == res_ten
    assert isinstance(grad(f, var1, b, 't'), TensorArray)
    assert grad(f, var1, b, 't').type_pq == (1, 0)
Beispiel #2
0
def test_grad_varlist():
    x1, x2, x3 = symbols('x1 x2 x3')

    f = x1**2 * x2 + sin(x2 * x3 - x2)
    var1 = [x1, x2, x3]

    res_ar1 = Arraypy([1, 3, 0])
    res_ar1[0] = 2 * x1 * x2
    res_ar1[1] = x1**2 + (x3 - 1) * cos(x2 * x3 - x2)
    res_ar1[2] = x2 * cos(x2 * x3 - x2)
    res_ten1 = res_ar1.to_tensor(1)

    res_ar = Arraypy([1, 3, 0])
    res_ar[0] = -x1**2 / 5 + 6 * x1 * x2 / 5 - (x3 - 1) * cos(x2 * x3 - x2) / 5
    res_ar[1] = 2 * x1**2 / 5 - 2 * x1 * x2 / \
        5 + cos(x2 * x3 - x2) * 2 * (x3 - 1) / 5
    res_ar[2] = x2 * cos(x2 * x3 - x2)
    res_ten = res_ar.to_tensor(1)

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

    assert grad(f, var1, output_type='l') == [
        2 * x1 * x2, x1**2 + (x3 - 1) * cos(x2 * x3 - x2),
        x2 * cos(x2 * x3 - x2)
    ]
    assert isinstance(grad(f, var1, output_type='l'), list)

    assert grad(f, var1) == [
        2 * x1 * x2, x1**2 + (x3 - 1) * cos(x2 * x3 - x2),
        x2 * cos(x2 * x3 - x2)
    ]
    assert isinstance(grad(f, var1), list)

    assert grad(f, var1, output_type='a') == res_ar1
    assert isinstance(grad(f, var1, output_type='t'), Arraypy)

    assert grad(f, var1, output_type='t') == res_ten1
    assert isinstance(grad(f, var1, output_type='t'), TensorArray)
    assert grad(f, var1, output_type='t').type_pq == (1, 0)

    assert str(
        grad(f, var1, g, output_type='l')
    ) == '[-x1**2/5 + 6*x1*x2/5 - (x3 - 1)*cos(x2*x3 - x2)/5, 2*x1**2/5 - 2*x1*x2/5 + 2*(x3 - 1)*cos(x2*x3 - x2)/5, x2*cos(x2*x3 - x2)]'
    assert isinstance(grad(f, var1, g, output_type='l'), list)

    assert grad(f, var1, g, output_type='a') == res_ar
    assert isinstance(grad(f, var1, g, output_type='a'), Arraypy)

    assert grad(f, var1, g, output_type='t') == res_ten
    assert isinstance(grad(f, var1, g, output_type='t'), TensorArray)
    assert grad(f, var1, g, output_type='t').type_pq == (1, 0)
Beispiel #3
0
def test_grad_gm_vl():
    x1, x2, x3 = symbols('x1 x2 x3')
    f = x1**2 * x2 + sin(x2 * x3 - x2)
    var1 = [x1, x2, x3]
    g = Matrix([[2, 1, 0], [1, 3, 0], [0, 0, 1]])

    k0 = Arraypy([1, 3, 1]).to_tensor(1)
    k0[1] = x1
    k0[2] = x2
    k0[3] = x3

    res_ar = Arraypy([1, 3, 0])
    res_ar[0] = -x1**2 / 5 + 6 * x1 * x2 / 5 - (x3 - 1) * cos(x2 * x3 - x2) / 5
    res_ar[1] = 2 * x1**2 / 5 - 2 * x1 * x2 / \
        5 + cos(x2 * x3 - x2) * 2 * (x3 - 1) / 5
    res_ar[2] = x2 * cos(x2 * x3 - x2)
    res_ten = res_ar.to_tensor(1)

    assert str(
        grad(f, k0, g, 'l')
    ) == '[-x1**2/5 + 6*x1*x2/5 - (x3 - 1)*cos(x2*x3 - x2)/5, 2*x1**2/5 - 2*x1*x2/5 + 2*(x3 - 1)*cos(x2*x3 - x2)/5, x2*cos(x2*x3 - x2)]'
    assert isinstance(grad(f, k0, g, 'l'), list)

    assert grad(f, k0, g, 'a') == res_ar
    assert isinstance(grad(f, k0, g, 'a'), Arraypy)

    assert grad(f, k0, g, 't') == res_ten
    assert isinstance(grad(f, k0, g, 't'), TensorArray)
    assert grad(f, k0, g, 't').type_pq == (1, 0)
def wedgearray2tensor(B):
    """Function takes the Wedge_array(or dictionary) and creates a full skew
    array.

    Examples:
    =========
    >>> from sympy import symbols
    >>> from sympy.tensor.arraypy import Arraypy, TensorArray
    >>> from sympy.tensor.tensor_fields import tensor2wedgearray, \
    wedgearray2tensor

    >>> x1, x2, x3 = symbols('x1 x2 x3')
    >>> y2 = TensorArray(Arraypy((3, 3)), (-1, -1))
    >>> y2[0, 1] = x3
    >>> y2[0, 2] = -x2
    >>> y2[1, 0] = -x3
    >>> y2[1, 2] = x1
    >>> y2[2, 0] = x2
    >>> y2[2, 1] = -x1
    >>> A=tensor2wedgearray(y2)
    >>> wdg=wedgearray2tensor(A)
    >>> print(wdg)
    0  x3  -x2
    -x3  0  x1
    x2  -x1  0

    """
    if isinstance(B, Wedge_array):
        B = B._output
    else:
        raise TypeError('Input tensor must be of Wedge_array or dict type')

    list_indices = sorted(B.keys())
    # (min_index, max_index) - the range of indexes
    max_index = max(max(list_indices))
    # for the start index of arraypy
    min_index = min(min(list_indices))
    # shape output array
    rank = len(list_indices[0])

    # Creating the output array
    arr = Arraypy([rank, max_index - min_index + 1, min_index])
    valence_list = [(-1) for k in range(max_index - min_index)]
    tensor = arr.to_tensor(valence_list)

    for key, value in B.items():
        tensor[key] = value
        # multiply by the sign of the permutation
        for p in permutations(list(key)):
            tensor[p] = sign_permutations(list(p)) * value

    return tensor
Beispiel #5
0
def wedgearray2tensor(B):
    """Function takes the Wedge_array(or dictionary) and creates a full skew
    array.

    Examples:
    =========
    >>> from sympy import symbols
    >>> from sympy.tensor.arraypy import Arraypy, TensorArray
    >>> from sympy.tensor.tensor_fields import tensor2wedgearray, \
    wedgearray2tensor

    >>> x1, x2, x3 = symbols('x1 x2 x3')
    >>> y2 = TensorArray(Arraypy((3, 3)), (-1, -1))
    >>> y2[0, 1] = x3
    >>> y2[0, 2] = -x2
    >>> y2[1, 0] = -x3
    >>> y2[1, 2] = x1
    >>> y2[2, 0] = x2
    >>> y2[2, 1] = -x1
    >>> A=tensor2wedgearray(y2)
    >>> wdg=wedgearray2tensor(A)
    >>> print(wdg)
    0  x3  -x2
    -x3  0  x1
    x2  -x1  0

    """
    if isinstance(B, Wedge_array):
        B = B._output
    else:
        raise TypeError('Input tensor must be of Wedge_array or dict type')

    list_indices = sorted(B.keys())
    # (min_index, max_index) - the range of indexes
    max_index = max(max(list_indices))
    # for the start index of arraypy
    min_index = min(min(list_indices))
    # shape output array
    rank = len(list_indices[0])

    # Creating the output array
    arr = Arraypy([rank, max_index - min_index + 1, min_index])
    valence_list = [(-1) for k in range(max_index - min_index)]
    tensor = arr.to_tensor(valence_list)

    for key, value in B.items():
        tensor[key] = value
        # multiply by the sign of the permutation
        for p in permutations(list(key)):
            tensor[p] = sign_permutations(list(p)) * value

    return tensor
def ricci(riemann, var, type_output='t'):
    """Return the tensor Ricci of type (-1, -1), is symmetric tensor
    for given Riemann curvature tensor.

    Examples:
    =========

    >>> from sympy.tensor.riemannian_geometry import ricci, riemann
    >>> from sympy.tensor.arraypy import Arraypy, TensorArray
    >>> from sympy import symbols, cos
    >>> x1, x2 = symbols('x1, x2')

    var it's a list of symbolic arguments. May be a list, one-dimensional
    arraypy or one-dimensional tensor with valence of indices (+1):

    >>> var = [x1, x2]

    g it's a metric tensor must be symmetric matrix, arraypy or tensor
    with valence indices (-1, -1):

    >>> A = Arraypy((2,2))
    >>> g = TensorArray(A,(-1,-1))
    >>> g[0,0] = cos(x2)**2
    >>> g[0,1] = 0
    >>> g[1,0] = 0
    >>> g[1,1] = 1

    riemann it's a Riemann curvature tensor must be symmetric matrix,
    arraypy or tensor with valences indices (-1, -1, -1, 1):

    >>> cur = riemann(g, var, 't')

    type_output it's optional parameter function, indicating the type of calculation
    result and receiving the character or string value:
    - symbol 't' means that the type of the result will match TensorArray;
    - symbol 'a' means that the type of the result will be Arraypy;
    - default function takes a parameter 't', so that the result will be a TensorArray.

    The Ricci tensor:
    >>> r = ricci(cur, var, 't')
    >>> print(r)
    cos(x2)**2  0
    0  1
    >>> r.type_pq
    (0, 2)
    """
    # Handling of input vector of arguments - var
    if not isinstance(var, (list, Arraypy, TensorArray)):
        raise TypeError(
            'The type of vector of arguments must be a list, Arraypy or TensorArray')
    if isinstance(var, (TensorArray, Arraypy)):
        if len(var.shape) != 1:
            raise ValueError("The dimension of vector of arguments must be 1")
        if isinstance(var, TensorArray):
            if not var.type_pq == (1, 0):
                raise ValueError(
                    'The valence of vector of arguments must be (+1)')
    if isinstance(var, (TensorArray, Arraypy)):
        var = var.to_list()

    # Definition of number of variables
    n = len(var)

    # Handling of a input argument Riemann curvature tensor - riemann
    if not isinstance(riemann, (Matrix, Arraypy, TensorArray)):
        raise TypeError(
            'The type of Riemann curvature tensor must be Matrix, Arraypy or TensorArray')
    else:
        if isinstance(riemann, (Arraypy, TensorArray)):
            if isinstance(riemann, TensorArray):
                if not riemann.type_pq == (1, 3):
                    raise ValueError(
                        'The valence of Riemann curvature tensor must be (1, -1, -1, -1)')
                if not (
                    riemann.start_index.count(
                        riemann.start_index[0]) == 4):
                    raise ValueError(
                        'The starting indices of Riemann curvature tensor must be identical')
            idx_start = riemann.start_index[0]
        else:
            idx_start = 0

    # The definition of diapason changes in an index
    [n1, n2, n3, n4] = riemann.shape
    if not n == n1:
        raise ValueError(
            'The rank of the Riemann curvature tensor does not coincide with the number of variables.')

    indices = range(idx_start, idx_start + n)

    # Creating of output array with new indices
    Ri = Arraypy([2, n, idx_start])

    # Calculation
    for j in indices:
        for k in indices:
            Ri[j, k] = sum([riemann[i, j, k, i] for i in indices])

    # Handling of an output array
    if type_output == str('t') or type_output == Symbol('t'):
        ricci = Ri.to_tensor((-1, -1))
    elif type_output == str('a') or type_output == Symbol('a'):
        ricci = Ri
    else:
        raise ValueError(
            "The parameter of type output result must 'a' - Arraypy or 't' and None - TensorArray.")

    # Output
    return ricci
def riemann(g, var, type_output='t'):
    """Return the Riemann curvature tensor of type (1, -1, -1, -1)
    for the given metric tensor.

    Examples:
    =========

    >>> from sympy.tensor.riemannian_geometry import riemann
    >>> from sympy.tensor.arraypy import Arraypy, TensorArray
    >>> from sympy import symbols, cos
    >>> x1, x2 = symbols('x1, x2')

    var it's a list of symbolic arguments. May be a list, one-dimensional
    arraypy or one-dimensional tensor with valence of indices (+1):

    >>> var = [x1, x2]

    g it's a metric tensor must be symmetric matrix, arraypy or tensor
    with valence indices (-1, -1):

    >>> A = Arraypy((2, 2))
    >>> g = TensorArray(A,(-1, -1))
    >>> g[0,0] = cos(x2)**2
    >>> g[0,1] = 0
    >>> g[1,0] = 0
    >>> g[1,1] = 1

    type_output it's optional parameter function, indicating the type of calculation
    result and receiving the character or string value:
    - symbol 't' means that the type of the result will match TensorArray;
    - symbol 'a' means that the type of the result will be Arraypy;
    - default function takes a parameter 't', so that the result will be a TensorArray.

    The curvature tensor:
    >>> r = riemann(g, var, 'a')
    >>> print(r)
    0  0
    0  0
    0  -cos(x2)**2
    1  0
    0  cos(x2)**2
    -1  0
    0  0
    0  0

    """
    # Handling of input vector of arguments - var
    if not isinstance(var, (list, Arraypy, TensorArray)):
        raise TypeError(
            'The type of vector of arguments must be a list, Arraypy or TensorArray')
    if isinstance(var, (TensorArray, Arraypy)):
        if len(var.shape) != 1:
            raise ValueError("The dimension of vector of arguments must be 1")
        if isinstance(var, TensorArray):
            if not var.type_pq == (1, 0):
                raise ValueError(
                    'The valence of vector of arguments must be (+1)')
    if isinstance(var, (TensorArray, Arraypy)):
        var = var.to_list()

    # Definition of number of variables
    n = len(var)

    # Handling of a input argument - metric tensor g
    if not isinstance(g, (Matrix, Arraypy, TensorArray)):
        raise TypeError(
            'The type of metric tensor must be Matrix, TensorArray or Arraypy')
    else:
        if isinstance(g, (Arraypy, TensorArray)):
            if isinstance(g, TensorArray):
                if not g.type_pq == (0, 2):
                    raise ValueError(
                        'The valence of metric tensor must be (-1,-1)')
            if not is_symmetric(g):
                raise ValueError('The metric tensor must be symmetric.')
            if not (g.start_index[0] == g.start_index[1]):
                raise ValueError(
                    'The starting indices of metric tensor must be identical')
            idx_start = g.start_index[0]
        elif isinstance(g, Matrix):
            if not g.is_symmetric():
                raise ValueError('The metric tensor must be symmetric.')
            idx_start = 0

    # The definition of diapason changes in an index
    [n1, n2] = g.shape
    if not n == n1:
        raise ValueError(
            'The rank of the metric tensor does not coincide with the number of variables.')

    indices = range(idx_start, idx_start + n)

    # Creating of output array with new indices
    R = Arraypy([4, n, idx_start])
    ch_2 = christoffel_2(g, var)

    # Calculation
    for i in indices:
        for j in indices:
            for k in indices:
                for l in indices:
                    R[i,
                      j,
                      k,
                      l] = diff(ch_2[j,
                                     k,
                                     l],
                                var[i - idx_start]) - diff(ch_2[i,
                                                                k,
                                                                l],
                                                           var[j - idx_start]) + sum([ch_2[i,
                                                                                           p,
                                                                                           l] * ch_2[j,
                                                                                                     k,
                                                                                                     p] - ch_2[j,
                                                                                                               p,
                                                                                                               l] * ch_2[i,
                                                                                                                         k,
                                                                                                                         p] for p in indices])

    # Handling of an output array
    if type_output == str('t') or type_output == Symbol('t'):
        riemann = R.to_tensor((1, -1, -1, -1))
    elif type_output == str('a') or type_output == Symbol('a'):
        riemann = R
    else:
        raise ValueError(
            "The parameter of type output result must 'a' - Arraypy or 't' and None - TensorArray.")

    # Output
    return riemann
def covar_der_XY(X, Y, g, var, type_output='t'):
    """Return the covariant derivative the vector field along another field.

    Examples:
    =========

    >>> from sympy.tensor.riemannian_geometry import covar_der_XY
    >>> from sympy.tensor.arraypy import Arraypy, TensorArray
    >>> from sympy import symbols, cos
    >>> x1, x2 = symbols('x1, x2')

    var it's a list of symbolic arguments. May be a list, one-dimensional arraypy
    or one-dimensional tensor with valence of indices (+1):

    >>> var = [x1, x2]

    g it's a metric tensor must be symmetric matrix, arraypy or tensor
    with valences indices (-1, -1):

    >>> A = Arraypy((2, 2))
    >>> g = TensorArray(A,(-1, -1))
    >>> g[0,0] = cos(x2)**2
    >>> g[0,1] = 0
    >>> g[1,0] = 0
    >>> g[1,1] = 1

    X, Y it's vector fields may be lists, one-dimensional arraypy,
    or one-dimensional tensor indices with valences (+ 1):

    >>> X = [x1 * x2**3, x1 - cos(x2)]
    >>> Y = [1, 2]

    type_output it's optional parameter function, indicating the type of calculation
    result and receiving the character or string value:
    - symbol 't' means that the type of the result will match TensorArray;
    - symbol 'a' means that the type of the result will be Arraypy;
    - default function takes a parameter 't', so that the result will be a TensorArray.

    The covariant derivative along another vector field:
    >>> c_v_XY = covar_der_XY(X, Y, g, var, 't')
    >>> print(c_v_XY)
    -2*x1*x2**3*sin(x2)/cos(x2) + 6*x1*x2**2 + x2**3 - (x1 - cos(x2))*sin(x2)/cos(x2) \
    x1*x2**3*sin(x2)*cos(x2) + 2*sin(x2) + 1

    """
    # Handling of input vector of arguments - var
    if not isinstance(var, (list, Arraypy, TensorArray)):
        raise TypeError(
            'The type of vector of arguments must be a list, Arraypy or TensorArray')
    if isinstance(var, (TensorArray, Arraypy)):
        if len(var.shape) != 1:
            raise ValueError("The dimension of vector of arguments must be 1!")
        if isinstance(var, TensorArray):
            if not var.type_pq == (1, 0):
                raise ValueError(
                    'The valence of vector of arguments must be (+1)')
    if isinstance(var, (TensorArray, Arraypy)):
        var = var.to_list()

    # Definition of number of variables
    n = len(var)

    # Handling of a input argument - metric tensor g
    if not isinstance(g, (Matrix, Arraypy, TensorArray)):
        raise TypeError(
            'The type of metric tensor must be Matrix, TensorArray or Arraypy')
    else:
        if isinstance(g, (Arraypy, TensorArray)):
            if isinstance(g, TensorArray):
                if not g.type_pq == (0, 2):
                    raise ValueError(
                        'The valence of metric tensor must be (-1,-1)')
            if not is_symmetric(g):
                raise ValueError('The metric tensor must be symmetric.')
            if not (g.start_index[0] == g.start_index[1]):
                raise ValueError(
                    'The starting indices of metric tensor must be identical')
            idx_g = g.start_index[0]
        elif isinstance(g, Matrix):
            if not g.is_symmetric():
                raise ValueError('The metric tensor must be symmetric.')
            idx_g = 0

    # Handling of a input argument - vector field X
    if not isinstance(X, (list, Arraypy, TensorArray)):
        raise TypeError(
            'The type of vector field must be list, TensorArray or Arraypy')
    else:
        if isinstance(X, (Arraypy, TensorArray)):
            if len(X.shape) != 1:
                raise ValueError("The dimension of vector field must be 1")
            if isinstance(X, TensorArray):
                if not X.type_pq == (1, 0):
                    raise ValueError(
                        'The valence of vector field must be (+1)')
            idx_X = X.start_index[0]
        elif isinstance(X, list):
            idx_X = 0

    # Handling of a input argument - vector field Y
    if not isinstance(Y, (list, Arraypy, TensorArray)):
        raise TypeError(
            'The type of vector field must be list, TensorArray or Arraypy')
    else:
        if isinstance(Y, (Arraypy, TensorArray)):
            if len(Y.shape) != 1:
                raise ValueError("The dimension of vector field must be 1")
            if isinstance(Y, TensorArray):
                if not Y.type_pq == (1, 0):
                    raise ValueError(
                        'The valence of vector field must be (+1)')
            idx_Y = Y.start_index[0]
        elif isinstance(Y, list):
            idx_Y = 0

    [n1, n2] = g.shape
    if not len(X) == len(Y):
        raise ValueError('The vectors must be identical length')
    elif not idx_X == idx_Y:
        raise ValueError('The start index of vector fields must be equal')
    elif not(idx_g == idx_X):
        raise ValueError(
            'The start index of the metric tensor and vector field must be equal')
    else:
        idx_start = idx_g
    if len(X) != n1:
        raise ValueError(
            'The vector fields and dimension of metric tensor must be identical length')

    # The definition of diapason changes in an index
    if not n == n1:
        raise ValueError(
            'The rank of the metric tensor does not concide with the number of variables.')
    indices = range(idx_start, idx_start + n)

    # Creating of output array with new indices
    nabla_XY = Arraypy([1, n, idx_start])
    nabla_X = covar_der(X, g, var)

    # Calculation
    for j in indices:
        nabla_XY[j] = sum([nabla_X[i, j] * Y[i] for i in indices])

    # Handling of an output array
    if type_output == str('t') or type_output == Symbol('t'):
        cov_der_XY = nabla_XY.to_tensor((1))
    elif type_output == str('a') or type_output == Symbol('a'):
        cov_der_XY = nabla_XY
    else:
        raise ValueError(
            "The parameter of type output result must 'a' - Arraypy or 't' and None - TensorArray.")

    # Output
    return cov_der_XY
def covar_der(X, g, var, type_output='t'):
    """Return the covariant derivative the vector field.

    Examples:
    =========

    >>> from sympy.tensor.riemannian_geometry import covar_der
    >>> from sympy.tensor.arraypy import Arraypy, TensorArray
    >>> from sympy import symbols, cos
    >>> x1, x2 = symbols('x1, x2')

    var it's a list of symbolic arguments. May be a list, one-dimensional
    arraypy or one-dimensional tensor with valence of indices (+1):

    >>> var = [x1, x2]

    g it's a metric tensor must be symmetric matrix, arraypy or tensor
    with valence indices (-1, -1):

    >>> A = Arraypy((2, 2))
    >>> g = TensorArray(A,(-1, -1))
    >>> g[0,0] = cos(x2)**2
    >>> g[0,1] = 0
    >>> g[1,0] = 0
    >>> g[1,1] = 1

    X it's vector field can be a list, one-dimensional arraypy, or one-dimensional
    tensor with valences of indices (+1):

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

    type_output it's optional parameter function, indicating the type of calculation
    result and receiving the character or string value:
    - symbol 't' means that the type of the result will match TensorArray;
    - symbol 'a' means that the type of the result will be Arraypy;
    - default function takes a parameter 't', so that the result will be a TensorArray.

    The covariant derivative:
    >>> c_v = covar_der(X, g, var, 't')
    >>> print(c_v)
    x2**3 - (x1 - cos(x2))*sin(x2)/cos(x2)  x1*x2**3*sin(x2)*cos(x2) + 1
    -x1*x2**3*sin(x2)/cos(x2) + 3*x1*x2**2  sin(x2)
    >>> c_v.type_pq
    (1, 1)

    """
    # Handling of input vector of arguments - var
    if not isinstance(var, (list, Arraypy, TensorArray)):
        raise TypeError(
            'The type of vector of arguments must be a list, Arraypy or TensorArray')
    if isinstance(var, (TensorArray, Arraypy)):
        if len(var.shape) != 1:
            raise ValueError("The dimension of vector of arguments must be 1")
        if isinstance(var, TensorArray):
            if not var.type_pq == (1, 0):
                raise ValueError(
                    'The valence of vector of arguments must be (+1)')
    if isinstance(var, (TensorArray, Arraypy)):
        var = var.to_list()

    # Definition of number of variables
    n = len(var)

    # Handling of a input argument - metric tensor g
    if not isinstance(g, (Matrix, Arraypy, TensorArray)):
        raise TypeError(
            'The type of metric tensor must be Matrix, TensorArray or Arraypy')
    else:
        if isinstance(g, (Arraypy, TensorArray)):
            if isinstance(g, TensorArray):
                if not g.type_pq == (0, 2):
                    raise ValueError(
                        'The valence of metric tensor must be (-1,-1)')
            if not is_symmetric(g):
                raise ValueError('The metric tensor must be symmetric.')
            if not (g.start_index[0] == g.start_index[1]):
                raise ValueError(
                    'The starting indices of metric tensor must be identical')
            idx_g = g.start_index[0]
        elif isinstance(g, Matrix):
            if not g.is_symmetric():
                raise ValueError('The metric tensor must be symmetric.')
            idx_g = 0

    # Handling of a input argument - vector field X
    if not isinstance(X, (list, Arraypy, TensorArray)):
        raise TypeError(
            'The type of vector field must be list, TensorArray or Arraypy')
    else:
        if isinstance(X, (Arraypy, TensorArray)):
            if len(X.shape) != 1:
                raise ValueError("The dimension of vector field must be 1")
            if isinstance(X, TensorArray):
                if not X.type_pq == (1, 0):
                    raise ValueError(
                        'The valence of vector field must be (+1)')
            idx_X = X.start_index[0]
        elif isinstance(X, list):
            idx_X = 0

    # The definition of diapason changes in an index
    [n1, n2] = g.shape
    if not n == n1:
        raise ValueError(
            'The rank of the metric tensor does not coincide with the number of variables.')

    if (idx_g != idx_X):
        raise ValueError(
            'The start index of the metric tensor and vector field must be equal')
    else:
        idx_start = idx_g

    indices = range(idx_start, idx_start + n)

    # Creating of output array with new indices
    cov = Arraypy([2, n, idx_start])
    ch_2 = christoffel_2(g, var)
    # Calculation
    for i in indices:
        for j in indices:
            cov[i, j] = diff(X[j], var[i - idx_start]) + \
                Add(*[ch_2[k, i, j] * X[k] for k in indices])

    # Handling of an output array
    if type_output == str('t') or type_output == Symbol('t'):
        cov_der = cov.to_tensor((1, -1))
    elif type_output == str('a') or type_output == Symbol('a'):
        cov_der = cov
    else:
        raise ValueError(
            "The parameter of type output result must 'a' - Arraypy or 't' and None - TensorArray.")

    # Output
    return cov_der
def christoffel_2(g, var, type_output='t'):
    """Return the (1, -1, -1) - tensor of Christoffel symbols for the given metric.
    This returns the Christoffel symbol of second kind that represents the
    Levi-Civita connection for the given metric.

    Examples:
    =========

    >>> from sympy.tensor.riemannian_geometry import christoffel_2
    >>> from sympy.tensor.arraypy import Arraypy, TensorArray
    >>> from sympy import symbols, cos
    >>> x1, x2 = symbols('x1, x2')

    var it's a list of symbolic arguments. May be a list, one-dimensional
    arraypy or one-dimensional tensor with valence of indices (+1):

    >>> var = [x1, x2]

    g it's a metric tensor must be symmetric matrix, arraypy or tensor
    with valence indices (-1, -1):

    >>> A = Arraypy((2, 2))
    >>> g = TensorArray(A,(-1, -1))
    >>> g[0,0] = cos(x2)**2
    >>> g[0,1] = 0
    >>> g[1,0] = 0
    >>> g[1,1] = 1

    type_output it's optional parameter function, indicating the type of calculation
    result and receiving the character or string value:
    - symbol 't' means that the type of the result will match TensorArray;
    - symbol 'a' means that the type of the result will be Arraypy;
    - default function takes a parameter 't', so that the result will be a TensorArray.

    The Christoffel symbols of the second kind:
    >>> ch_2 = christoffel_2(g, var, 'a')
    >>> print(ch_2)
    0  sin(x2)*cos(x2)
    -sin(x2)/cos(x2)  0
    -sin(x2)/cos(x2)  0
    0  0

    """
    # Handling of input vector of arguments - var
    if not isinstance(var, (list, Arraypy, TensorArray)):
        raise TypeError(
            'The type of vector of arguments must be a list, Arraypy or TensorArray')
    if isinstance(var, (TensorArray, Arraypy)):
        if len(var.shape) != 1:
            raise ValueError("The dimension of vector of arguments must be 1")
        if isinstance(var, TensorArray):
            if not var.type_pq == (1, 0):
                raise ValueError(
                    'The valence of vector of arguments must be (+1)')
    if isinstance(var, (TensorArray, Arraypy)):
        var = var.to_list()
    # Definition of number of variables
    n = len(var)

    # Handling of a input argument - metric tensor g
    if not isinstance(g, (Matrix, Arraypy, TensorArray)):
        raise TypeError(
            'The type of metric tensor must be Matrix, TensorArray or Arraypy')
    else:
        if isinstance(g, (Arraypy, TensorArray)):
            if isinstance(g, TensorArray):
                if not g.type_pq == (0, 2):
                    raise ValueError(
                        'The valence of metric tensor must be (-1,-1)')
            if not is_symmetric(g):
                raise ValueError('The metric tensor must be symmetric.')
            if not (g.start_index[0] == g.start_index[1]):
                raise ValueError(
                    'The starting indices of metric tensor must be identical')
            idx_start = g.start_index[0]
            g_inv = (g.to_matrix()).inv()
        elif isinstance(g, Matrix):
            if not g.is_symmetric():
                raise ValueError('The metric tensor must be symmetric.')
            idx_start = 0
            g_inv = g.inv()

    # The definition of diapason changes in an index
    [n1, n2] = g.shape
    if not n == n1:
        raise ValueError(
            'The rank of the metric tensor does not coincide with the number of variables.')

    indices = range(idx_start, idx_start + n)

    # Creating of output array with new indices
    Ch = Arraypy([3, n, idx_start])

    # Calculation
    for i in indices:
        for j in indices:
            for k in indices:
                Ch[i,
                   j,
                   k] = Add(*[g_inv[k - idx_start,
                                    l - idx_start] * (diff(g[j,
                                                             l],
                                                           var[i - idx_start]) + diff(g[i,
                                                                                        l],
                                                                                      var[j - idx_start]) - diff(g[i,
                                                                                                                   j],
                                                                                                                 var[l - idx_start])) / 2 for l in indices])

    # Other variant calculation
    # christ_1 = christoffel_1(g, var)
    # for i in indices:
        # for j in indices:
            # for k in indices:
                # Ch[i,
                # j,
                # k] = Add(*[g_inv[k,
                # l] *christ_1[i,
                # j,
                # l] for l in indices])

    # Handling of an output array
    if type_output == str('t') or type_output == Symbol('t'):
        christoffel_2 = Ch.to_tensor((1, -1, -1))
    elif type_output == str('a') or type_output == Symbol('a'):
        christoffel_2 = Ch
    else:
        raise ValueError(
            "The parameter of type output result must 'a' - Arraypy or 't' and None - TensorArray.")

    # Output
    return christoffel_2
def int_product(w, X):
    """Calculation of the inner product of the form and the vector field.
    Return.

    Examples:
    =========
    >>> from sympy import symbols
    >>> from sympy.tensor.arraypy import Arraypy
    >>> from sympy.tensor.tensor_fields import int_product

    >>> x1, x2, x3, l, m, n = symbols('x1 x2 x3 l m n')
    >>> omega2=Arraypy([2,3,1]).to_tensor((-1,-1))
    >>> omega2[1,2]=x3
    >>> omega2[1,3]=-x2
    >>> omega2[2,1]=-x3
    >>> omega2[2,3]=x1
    >>> omega2[3,1]=x2
    >>> omega2[3,2]=-x1

    >>> X_t=Arraypy([1,3,1]).to_tensor((1))
    >>> X_t[1]=l
    >>> X_t[2]=m
    >>> X_t[3]=n

    >>> print(int_product(omega2, X_t))
    -m*x3 + n*x2  l*x3 - n*x1  -l*x2 + m*x1

    """
    # Handling of a differential form
    if not isinstance(w, (TensorArray, Arraypy)):
        raise ValueError(
            "The type of differential form must be TensorArray or Arraypy")

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

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

    # Define the start index in the output form
    idx_start_w = w.start_index[0]
    if idx_start_w != idx_start_X:
        raise ValueError(
            "The start index of tensor and vector field must be equal")

    # Creating the output array in accordance with start indexes
    n = w.shape[0]  # the dimension of the input array
    q = len(w.shape)  # the rank of the input array
    if (q != 1):
        result_tensor = Arraypy([q - 1, n, idx_start_w])
        # all indices are -1
        valence_list = [(-1) for k in range(q - 1)]
        # result tensor
        int_prod = result_tensor.to_tensor(valence_list)

        for index in int_prod.index_list:
            # the sum on k.k is [0,n-1], n is len(X)
            for k in range(len(X)):
                idx = list(index)
                idx.insert(0, k + idx_start_w)
                int_prod[index] += w[tuple(idx)] * X[k + idx_start_w]
    if q == 1:
        # int_prod is number(symbolic expression)
        int_prod = 0
        for index in w.index_list:
            for k in range(len(X)):
                int_prod += w[index] * X[k + idx_start_w]
    # Output
    return int_prod
def lie_w(omega, X, args):
    """Return a skew-symmetric tensor of type (0,p).
    Function lie_w calculates all the components of the Lie derivative
    differential forms in a symbolic form.

    Indexes the output tensor will start as well as the input tensor (array)
    "omega". If all the input parameters of the same type, they must be equal
    to the initial indexes.

    Examples:
    =========

    >>> from sympy.tensor.tensor_fields import lie_w
    >>> from sympy import symbols, cos
    >>> from sympy.tensor.arraypy import Arraypy
    >>> x1, x2, x3 = symbols('x1 x2 x3')

    omega - skew-symmetric tensor. Can be a tensor of type (0,p) or an array
    arraypy:

    >>> omega=Arraypy([2,3,1]).to_tensor((-1,-1))
    >>> omega[1,2]=x3
    >>> omega[1,3]=-x2
    >>> omega[2,1]=-x3
    >>> omega[2,3]=x1
    >>> omega[3,1]=x2
    >>> omega[3,2]=-x1

    X - the vector field along which the derivative is calculated:

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

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

    >>> arg = [x1, x2, x3]

    Lie derivative of a differential form:

    >>> li = lie_w(omega,X,arg)
    >>> print(li)
    0 x2**3*x3 + x3**3 + x3 -x2**4 - 3*x2*x3**2 - x2 + x3*sin(x3) + cos(x3)
    -x2**3*x3 - x3**3 - x3 0 -2*x1*x2**3 + 3*x1*x3**2 + x1
    x2**4 + 3*x2*x3**2 + x2 - x3*sin(x3) - cos(x3) 2*x1*x2**3 - \
    3*x1*x3**2 - x1 0
    >>> li.type_pq
    (0, 2)

    """
    # 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 a vector field
    check_the_vector_field(X)
    if isinstance(X, (TensorArray, Arraypy)):
        idx_X = X.start_index[0]
    else:
        idx_X = 0

    # Handling of a differential form
    if not isinstance(omega, (TensorArray, Arraypy)):
        raise ValueError(
            "The type of differential form must be TensorArray or Arraypy")
    if not is_asymmetric(omega):
        raise ValueError("The differential form must be a skew-symmetric")
    idx_omega = omega.start_index[0]


# Define the start index in the output tensor
    if type(omega) == type(X) == type(args):
        if idx_omega != idx_X or idx_omega != idx_args or idx_X != idx_args:
            raise ValueError(
                "The start index of differential form, vector field and \
                vector of argements must be equal")
    if isinstance(omega, type(X)) and idx_omega != idx_X:
        raise ValueError(
            "The start index of differential form and vector field must be \
            equal")
    idx_st = idx_omega

# Creating the output array in accordance with start indexes
    n = omega.shape[0]  # the dimensionality of the input array
    r = len(omega.shape)  # the rank of the input array
    a = Arraypy([r, n, idx_st])
    valence_list = [(-1) for k in range(r)]
    diff_Lie = a.to_tensor(valence_list)

    # Calculation
    idx = diff_Lie.start_index
    if isinstance(args, (TensorArray, Arraypy)):
        args = args.to_list()
    if isinstance(X, (TensorArray, Arraypy)):
        X = X.to_list()
    l_idx = len(idx)
    for p in range(len(diff_Lie)):
        for k in range(l_idx + 1):
            tuple_list_indx = [
                replace_index_to_k(idx, f, k + idx_st) for f in range(l_idx)]
            # the intermediate value
            diff_omega = diff(omega[idx], args[k]) * X[k]
            for j in range(l_idx):
                diff_Lie[idx] += diff(X[k], args[idx[j] - idx_st]) *\
                    omega[tuple_list_indx[j]]
            diff_Lie[idx] = diff_Lie[idx] + diff_omega
        idx = diff_Lie.next_index(idx)
    # Output
    return diff_Lie
def lie_xy(X, Y, args, output_type=None):
    """Return the vector field [X,Y], Lie bracket (commutator) of a vector
    fields X and Y.

    Examples:
    =========
    >>> from sympy.tensor.tensor_fields import lie_xy
    >>> from sympy import symbols, cos, sin
    >>> x1, x2, x3 = symbols('x1 x2 x3')

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

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

    The Lie brackets of two vector fields:

    >>> lie = lie_xy(X, Y, arg,'a')
    >>> print(lie)
    2*x1**3*x2**6 + 3*x1**3*x2**2*(x2 - cos(x3)) - 3*x1*x2**2*(x2*x3 - \
    sin(x1*x3))
    -x1*x2**3*x3*cos(x1*x3) - x2*x3 + x3*(x2 - cos(x3)) + \
    (-x1 + x3**3)*(-x1*cos(x1*x3) + x2) - (-x1**2 + x3**3)*sin(x3) + sin(x1*x3)
    x1**3*x2**3 - 2*x1**2*x2**3 + 3*x3**2*(-x1 + x3**3) - \
    3*x3**2*(-x1**2 + x3**3)

    """
    # Handling of a vector of arguments
    check_vector_of_arguments(args)
    # The definition of the start index 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)
    # The definition of the start index X and type of output
    if isinstance(X, (TensorArray, Arraypy)):
        if isinstance(X, TensorArray):
            out_t = 't'
        idx_X = X.start_index[0]
    else:
        idx_X = 0
        out_t = 'l'

    # Handling of the second vector field
    check_the_vector_field(Y)
    # The definition of the start index Y
    if isinstance(Y, (TensorArray, Arraypy)):
        idx_Y = Y.start_index[0]
    else:
        idx_Y = 0

    if len(Y) != len(X):
        raise ValueError(
            "The different number of arguments in the vector fields")
    elif len(args) != len(X) or len(args) != len(Y):
        raise ValueError(
            "The different number of components in the vector field and \
            vector of arguments")

    # Define the start index in the output tensor
    if type(Y) == type(X) == type(args):
        if idx_Y != idx_X or idx_Y != idx_args or idx_X != idx_args:
            raise ValueError(
                "The start index of vector fields and vector of argements \
                must be equal")
    if idx_Y != idx_X:
        raise ValueError(
            "The start index of vector fields must be equal")
    idx_st = idx_Y

    if output_type is None:
        if out_t is not None:
            output_type = out_t
        else:
            output_type = 'a'

    # Creating the output array in accordance with start indexes
    Li = Arraypy([1, len(X), idx_st])

    # Calculating
    if isinstance(Y, (TensorArray, Arraypy)):
        Y = Y.to_list()
    if isinstance(X, (TensorArray, Arraypy)):
        X = X.to_list()
    if isinstance(args, (TensorArray, Arraypy)):
        args = args.to_list()

    if X == Y:
        return 0
    else:
        indices = range(len(args))
        for i in indices:
            for k in indices:
                Li[i +
                   idx_st] += Add(diff(Y[i], args[k]) *
                                  X[k] -
                                  diff(X[i], args[k]) *
                                  Y[k])
    # Handling of an output array
    if output_type == 't' or output_type == Symbol('t'):
        Lie = Arraypy.to_tensor(Li, 1)
    elif output_type == 'a' or output_type == Symbol('a'):
        Lie = Li
    elif output_type == 'l' or output_type == Symbol('l'):
        Lie = Arraypy.to_list(Li)
    else:
        raise TypeError(
            "The third argument must be 't'-TensorArray,'a'-Arraypy, \
            'l'-list")

    # Output
    return Lie
def df(f, args, output_type='l'):
    """Return an the 1-form df, differential of function f(x).

    Examples:
    =========

    >>> from sympy.tensor.tensor_fields import df
    >>> from sympy import symbols, sin
    >>> from sympy.tensor.arraypy import Arraypy
    >>> x1, x2, x3= symbols('x1 x2 x3')

    f it's a function the differential of that is calculated:

    >>> f=x1**2*x2 + sin(x2*x3 - x2)

    args it's a list of symbol arguments of the function f. It can be in list,
    array of arraypy or contravariant tensor:

    >>> args_t=Arraypy([1,3,1]).to_tensor(1)
    >>> args_t[1]=x1
    >>> args_t[2]=x2
    >>> args_t[3]=x3

    output_type  it is an optional parameter accepting  symbol value of
    'l', 'a' or  't' and indicative on the type of result of calculations:
    - 'l' it is  a result as a list(list);
    - 'a' it is a result as an unidimensional array of arraypy;
    - 't' it is a result as an unidimensional covariant tensor.

    Differential:

    >>> d = df(f, args_t, 't')
    >>> print(d)
    2*x1*x2 x1**2 + (x3 - 1)*cos(x2*x3 - x2) x2*cos(x2*x3 - x2)

    The valence of the returned tensor:

    >>> d.type_pq
    (0, 1)

    """
    # Handling of a vector of arguments
    check_vector_of_arguments(args)

    # The definition of the start index
    if isinstance(args, list):
        idx_start = 0
    else:
        idx_start = args.start_index[0]

    # Creating the output array in accordance with the start index
    n = len(args)
    array = Arraypy([1, n, idx_start])

    # Calculation
    for k in range(idx_start, idx_start + n):
        array[k] = diff(f, args[k])

    # Handling of an output array
    if output_type == 't' or output_type == Symbol('t'):
        differential = Arraypy.to_tensor(array, -1)
    elif output_type == 'a' or output_type == Symbol('a'):
        differential = array
    elif output_type == 'l' or output_type == Symbol('l'):
        differential = Arraypy.to_list(array)
    else:
        raise TypeError(
            "The third argument must be 't' - TensorArray,'a' - Arraypy, \
            'l' - list")
    # Output
    return differential
def curl(X, args, output_type=None):
    """Return the rotor vector field curl(X) of a vector field X in R^3
    (curl, rotation, rotor, vorticity).
    A rotor can be calculated for only in three-dimensional Euclidean space.

    Examples:
    =========

    >>> from sympy.tensor.tensor_fields import curl
    >>> from sympy import symbols, cos
    >>> from sympy.tensor.arraypy import Arraypy, TensorArray
    >>> x1, x2, x3 = symbols('x1 x2 x3')

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

    >>> X=Arraypy(3)
    >>> X_t=TensorArray(X,(1))
    >>> X_t[0]=x1*x2**3
    >>> X_t[1]=x2-cos(x3)
    >>> X_t[2]=x3**3-x1
    >>> arg=[x1,x2,x3]
    >>> r=curl(X_t,arg,'t')
    >>> print(r)
    -sin(x3) 1 -3*x1*x2**2
    >>> r.type_pq
    (1, 0)

    """
    # Handling of a vector of arguments
    check_vector_of_arguments(args)
    if len(args) != 3:
        raise ValueError("Three variables are required")
    # The definition of the start index
    if isinstance(args, list):
        idx_args = 0
    else:
        idx_args = args.start_index[0]

    # Handling of a vector field
    check_the_vector_field(X)
    if len(X) != 3:
        raise ValueError("A three-dimensional vector field is necessary")
    # The definition of the start index and type of output
    if isinstance(X, (TensorArray, Arraypy)):
        if isinstance(X, TensorArray):
            out_t = 't'
        idx_X = X.start_index[0]
    else:
        idx_X = 0
        out_t = 'l'

    # The definition type of output of an output array
    if output_type is None:
        if out_t is not None:
            output_type = out_t
        else:
            output_type = 'a'

    # The definition of the start index
    if isinstance(X, type(args)) and (idx_X != idx_args):
        raise ValueError(
            "The start index of vector field and vector of arguments must be \
            equal")
    idx_st = idx_X

    # Creating the output array in accordance with the start index
    array = Arraypy([1, 3, idx_st])

    # Calculation
    if isinstance(X, (TensorArray, Arraypy)):
        X = X.to_list()
    if isinstance(args, (TensorArray, Arraypy)):
        args = args.to_list()

    array[idx_st] = (diff(X[2], args[1]) - diff(X[1], args[2]))
    array[idx_st + 1] = diff(X[0], args[2]) - diff(X[2], args[0])
    array[idx_st + 2] = diff(X[1], args[0]) - diff(X[0], args[1])

    # Handling of an output array
    if output_type == 't' or output_type == Symbol('t'):
        rotor = Arraypy.to_tensor(array, 1)
    elif output_type == 'a' or output_type == Symbol('a'):
        rotor = array
    elif output_type == 'l' or output_type == Symbol('l'):
        rotor = Arraypy.to_list(array)
    else:
        raise TypeError(
            "The third argument must be 't'-tensor,'a'-Arraypy, \
            'l'-list")
    # Output
    return rotor
def grad(f, args, g=None, output_type=None):
    """Return the vector field gradient of a function f(x).

    Examples:
    =========

    >>> from sympy.tensor.tensor_fields import grad
    >>> from sympy import symbols, sin
    >>> from sympy.tensor.arraypy import Arraypy
    >>> x1, x2, x3 = symbols('x1 x2 x3')

    f it's a function the differential of that is calculated:

    >>> f=x1**2*x2 + sin(x2*x3 - x2)

    args it's a list of symbol arguments of function of f.
    It can be in list, array of arraypy or contravariant tensor:

    >>> args=[x1,x2,x3]

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

    >>> g=Arraypy([2,3,1])
    >>> g_t=g.to_tensor((-1,-1))
    >>> g_t[1,1]=2
    >>> g_t[1,2]=1
    >>> g_t[1,3]=0
    >>> g_t[2,1]=1
    >>> g_t[2,2]=3
    >>> g_t[2,3]=0
    >>> g_t[3,1]=0
    >>> g_t[3,2]=0
    >>> g_t[3,3]=1

    output _ type  it is an optional parameter accepting  symbol value of
    'l', 'a' or  't' and indicative on the type of result of calculations:
    - 'l' it is  a result as a list(list);
    - 'a' it is a result as an unidimensional array of arraypy;
    - 't' it is a result as an unidimensional covariant tensor.

    Gradient:
    >>> gr=grad(f,args,g_t,'a')
    >>> print(gr)
    -x1**2/5 + 6*x1*x2/5 - (x3 - 1)*cos(x2*x3 - x2)/5 2*x1**2/5 - 2*x1*x2/5 + \
    2*(x3 - 1)*cos(x2*x3 - x2)/5 x2*cos(x2*x3 - x2)

    """
    # Handling of a vector of arguments
    check_vector_of_arguments(args)

    # The definition of the start index
    if isinstance(args, list):
        idx_args = 0
    else:
        idx_args = args.start_index[0]

    # Handling of the metric tensor
    # 1. if g is not NULL
    if g is not None:
        if output_type is None:
            output_type = 't'
        check_metric_tensor(g)

        # The definition of the start index
        if isinstance(g, Matrix):
            idx_st = 0
        else:
            idx_st = g.start_index[0]
        # The start index is the same
        if isinstance(g, type(args)) and idx_st != idx_args:
            raise ValueError(
                "The start index of the metric tensor and vector of arguments \
                must be equal")
        if isinstance(g, (TensorArray, Arraypy)):
            g = g.to_matrix()
    # 2.if g is NULL
    else:
        # g - the identity matrix
        g = eye(len(args))
        idx_st = 0

    # Creating the output array in accordance with start indexes
    n = len(args)
    array = Arraypy([1, n, idx_st])
    indices = range(idx_st, idx_st + n)

    # Calculating
    g_inv = g.inv()
    if isinstance(args, (TensorArray, Arraypy)):
        args = args.to_list()
    for i in indices:
        for j in indices:
            array[i] += (g_inv[i - idx_st, j - idx_st] * diff(f, args[j -
                                                                      idx_st]))

    # Handling of an output array
    if output_type == 't' or output_type == Symbol('t'):
        gradient = Arraypy.to_tensor(array, 1)
    elif output_type == 'a' or output_type == Symbol('a'):
        gradient = array
    elif output_type == 'l' or output_type == Symbol('l') or output_type is \
            None:
        gradient = Arraypy.to_list(array)
    else:
        raise TypeError(
            "The third argument must be 't' - tensor,'a' - Arraypy, \
            'l' - list")
# Output
    return gradient