Example #1
0
 def test_select_equations_excluded_raises(self):
     with self.assertRaises(Exception) as context:
         select_equations(bad_equation)
     self.assertEqual(type(context.exception), ValueError)
     self.assertEqual(
         str(context.exception),
         "First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'"
     )
Example #2
0
def extrema_points(equation_type, coefficients, precision=4):
    """
    Calculates the extrema of a specific function

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which extrema must be determined (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients to use to generate the equation to investigate
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the results

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    points['maxima'] : list of float or str
        Values of the x-coordinates at which the original function has a relative maximum; if the function is sinusoidal, then only two or three results within a two-period interval will be listed, but a general form will also be included; if the function has no maxima, then it will return a list of `None`
    points['minima'] : list of float or str
        Values of the x-coordinates at which the original function has a relative minimum; if the function is sinusoidal, then only two or three results within a two-period interval will be listed, but a general form will also be included; if the function has no minima, then it will return a list of `None`

    See Also
    --------
    - Roots for key functions: :func:`~regressions.analyses.roots.linear.linear_roots`, :func:`~regressions.analyses.roots.quadratic.quadratic_roots`, :func:`~regressions.analyses.roots.cubic.cubic_roots`, :func:`~regressions.analyses.roots.hyperbolic.hyperbolic_roots`, :func:`~regressions.analyses.roots.exponential.exponential_roots`, :func:`~regressions.analyses.roots.logarithmic.logarithmic_roots`, :func:`~regressions.analyses.roots.logistic.logistic_roots`, :func:`~regressions.analyses.roots.sinusoidal.sinusoidal_roots`
    - Graphical analysis: :func:`~regressions.analyses.criticals.critical_points`, :func:`~regressions.analyses.intervals.sign_chart`, :func:`~regressions.analyses.maxima.maxima_points`, :func:`~regressions.analyses.minima.minima_points`, :func:`~regressions.analyses.points.key_coordinates`

    Notes
    -----
    - Critical points for the derivative of a function: :math:`c_i = \\{ c_1, c_2, c_3,  \\cdots, c_{n-1}, c_n \\}`
    - X-coordinates of the extrema of the function: :math:`x_{ext} = \\{ x \\mid x \\in c_i, \\left( f'(\\frac{c_{j-1} + c_j}{2}) < 0 \\cap f'(\\frac{c_j + c_{j+1}}{2}) > 0 \\right) \\\\ \\cup \\left( f'(\\frac{c_{j-1} + c_j}{2}) > 0 \\cap f'(\\frac{c_j + c_{j+1}}{2}) < 0 \\right) \\}`
    - |extrema_values|

    Examples
    --------
    Import `extrema_points` function from `regressions` library
        >>> from regressions.analyses.extrema import extrema_points
    Calulate the extrema of a cubic function with coefficients 1, -15, 63, and -7
        >>> points_cubic = extrema_points('cubic', [1, -15, 63, -7])
        >>> print(points_cubic['maxima'])
        [3.0]
        >>> print(points_cubic['minima'])
        [7.0]
    Calulate the extrema of a sinusoidal function with coefficients 2, 3, 5, and 7
        >>> points_sinusoidal = extrema_points('sinusoidal', [2, 3, 5, 7])
        >>> print(points_sinusoidal['maxima'])
        [5.5236, 7.618, 9.7124, '5.5236 + 2.0944k']
        >>> print(points_sinusoidal['minima'])
        [6.5708, 8.6652, '6.5708 + 2.0944k']
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    positive_integer(precision)

    # Determine maxima and minima
    max_points = maxima_points(equation_type, coefficients, precision)
    min_points = minima_points(equation_type, coefficients, precision)

    # Create dictionary to return
    result = {}

    # Handle sinusoidal case
    if equation_type == 'sinusoidal':
        # Recreate sign chart
        intervals_set = sign_chart('sinusoidal', coefficients, 1, precision)

        # Grab general form
        general_form = intervals_set[-1]

        # Extract periodic unit
        periodic_unit_index = general_form.find(' + ') + 3
        periodic_unit = 2 * float(general_form[periodic_unit_index:-1])
        rounded_periodic_unit = rounded_value(periodic_unit, precision)

        # Create general forms for max and min
        max_general_form = str(
            max_points[0]) + ' + ' + str(rounded_periodic_unit) + 'k'
        min_general_form = str(
            min_points[0]) + ' + ' + str(rounded_periodic_unit) + 'k'

        # Append general form as final element of each list
        max_extended = max_points + [max_general_form]
        min_extended = min_points + [min_general_form]
        result = {'maxima': max_extended, 'minima': min_extended}

    # Handle all other cases
    else:
        result = {'maxima': max_points, 'minima': min_points}
    return result
Example #3
0
def coordinate_pairs(equation_type, coefficients, inputs, point_type = 'point', precision = 4):
    """
    Creates a list of coordinate pairs from a set of inputs

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which coordinate pairs must be determined (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients to use to generate the equation to investigate
    inputs : list of int or float or str
        X-coordinates to use to generate the y-coordinates for each coordinate pair
    point_type : str, default='point'
        Name of the type of point that describes all points which must be generated (e.g., 'intercepts', 'maxima')
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the results

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    TypeError
        Third argument must be a 1-dimensional list containing elements that are integers, floats, strings, or None
    ValueError
        Fourth argument must be either 'point', 'intercepts', 'maxima', 'minima', or 'inflections'
    ValueError
        Last argument must be a positive integer
        
    Returns
    -------
    points : list of float or str
        List containing lists of coordinate pairs, in which the second element of the inner lists are floats and the first elements of the inner lists are either floats or strings (the latter for general forms); may return a list of None if inputs list contained None

    See Also
    --------
    :func:`~regressions.vectors.generate.generate_elements`, :func:`~regressions.vectors.unify.unite_vectors`

    Notes
    -----
    - Set of x-coordinates of points: :math:`x_i = \\{ x_1, x_2, \\cdots, x_n \\}`
    - Set of y-coordinates of points: :math:`y_i = \\{ y_1, y_2, \\cdots, y_n \\}`
    - Set of coordinate pairs of points: :math:`p_i = \\{ (x_1, y_1), (x_2, y_2), \\cdots, (x_n, y_n) \\}`

    Examples
    --------
    Import `coordinate_pairs` function from `regressions` library
        >>> from regressions.analyses.points import coordinate_pairs
    Generate a list of coordinate pairs for a cubic function with coefficients 2, 3, 5, and 7 based off x-coordinates of 1, 2, 3, and 4
        >>> points_cubic = coordinate_pairs('cubic', [2, 3, 5, 7], [1, 2, 3, 4])
        >>> print(points_cubic)
        [[1.0, 17.0], [2.0, 45.0], [3.0, 103.0], [4.0, 203.0]]
    Generate a list of coordinate pairs for a sinusoidal function with coefficients 2, 3, 5, and 7 based off x-coordinates of 1, 2, 3, and 4
        >>> points_sinusoidal = coordinate_pairs('sinusoidal', [2, 3, 5, 7], [1, 2, 3, 4])
        >>> print(points_sinusoidal)
        [[1.0, 8.0731], [2.0, 6.1758], [3.0, 7.5588], [4.0, 6.7178]]
    Generate a list of coordinate pairs for a quadratic function with coefficients 1, -5, and 6 based off x-coordinates of 2 and 3 (given that the resultant coordinates will be x-intercepts)
        >>> points_quadratic = coordinate_pairs('quadratic', [1, -5, 6], [2, 3], 'intercepts')
        >>> print(points_quadratic)
        [[2.0, 0.0], [3.0, 0.0]]
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    allow_none_vector(inputs, 'third')
    select_points(point_type, 'fourth')
    positive_integer(precision)

    # Create equations for evaluating inputs (based on equation type)
    equation = lambda x : x
    if equation_type == 'linear':
        equation = linear_equation(*coefficients, precision)
    elif equation_type == 'quadratic':
        equation = quadratic_equation(*coefficients, precision)
    elif equation_type == 'cubic':
        equation = cubic_equation(*coefficients, precision)
    elif equation_type == 'hyperbolic':
        equation = hyperbolic_equation(*coefficients, precision)
    elif equation_type == 'exponential':
        equation = exponential_equation(*coefficients, precision)
    elif equation_type == 'logarithmic':
        equation = logarithmic_equation(*coefficients, precision)
    elif equation_type == 'logistic':
        equation = logistic_equation(*coefficients, precision)
    elif equation_type == 'sinusoidal':
        equation = sinusoidal_equation(*coefficients, precision)

    # Round inputs
    rounded_inputs = []
    for point in inputs:
        if isinstance(point, (int, float)):
            rounded_inputs.append(rounded_value(point, precision))
        else:
            rounded_inputs.append(point)

    # Create empty lists
    outputs = []
    coordinates = []
    
    # Handle no points
    if rounded_inputs[0] == None:
        coordinates.append(None)
    
    # Fill outputs list with output value at each input
    else:
        for value in rounded_inputs:
            # Circumvent inaccurate rounding
            if point_type == 'intercepts':
                outputs.append(0.0)
            
            # Evaluate function at inputs
            else:
                # Evaluate numerical inputs
                if isinstance(value, (int, float)):
                    output = equation(value)
                    rounded_output = rounded_value(output, precision)
                    outputs.append(rounded_output)
                
                # Handle non-numerical inputs
                else:
                    outputs.append(outputs[0])

        # Unite inputs and outputs for maxima into single list
        coordinates.extend(unite_vectors(rounded_inputs, outputs))
    
    # Return final coordinate pairs
    return coordinates
Example #4
0
def key_coordinates(equation_type, coefficients, precision = 4):
    """
    Calculates the key points of a specific function

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which key points must be determined (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients to use to generate the equation to investigate
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the results

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    points['roots'] : list of float or str
        List containing two-element lists for each point; first elements of those lists will be the value of the x-coordinate at which the original function has a root; second elements of those lists will be 0; if the function is sinusoidal, then only the initial results within a four-period interval will be listed, but general forms will also be included; if the function has no roots, then it will return a list of `None`
    points['maxima'] : list of float or str
        List containing two-element lists for each point; first elements of those lists will be the value of the x-coordinate at which the original function has a relative maximum; second elements of those lists will be the y-coordinate of that maximum; if the function is sinusoidal, then only the initial results within a two-period interval will be listed, but a general form will also be included; if the function has no maxima, then it will return a list of `None`
    points['minima'] : list of float or str
        List containing two-element lists for each point; first elements of those lists will be the value of the x-coordinate at which the original function has a relative minimum; second elements of those lists will be the y-coordinate of that minimum; if the function is sinusoidal, then only the initial results within a two-period interval will be listed, but a general form will also be included; if the function has no minima, then it will return a list of `None`
    points['inflections'] : list of float or str
        List containing two-element lists for each point; first elements of those lists will be the value of the x-coordinate at which the original function has an inflection; second elements of those lists will be the y-coordinate of that inflection; if the function is sinusoidal, then only the initial results within a two-period interval will be listed, but a general form will also be included; if the function has no inflection points, then it will return a list of `None`

    See Also
    --------
    - Roots for key functions: :func:`~regressions.analyses.roots.linear.linear_roots`, :func:`~regressions.analyses.roots.quadratic.quadratic_roots`, :func:`~regressions.analyses.roots.cubic.cubic_roots`, :func:`~regressions.analyses.roots.hyperbolic.hyperbolic_roots`, :func:`~regressions.analyses.roots.exponential.exponential_roots`, :func:`~regressions.analyses.roots.logarithmic.logarithmic_roots`, :func:`~regressions.analyses.roots.logistic.logistic_roots`, :func:`~regressions.analyses.roots.sinusoidal.sinusoidal_roots`
    - Graphical analysis: :func:`~regressions.analyses.criticals.critical_points`, :func:`~regressions.analyses.intervals.sign_chart`, :func:`~regressions.analyses.maxima.maxima_points`, :func:`~regressions.analyses.minima.minima_points`, :func:`~regressions.analyses.extrema.extrema_points`, :func:`~regressions.analyses.inflections.inflection_points`

    Notes
    -----
    - Key points include x-intercepts, maxima, minima, and points of inflection
    - |intercepts|
    - |extrema|
    - |inflections|

    Examples
    --------
    Import `key_coordinates` function from `regressions` library
        >>> from regressions.analyses.points import key_coordinates
    Calculate the key points of a cubic function with coefficients 1, -15, 63, and -7
        >>> points_cubic = key_coordinates('cubic', [1, -15, 63, -7])
        >>> print(points_cubic['roots'])
        [[0.1142, 0.0]]
        >>> print(points_cubic['maxima'])
        [[3.0, 74.0]]
        >>> print(points_cubic['minima'])
        [[7.0, 42.0]]
        >>> print(points_cubic['inflections'])
        [[5.0, 58.0]]
    Calculate the key points of a sinusoidal function with coefficients 2, 3, 5, and 1
        >>> points_sinusoidal = key_coordinates('sinusoidal', [2, 3, 5, 1])
        >>> print(points_sinusoidal['roots'])
        [[4.8255, 0.0], [6.2217, 0.0], [6.9199, 0.0], [8.3161, 0.0], [9.0143, 0.0], [10.4105, 0.0], [11.1087, 0.0], [12.5049, 0.0], [13.203, 0.0], [14.5993, 0.0], ['4.8255 + 2.0944k', 0.0], ['6.2217 + 2.0944k', 0.0]]
        >>> print(points_sinusoidal['maxima'])
        [[5.5236, 3.0], [7.618, 3.0], [9.7124, 3.0], ['5.5236 + 2.0944k', 3.0]]
        >>> print(points_sinusoidal['minima'])
        [[6.5708, -1.0], [8.6652, -1.0], ['6.5708 + 2.0944k', -1.0]]
        >>> print(points_sinusoidal['inflections'])
        [[5.0, 1.0], [6.0472, 1.0], [7.0944, 1.0], [8.1416, 1.0], [9.1888, 1.0001], ['5.0 + 1.0472k', 1.0]]
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    positive_integer(precision)
    
    # Create lists of inputs
    intercepts_inputs = intercept_points(equation_type, coefficients, precision)
    extrema_inputs = extrema_points(equation_type, coefficients, precision)
    maxima_inputs = extrema_inputs['maxima']
    minima_inputs = extrema_inputs['minima']
    inflections_inputs = inflection_points(equation_type, coefficients, precision)

    # Generate coordinate pairs for all x-intercepts
    intercepts_coordinates = coordinate_pairs(equation_type, coefficients, intercepts_inputs, 'intercepts', precision)
    
    # Generate coordinate pairs for all maxima
    maxima_coordinates = coordinate_pairs(equation_type, coefficients, maxima_inputs, 'maxima', precision)
    
    # Generate coordinate pairs for all minima
    minima_coordinates = coordinate_pairs(equation_type, coefficients, minima_inputs, 'minima', precision)
    
    # Generate coordinate pairs for all points of inflection
    inflections_coordinates = coordinate_pairs(equation_type, coefficients, inflections_inputs, 'inflections', precision)
    
    # Create dictionary to return
    result = {
        'roots': intercepts_coordinates,
        'maxima': maxima_coordinates,
        'minima': minima_coordinates,
        'inflections': inflections_coordinates
    }
    return result
Example #5
0
def intercept_points(equation_type, coefficients, precision=4):
    """
    Calculates the roots of a specific function

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which intercepts must be determined (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients to use to generate the equation to investigate
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the results

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    points : list of float or str
        Values of the x-coordinates at which the original function crosses the x-axis; if the function is sinusoidal, then only the initial results within a four-period interval will be listed, but general forms will also be included; if the function has no x-intercepts, then it will return a list of `None`

    See Also
    --------
    - Roots for key functions: :func:`~regressions.analyses.roots.linear.linear_roots`, :func:`~regressions.analyses.roots.quadratic.quadratic_roots`, :func:`~regressions.analyses.roots.cubic.cubic_roots`, :func:`~regressions.analyses.roots.hyperbolic.hyperbolic_roots`, :func:`~regressions.analyses.roots.exponential.exponential_roots`, :func:`~regressions.analyses.roots.logarithmic.logarithmic_roots`, :func:`~regressions.analyses.roots.logistic.logistic_roots`, :func:`~regressions.analyses.roots.sinusoidal.sinusoidal_roots`
    - Graphical analysis: :func:`~regressions.analyses.criticals.critical_points`, :func:`~regressions.analyses.intervals.sign_chart`, :func:`~regressions.analyses.points.key_coordinates`

    Notes
    -----
    - Domain of a function: :math:`x_i = \\{ x_1, x_2, \\cdots, x_n \\}`
    - X-intercepts (roots) of the function: :math:`x_r = \\{ r \\mid r \\in x_i, f(r) = 0 \\}`
    - |intercepts|

    Examples
    --------
    Import `intercept_points` function from `regressions` library
        >>> from regressions.analyses.intercepts import intercept_points
    Calculate the roots of a cubic function with coefficients 1, -15, 66, and -80
        >>> points_cubic = intercept_points('cubic', [1, -15, 66, -80])
        >>> print(points_cubic)
        [2.0, 5.0, 8.0]
    Calculate the roots of a sinusoidal function with coefficients 3, 1, -2, and 3
        >>> points_sinusoidal = intercept_points('sinusoidal', [3, 1, -2, 3])
        >>> print(points_sinusoidal)
        [-3.5708, 2.7124, 8.9956, 15.2788, 21.5619, '-3.5708 + 6.2832k']
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    positive_integer(precision)

    # Determine intercepts based on equation type
    result = []
    if equation_type == 'linear':
        result = linear_roots(*coefficients, precision)
    elif equation_type == 'quadratic':
        result = quadratic_roots(*coefficients, precision)
    elif equation_type == 'cubic':
        result = cubic_roots(*coefficients, precision)
    elif equation_type == 'hyperbolic':
        result = hyperbolic_roots(*coefficients, precision)
    elif equation_type == 'exponential':
        result = exponential_roots(*coefficients, precision)
    elif equation_type == 'logarithmic':
        result = logarithmic_roots(*coefficients, precision)
    elif equation_type == 'logistic':
        result = logistic_roots(*coefficients, precision)
    elif equation_type == 'sinusoidal':
        result = sinusoidal_roots(*coefficients, precision)
    return result
Example #6
0
def average_values(equation_type, coefficients, start, end, precision=4):
    """
    Calculates the average values for a specific function

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which average values must be determined (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients of the origianl function under investigation
    start : int or float
        Value of the x-coordinate of the first point to use for evaluating the average values; results within lists must be greater than this value
    end : int or float
        Value of the x-coordinate of the second point to use for evaluating the average values; results within lists must be less than this value
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the result

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    TypeError
        Third and fourth arguments must be integers or floats
    ValueError
        Third argument must be less than or equal to fourth argument
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    averages['average_value_derivative'] : float
        Slope of a function between two points
    averages['mean_values_derivative'] : list of float or str
        Values of the x-coordinates within the specified interval at which the original function has a value equal to its average value over that entire interval; if the function is sinusoidal, then only the initial results within at most a four-period interval within the specified interval will be listed, but general forms will also be included (however, their results may be outside the specified interval); if the algorithm cannot determine any values, then it will return a list of `None`
    averages['average_value_integral'] : float
        Average value of the function between two points
    averages['mean_values_integral'] : list of float or str
        Values of the x-coordinates within the specified interval at which the original function has a value equal to its average value over that entire interval; if the function is sinusoidal, then only the initial results within at most a four-period interval within the specified interval will be listed, but general forms will also be included (however, their results may be outside the specified interval); if the algorithm cannot determine any values, then it will return a list of `None`

    See Also
    --------
    :func:`~regressions.analyses.mean_values.average_value_derivative`, :func:`~regressions.analyses.mean_values.mean_values_derivative`, :func:`~regressions.analyses.mean_values.average_value_integral`, :func:`~regressions.analyses.mean_values.mean_values_integral`

    Notes
    -----
    - |mean_derivatives|
    - |mean_integrals|

    Examples
    --------
    Import `average_values` function from `regressions` library
        >>> from regressions.analyses.mean_values import average_values
    Calculate the averages of a cubic function with coefficients 2, 3, 5, and 7 between 10 and 20
        >>> averages_cubic = average_values('cubic', [2, 3, 5, 7], 10, 20)
        >>> print(averages_cubic['average_value_derivative'])
        1495.0
        >>> print(averages_cubic['mean_values_derivative'])
        [15.2665]
        >>> print(averages_cubic['average_value_integral'])
        8282.0
        >>> print(averages_cubic['mean_values_integral'])
        [15.5188]
    Calculate the averages of a sinusoidal function with coefficients 2, 3, 5, and 7 between 10 and 20
        >>> averages_sinusoidal = average_values('sinusoidal', [2, 3, 5, 7], 10, 20)
        >>> print(averages_sinusoidal['average_value_derivative'])
        0.0401
        >>> print(averages_sinusoidal['mean_values_derivative'])
        [10.7618, 11.8046, 12.8562, 13.899, 14.9506, 15.9934, 17.045, 18.0878, 19.1394, '10.7618 + 2.0944k', '11.8046 + 2.0944k']
        >>> print(averages_sinusoidal['average_value_integral'])
        6.9143
        >>> print(averages_sinusoidal['mean_values_integral'])
        [10.2503, 11.2689, 12.3447, 13.3633, 14.4391, 15.4577, 16.5335, 17.5521, 18.6279, 19.6465, '10.2503 + 2.0944k', '11.2689 + 2.0944k']
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    compare_scalars(start, end, 'third', 'fourth')
    positive_integer(precision)

    # Determine various mean values
    derivative_value = average_value_derivative(equation_type, coefficients,
                                                start, end, precision)
    derivative_inputs = mean_values_derivative(equation_type, coefficients,
                                               start, end, precision)
    integral_value = average_value_integral(equation_type, coefficients, start,
                                            end, precision)
    integral_inputs = mean_values_integral(equation_type, coefficients, start,
                                           end, precision)

    # Package all values in single dictionary
    results = {
        'average_value_derivative': derivative_value,
        'mean_values_derivative': derivative_inputs,
        'average_value_integral': integral_value,
        'mean_values_integral': integral_inputs
    }
    return results
Example #7
0
def mean_values_integral(equation_type, coefficients, start, end, precision=4):
    """
    Generates a list of all the x-coordinates between two points at which a function's value will equal its average value over that interval

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which an average value must be determined (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients of the origianl function under investigation
    start : int or float
        Value of the x-coordinate of the first point to use for evaluating the average value; all results must be greater than this value
    end : int or float
        Value of the x-coordinate of the second point to use for evaluating the average value; all results must be less than this value
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the result

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    TypeError
        Third and fourth arguments must be integers or floats
    ValueError
        Third argument must be less than or equal to fourth argument
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    points : list of float or str
        Values of the x-coordinates within the specified interval at which the original function has a value equal to its average value over that entire interval; if the function is sinusoidal, then only the initial results within at most a four-period interval within the specified interval will be listed, but general forms will also be included (however, their results may be outside the specified interval); if the algorithm cannot determine any values, then it will return a list of `None`

    See Also
    --------
    - Roots for key functions: :func:`~regressions.analyses.roots.linear.linear_roots`, :func:`~regressions.analyses.roots.quadratic.quadratic_roots`, :func:`~regressions.analyses.roots.cubic.cubic_roots`, :func:`~regressions.analyses.roots.hyperbolic.hyperbolic_roots`, :func:`~regressions.analyses.roots.exponential.exponential_roots`, :func:`~regressions.analyses.roots.logarithmic.logarithmic_roots`, :func:`~regressions.analyses.roots.logistic.logistic_roots`, :func:`~regressions.analyses.roots.sinusoidal.sinusoidal_roots`
    - Mean values: :func:`~regressions.analyses.mean_values.average_value_integral`, :func:`~regressions.analyses.mean_values.average_value_derivative`, :func:`~regressions.analyses.mean_values.mean_values_derivative`

    Notes
    -----
    - Mean values for the integral over an interval: :math:`f(c) = \\frac{1}{b - a}\\cdot{\\int_{a}^{b} f(x) \\,dx}` 
    - |mean_integrals|

    Examples
    --------
    Import `mean_values_integral` function from `regressions` library
        >>> from regressions.analyses.mean_values import mean_values_integral
    Generate a list of all the x-coordinates of a cubic function with coefficients 2, 3, 5, and 7 at which the function's value will equal its average value between 10 and 20
        >>> points_cubic = mean_values_integral('cubic', [2, 3, 5, 7], 10, 20)
        >>> print(points_cubic)
        [15.5188]
    Generate a list of all the x-coordinates of a sinusoidal function with coefficients 2, 3, 5, and 7 at which the function's value will equal its average value between 10 and 20
        >>> points_sinusoidal = mean_values_integral('sinusoidal', [2, 3, 5, 7], 10, 20)
        >>> print(points_sinusoidal)
        [10.2503, 11.2689, 12.3447, 13.3633, 14.4391, 15.4577, 16.5335, 17.5521, 18.6279, 19.6465, '10.2503 + 2.0944k', '11.2689 + 2.0944k']
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    compare_scalars(start, end, 'third', 'fourth')
    positive_integer(precision)

    # Create list to return
    result = []

    # Determine average value of function over interval
    average = average_value_integral(equation_type, coefficients, start, end,
                                     precision)

    # Circumvent division by zero
    if average == 0:
        average = 10**(-precision)

    # Determine points satisfying theorem based on equation type
    if equation_type == 'linear':
        result = linear_roots_initial_value(*coefficients, average, precision)
    elif equation_type == 'quadratic':
        result = quadratic_roots_initial_value(*coefficients, average,
                                               precision)
    elif equation_type == 'cubic':
        result = cubic_roots_initial_value(*coefficients, average, precision)
    elif equation_type == 'hyperbolic':
        result = hyperbolic_roots_initial_value(*coefficients, average,
                                                precision)
    elif equation_type == 'exponential':
        result = exponential_roots_initial_value(*coefficients, average,
                                                 precision)
    elif equation_type == 'logarithmic':
        result = logarithmic_roots_initial_value(*coefficients, average,
                                                 precision)
    elif equation_type == 'logistic':
        result = logistic_roots_initial_value(*coefficients, average,
                                              precision)
    elif equation_type == 'sinusoidal':
        options = sinusoidal_roots_initial_value(*coefficients, average,
                                                 precision)
        result = shifted_points_within_range(options, start, end, precision)

    # Eliminate points outside of interval
    final_result = points_within_range(result, start, end)
    return final_result
Example #8
0
def average_value_derivative(equation_type,
                             coefficients,
                             start,
                             end,
                             precision=4):
    """
    Evaluates the average rate of change between two points for a given function

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which the definite integral must be evaluated (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients of the original function to use for evaluating the average rate of change
    start : int or float
        Value of the x-coordinate of the first point to use for evaluating the rate of change
    end : int or float
        Value of the x-coordinate of the second point to use for evaluating the rate of change
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the result

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    TypeError
        Third and fourth arguments must be integers or floats
    ValueError
        Third argument must be less than or equal to fourth argument
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    average : float
        Slope of a function between two points; if start and end values are identical, then slope will be zero

    See Also
    --------
    :func:`~regressions.analyses.mean_values.mean_values_derivative`, 
    :func:`~regressions.analyses.mean_values.average_value_integral`, :func:`~regressions.analyses.mean_values.mean_values_integral`

    Notes
    -----
    - Slope of a function over an interval: :math:`m = \\frac{f(b) - f(a)}{b - a}`
    - |mean_derivatives|

    Examples
    --------
    Import `average_value_derivative` function from `regressions` library
        >>> from regressions.analyses.mean_values import average_value_derivative
    Evaluate the average rate of change of a cubic function with coefficients 2, 3, 5, and 7 between end points of 10 and 20
        >>> average_cubic = average_value_derivative('cubic', [2, 3, 5, 7], 10, 20)
        >>> print(average_cubic)
        1495.0
    Evaluate the average rate of change of a sinusoidal function with coefficients 2, 3, 5, and 7 between end points of 10 and 20
        >>> average_sinusoidal = average_value_derivative('sinusoidal', [2, 3, 5, 7], 10, 20)
        >>> print(average_sinusoidal)
        0.0401
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    compare_scalars(start, end, 'third', 'fourth')
    positive_integer(precision)

    # Create equation based on equation type
    equation = lambda x: x
    if equation_type == 'linear':
        equation = linear_equation(*coefficients, precision)
    elif equation_type == 'quadratic':
        equation = quadratic_equation(*coefficients, precision)
    elif equation_type == 'cubic':
        equation = cubic_equation(*coefficients, precision)
    elif equation_type == 'hyperbolic':
        equation = hyperbolic_equation(*coefficients, precision)
    elif equation_type == 'exponential':
        equation = exponential_equation(*coefficients, precision)
    elif equation_type == 'logarithmic':
        equation = logarithmic_equation(*coefficients, precision)
    elif equation_type == 'logistic':
        equation = logistic_equation(*coefficients, precision)
    elif equation_type == 'sinusoidal':
        equation = sinusoidal_equation(*coefficients, precision)

    # Create intermediary variables
    vertical_change = equation(end) - equation(start)
    horizontal_change = end - start

    # Circumvent division by zero
    if horizontal_change == 0:
        horizontal_change = 10**(-precision)

    # Determine average slope
    ratio = vertical_change / horizontal_change
    result = rounded_value(ratio, precision)
    return result
Example #9
0
def average_value_integral(equation_type,
                           coefficients,
                           start,
                           end,
                           precision=4):
    """
    Evaluates the average value of a given function between two points

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which the definite integral must be evaluated (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients of the original function to integrate
    start : int or float
        Value of the x-coordinate of the first point to use for evaluating the average value
    end : int or float
        Value of the x-coordinate of the second point to use for evaluating the average value
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the result

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    TypeError
        Third and fourth arguments must be integers or floats
    ValueError
        Third argument must be less than or equal to fourth argument
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    average : float
        Average value of the function between two points; if start and end values are identical, then average value will be zero

    See Also
    --------
    :func:`~regressions.analyses.accumulation.accumulated_area`, :func:`~regressions.analyses.mean_values.mean_values_integral`, :func:`~regressions.analyses.mean_values.average_value_derivative`, :func:`~regressions.analyses.mean_values.mean_values_derivative`

    Notes
    -----
    - Average value of a function over an interval: :math:`f_{avg} = \\frac{1}{b - a}\\cdot{\\int_{a}^{b} f(x) \\,dx}`
    - |mean_integrals|

    Examples
    --------
    Import `average_value_integral` function from `regressions` library
        >>> from regressions.analyses.mean_values import average_value_integral
    Evaluate the average value of a cubic function with coefficients 2, 3, 5, and 7 between end points of 10 and 20
        >>> average_cubic = average_value_integral('cubic', [2, 3, 5, 7], 10, 20)
        >>> print(average_cubic)
        8282.0
    Evaluate the average value of a sinusoidal function with coefficients 2, 3, 5, and 7 between end points of 10 and 20
        >>> average_sinusoidal = average_value_integral('sinusoidal', [2, 3, 5, 7], 10, 20)
        >>> print(average_sinusoidal)
        6.9143
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    compare_scalars(start, end, 'third', 'fourth')
    positive_integer(precision)

    # Determine accumulated value of function over interval
    accumulated_value = accumulated_area(equation_type, coefficients, start,
                                         end, precision)

    # Create intermediary variable
    change = end - start

    # Circumvent division by zero
    if change == 0:
        change = 10**(-precision)

    # Determine average value of function over interval
    ratio = accumulated_value / change

    # Round value
    rounded_ratio = rounded_value(ratio, precision)

    # Return result
    result = rounded_ratio
    return result
Example #10
0
def minima_points(equation_type, coefficients, precision = 4):
    """
    Calculates the minima of a specific function

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which the minima must be determined (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients to use to generate the equation to investigate
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the results

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    points : list of float
        Values of the x-coordinates at which the original function has a relative minimum; if the function is sinusoidal, then only two or three results within a two-period interval will be listed; if the function has no minima, then it will return a list of `None`

    See Also
    --------
    - Roots for key functions: :func:`~regressions.analyses.roots.linear.linear_roots`, :func:`~regressions.analyses.roots.quadratic.quadratic_roots`, :func:`~regressions.analyses.roots.cubic.cubic_roots`, :func:`~regressions.analyses.roots.hyperbolic.hyperbolic_roots`, :func:`~regressions.analyses.roots.exponential.exponential_roots`, :func:`~regressions.analyses.roots.logarithmic.logarithmic_roots`, :func:`~regressions.analyses.roots.logistic.logistic_roots`, :func:`~regressions.analyses.roots.sinusoidal.sinusoidal_roots`
    - Graphical analysis: :func:`~regressions.analyses.criticals.critical_points`, :func:`~regressions.analyses.intervals.sign_chart`, :func:`~regressions.analyses.maxima.maxima_points`, :func:`~regressions.analyses.extrema.extrema_points`, :func:`~regressions.analyses.points.key_coordinates`

    Notes
    -----
    - Critical points for the derivative of a function: :math:`c_i = \\{ c_1, c_2, c_3,  \\cdots, c_{n-1}, c_n \\}`
    - X-coordinates of the minima of the function: :math:`x_{min} = \\{ x \\mid x \\in c_i, f'(\\frac{c_{j-1} + c_j}{2}) < 0, f'(\\frac{c_j + c_{j+1}}{2}) > 0 \\}`
    - |minima_values|

    Examples
    --------
    Import `minima_points` function from `regressions` library
        >>> from regressions.analyses.minima import minima_points
    Calculate the minima of a cubic function with coefficients 1, -15, 63, and -7
        >>> points_cubic = minima_points('cubic', [1, -15, 63, -7])
        >>> print(points_cubic)
        [7.0]
    Calculate the minima of a sinusoidal function with coefficients 2, 3, 5, and 7
        >>> points_sinusoidal = minima_points('sinusoidal', [2, 3, 5, 7])
        >>> print(points_sinusoidal)
        [6.5708, 8.6652]
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    positive_integer(precision)
    
    # Create sign chart
    intervals = sign_chart(equation_type, coefficients, 1, precision)
    
    # Determine minima
    result = []
    for i in range(len(intervals)):
        try:
            if intervals[i] == 'negative' and intervals[i + 2] == 'positive':
                result.append(intervals[i + 1])
        except IndexError:
            pass
    
    # Handle no minima
    if len(result) == 0:
        result.append(None)
    return result
def inflection_points(equation_type, coefficients, precision=4):
    """
    Calculates the inflection points of a specific function

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which inflections must be determined (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients to use to generate the equation to investigate
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the results

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    points : list of float or str
        Values of the x-coordinates at which the original function has an inflection point; if the function is sinusoidal, then only five results within a two-period interval will be listed, but a general form will also be included; if the function has no inflection points, then it will return a list of `None`

    See Also
    --------
    - Roots for key functions: :func:`~regressions.analyses.roots.linear.linear_roots`, :func:`~regressions.analyses.roots.quadratic.quadratic_roots`, :func:`~regressions.analyses.roots.cubic.cubic_roots`, :func:`~regressions.analyses.roots.hyperbolic.hyperbolic_roots`, :func:`~regressions.analyses.roots.exponential.exponential_roots`, :func:`~regressions.analyses.roots.logarithmic.logarithmic_roots`, :func:`~regressions.analyses.roots.logistic.logistic_roots`, :func:`~regressions.analyses.roots.sinusoidal.sinusoidal_roots`
    - Graphical analysis: :func:`~regressions.analyses.criticals.critical_points`, :func:`~regressions.analyses.intervals.sign_chart`, :func:`~regressions.analyses.points.key_coordinates`

    Notes
    -----
    - Critical points for the second derivative of a function: :math:`c_i = \\{ c_1, c_2, c_3,  \\cdots, c_{n-1}, c_n \\}`
    - X-coordinates of the inflections of the function: :math:`x_{infl} = \\{ x \\mid x \\in c_i, \\left( f''(\\frac{c_{j-1} + c_j}{2}) < 0 \\cap f''(\\frac{c_j + c_{j+1}}{2}) > 0 \\right) \\\\ \\cup \\left( f''(\\frac{c_{j-1} + c_j}{2}) > 0 \\cap f''(\\frac{c_j + c_{j+1}}{2}) < 0 \\right) \\}`
    - |inflection_points|

    Examples
    --------
    Import `inflection_points` function from `regressions` library
        >>> from regressions.analyses.inflections import inflection_points
    Calculate the inflection points of a cubic functions with coefficients 1, -15, 63, and -7
        >>> points_cubic = inflection_points('cubic', [1, -15, 63, -7])
        >>> print(points_cubic)
        [5.0]
    Calculate the inflection points of a sinusoidal functions with coefficients 2, 3, 5, and 7
        >>> points_sinusoidal = inflection_points('sinusoidal', [2, 3, 5, 7])
        >>> print(points_sinusoidal)
        [5.0, 6.0472, 7.0944, 8.1416, 9.1888, '5.0 + 1.0472k']
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    positive_integer(precision)

    # Create sign chart
    intervals_set = sign_chart(equation_type, coefficients, 2, precision)

    # Handle hyperbolic case
    if equation_type == 'hyperbolic':
        result = [None]
        return result

    # Determine inflections
    result = []
    for i in range(len(intervals_set)):
        try:
            if (intervals_set[i] == 'positive' and intervals_set[i + 2]
                    == 'negative') or (intervals_set[i] == 'negative'
                                       and intervals_set[i + 2] == 'positive'):
                result.append(intervals_set[i + 1])
        except IndexError:
            pass

    # Handle sinusoidal case
    if equation_type == 'sinusoidal':
        result.append(intervals_set[-1])

    # Handle no inflections
    if len(result) == 0:
        result.append(None)
    return result
Example #12
0
def critical_points(equation_type,
                    coefficients,
                    derivative_level,
                    precision=4):
    """
    Calculates the critical points of a specific function at a certain derivative level

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which critical points must be determined (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients to use to generate the equation to investigate
    derivative_level : int
        Integer corresponding to which derivative to investigate for critical points (1 for the first derivative and 2 for the second derivative)
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the results

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    ValueError
        Third argument must be one of the following integers: [1, 2]
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    points : list of float or str
        Values of the x-coordinates at which the original function's derivative either crosses the x-axis or does not exist; if the function is sinusoidal, then only five results within a two-period interval will be listed, but a general form will also be included; if the derivative has no critical points, then it will return a list of `None`

    See Also
    --------
    - Roots for key functions: :func:`~regressions.analyses.roots.linear.linear_roots`, :func:`~regressions.analyses.roots.quadratic.quadratic_roots`, :func:`~regressions.analyses.roots.cubic.cubic_roots`, :func:`~regressions.analyses.roots.hyperbolic.hyperbolic_roots`, :func:`~regressions.analyses.roots.exponential.exponential_roots`, :func:`~regressions.analyses.roots.logarithmic.logarithmic_roots`, :func:`~regressions.analyses.roots.logistic.logistic_roots`, :func:`~regressions.analyses.roots.sinusoidal.sinusoidal_roots`
    - Graphical analysis: :func:`~regressions.analyses.intervals.sign_chart`, :func:`~regressions.analyses.points.key_coordinates`

    Notes
    -----
    - Domain of a function: :math:`x_i = \\{ x_1, x_2, \\cdots, x_n \\}`
    - Potential critical points of the derivative of the function: :math:`x_c = \\{ c \\mid c \\in x_i, f'(c) = 0 \\cup f'(c) = \\varnothing \\}`
    - |critical_points|

    Examples
    --------
    Import `critical_points` function from `regressions` library
        >>> from regressions.analyses.criticals import critical_points
    Calulate the critical points of the second derivative of a cubic function with coefficients 2, 3, 5, and 7
        >>> points_cubic = critical_points('cubic', [2, 3, 5, 7], 2)
        >>> print(points_cubic)
        [-0.5]
    Calulate the critical points of the first derivative of a sinusoidal function with coefficients 2, 3, 5, and 7
        >>> points_sinusoidal = critical_points('sinusoidal', [2, 3, 5, 7], 1)
        >>> print(points_sinusoidal)
        [5.5236, 6.5708, 7.618, 8.6652, 9.7124, '5.5236 + 1.0472k']
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    select_integers(derivative_level, [1, 2], 'third')
    positive_integer(precision)

    # Create list to return
    results = []

    # Determine critical points for first derivative based on equation type
    if derivative_level == 1:
        if equation_type == 'linear':
            results = linear_roots_first_derivative(*coefficients, precision)
        elif equation_type == 'quadratic':
            results = quadratic_roots_first_derivative(*coefficients,
                                                       precision)
        elif equation_type == 'cubic':
            results = cubic_roots_first_derivative(*coefficients, precision)
        elif equation_type == 'hyperbolic':
            results = hyperbolic_roots_first_derivative(
                *coefficients, precision)
        elif equation_type == 'exponential':
            results = exponential_roots_first_derivative(
                *coefficients, precision)
        elif equation_type == 'logarithmic':
            results = logarithmic_roots_first_derivative(
                *coefficients, precision)
        elif equation_type == 'logistic':
            results = logistic_roots_first_derivative(*coefficients, precision)
        elif equation_type == 'sinusoidal':
            results = sinusoidal_roots_first_derivative(
                *coefficients, precision)

    # Determine critical points for second derivative based on equation type
    elif derivative_level == 2:
        if equation_type == 'linear':
            results = linear_roots_second_derivative(*coefficients, precision)
        elif equation_type == 'quadratic':
            results = quadratic_roots_second_derivative(
                *coefficients, precision)
        elif equation_type == 'cubic':
            results = cubic_roots_second_derivative(*coefficients, precision)
        elif equation_type == 'hyperbolic':
            results = hyperbolic_roots_second_derivative(
                *coefficients, precision)
        elif equation_type == 'exponential':
            results = exponential_roots_second_derivative(
                *coefficients, precision)
        elif equation_type == 'logarithmic':
            results = logarithmic_roots_second_derivative(
                *coefficients, precision)
        elif equation_type == 'logistic':
            results = logistic_roots_second_derivative(*coefficients,
                                                       precision)
        elif equation_type == 'sinusoidal':
            results = sinusoidal_roots_second_derivative(
                *coefficients, precision)
    return results
Example #13
0
 def test_select_equations_included(self):
     select_equations_multiple = select_equations(good_equation)
     self.assertEqual(
         select_equations_multiple,
         "First argument is either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'"
     )
Example #14
0
def accumulated_area(equation_type, coefficients, start, end, precision=4):
    """
    Evaluates the definite integral between two points for a specific function

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which the definite integral must be evaluated (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients of the original function to integrate
    start : int or float
        Value of the x-coordinate of the first point to use for evaluating the definite integral
    end : int or float
        Value of the x-coordinate of the second point to use for evaluating the definite integral
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the result

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    TypeError
        Third and fourth arguments must be integers or floats
    ValueError
        Third argument must be less than or equal to fourth argument
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    area : float
        Definite integral of the original equation, evaluated between two points; if start and end values are identical, then definite integral will be zero

    See Also
    --------
    :func:`~regressions.analyses.integrals.linear.linear_integral`, :func:`~regressions.analyses.integrals.quadratic.quadratic_integral`, :func:`~regressions.analyses.integrals.cubic.cubic_integral`, :func:`~regressions.analyses.integrals.hyperbolic.hyperbolic_integral`, :func:`~regressions.analyses.integrals.exponential.exponential_integral`, :func:`~regressions.analyses.integrals.logarithmic.logarithmic_integral`, :func:`~regressions.analyses.integrals.logistic.logistic_integral`, :func:`~regressions.analyses.integrals.sinusoidal.sinusoidal_integral`

    Notes
    -----
    - Definite integral of a function: :math:`\\int_{a}^{b} f(x) \\,dx = F(b) - F(a)`
    - |definite_integral|
    - |fundamental_theorem|

    Examples
    --------
    Import `accumulated_area` function from `regressions` library
        >>> from regressions.analyses.accumulation import accumulated_area
    Evaluate the definite integral of a linear function with coefficients 2 and 3 between the end points 10 and 20
        >>> area_linear = accumulated_area('linear', [2, 3], 10, 20)
        >>> print(area_linear)
        330.0
    Evaluate the definite integral of a cubic function with coefficients 8, 6, -10, and 7 between the end points 10 and 20
        >>> area_cubic = accumulated_area('cubic', [8, 6, -10, 7], 10, 20)
        >>> print(area_cubic)
        312570.0
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    compare_scalars(start, end, 'third', 'fourth')
    positive_integer(precision)

    # Create indefinite integral based on equation type
    integral = lambda x: x
    if equation_type == 'linear':
        integral = linear_integral(*coefficients, precision)['evaluation']
    elif equation_type == 'quadratic':
        integral = quadratic_integral(*coefficients, precision)['evaluation']
    elif equation_type == 'cubic':
        integral = cubic_integral(*coefficients, precision)['evaluation']
    elif equation_type == 'hyperbolic':
        integral = hyperbolic_integral(*coefficients, precision)['evaluation']
    elif equation_type == 'exponential':
        integral = exponential_integral(*coefficients, precision)['evaluation']
    elif equation_type == 'logarithmic':
        integral = logarithmic_integral(*coefficients, precision)['evaluation']
    elif equation_type == 'logistic':
        integral = logistic_integral(*coefficients, precision)['evaluation']
    elif equation_type == 'sinusoidal':
        integral = sinusoidal_integral(*coefficients, precision)['evaluation']

    # Evaluate definite integral
    area = integral(end) - integral(start)

    # Round evaluation
    result = rounded_value(area, precision)
    return result
Example #15
0
def sign_chart(equation_type, coefficients, derivative_level, precision=4):
    """
    Creates a sign chart for a given derivative

    Parameters
    ----------
    equation_type : str
        Name of the type of function for which the sign chart must be constructed (e.g., 'linear', 'quadratic')
    coefficients : list of int or float
        Coefficients to use to generate the equation to investigate
    derivative_level : int
        Integer corresponding to which derivative to investigate for sign chart (1 for the first derivative and 2 for the second derivative)
    precision : int, default=4
        Maximum number of digits that can appear after the decimal place of the results

    Raises
    ------
    ValueError
        First argument must be either 'linear', 'quadratic', 'cubic', 'hyperbolic', 'exponential', 'logarithmic', 'logistic', or 'sinusoidal'
    TypeError
        Second argument must be a 1-dimensional list containing elements that are integers or floats
    ValueError
        Third argument must be one of the following integers: [1, 2]
    ValueError
        Last argument must be a positive integer

    Returns
    -------
    chart : list of str and float
        Strings describing the sign (e.g., 'positive', 'negative') of the derivative between its critical points; as a result, its elements will alternate between strings (indicating the signs) and floats (indicating the end points); if the function is sinusoidal, then only the initial results within a two-period interval will be listed, but a general form to determine other end points will also be included

    See Also
    --------
    - Roots for key functions: :func:`~regressions.analyses.roots.linear.linear_roots`, :func:`~regressions.analyses.roots.quadratic.quadratic_roots`, :func:`~regressions.analyses.roots.cubic.cubic_roots`, :func:`~regressions.analyses.roots.hyperbolic.hyperbolic_roots`, :func:`~regressions.analyses.roots.exponential.exponential_roots`, :func:`~regressions.analyses.roots.logarithmic.logarithmic_roots`, :func:`~regressions.analyses.roots.logistic.logistic_roots`, :func:`~regressions.analyses.roots.sinusoidal.sinusoidal_roots`
    - Graphical analysis: :func:`~regressions.analyses.criticals.critical_points`, :func:`~regressions.analyses.points.key_coordinates`

    Notes
    -----
    - Critical points for the derivative of a function: :math:`c_i = \\{ c_1, c_2, c_3,  \\cdots, c_{n-1}, c_n \\}`
    - Midpoints and key values of the intervals demarcated by the critical points: :math:`m_i = \\{ c_1 - 1,  \\frac{c_1+c_2}{2}, \\frac{c_2+c_3}{2}, \\cdots, \\frac{c_{n-1}+c_n}{2}, c_n + 1 \\}`
    - Values of the derivative within the intervals: :math:`v_i = \\{ v_1, v_2, v_3, v_4 \\cdots, v_{n-1}, v_n, v_{n+1} \\}`
    - Sign chart: :math:`s = ( v_1, c_1, v_2, c_2, v_3, c_3, v_4, \\dots, v_{n-1}, c_{n-1}, v_n, c_n, v_{n+1} )`

        - :math:`v_j = negative` if :math:`f'(m_j) < 0`
        - :math:`v_j = constant` if :math:`f'(m_j) = 0`
        - :math:`v_j = positve` if :math:`f'(m_j) > 0`

    - |intervals|

    Examples
    --------
    Import `sign_chart` function from `regressions` library
        >>> from regressions.analyses.intervals import sign_chart
    Create the sign chart for the first derivative of a cubic function with coefficients 1, -15, 63, and -7
        >>> chart_cubic = sign_chart('cubic', [1, -15, 63, -7], 1)
        >>> print(chart_cubic)
        ['positive', 3.0, 'negative', 7.0, 'positive']
    Create the sign chart for the second derivative of a sinusoidal function with coefficients 2, 3, 5, and 7
        >>> chart_sinusoidal = sign_chart('sinusoidal', [2, 3, 5, 7], 2)
        >>> print(chart_sinusoidal)
        ['positive', 5.0, 'negative', 6.0472, 'positive', 7.0944, 'negative', 8.1416, 'positive', 9.1888, 'negative', '5.0 + 1.0472k']
    """
    # Handle input errors
    select_equations(equation_type)
    vector_of_scalars(coefficients, 'second')
    select_integers(derivative_level, [1, 2], 'third')
    positive_integer(precision)

    # Create first and second derivatives based on equation type
    both_derivatives = {}
    if equation_type == 'linear':
        both_derivatives = linear_derivatives(*coefficients, precision)
    elif equation_type == 'quadratic':
        both_derivatives = quadratic_derivatives(*coefficients, precision)
    elif equation_type == 'cubic':
        both_derivatives = cubic_derivatives(*coefficients, precision)
    elif equation_type == 'hyperbolic':
        both_derivatives = hyperbolic_derivatives(*coefficients, precision)
    elif equation_type == 'exponential':
        both_derivatives = exponential_derivatives(*coefficients, precision)
    elif equation_type == 'logarithmic':
        both_derivatives = logarithmic_derivatives(*coefficients, precision)
    elif equation_type == 'logistic':
        both_derivatives = logistic_derivatives(*coefficients, precision)
    elif equation_type == 'sinusoidal':
        both_derivatives = sinusoidal_derivatives(*coefficients, precision)

    # Grab specific derivative evaluation based on derivative level
    derivative = lambda x: x
    if derivative_level == 1:
        derivative = both_derivatives['first']['evaluation']
    elif derivative_level == 2:
        derivative = both_derivatives['second']['evaluation']

    # Create critical points for specific derivative
    points = critical_points(equation_type, coefficients, derivative_level,
                             precision)

    # Create sign chart for specific derivative
    result = []

    # Handle no critical points
    if points[0] == None:
        # Test an arbitrary number
        if derivative(10) > 0:
            result = ['positive']
        elif derivative(10) < 0:
            result = ['negative']
        else:
            result = ['constant']

    # Handle exactly one critical point
    elif len(points) == 1:
        # Generate numbers to test
        turning_point = points[0]
        before = turning_point - 1
        after = turning_point + 1

        # Test numbers
        if derivative(before) > 0:
            before = 'positive'
        elif derivative(before) < 0:
            before = 'negative'
        if derivative(after) > 0:
            after = 'positive'
        elif derivative(after) < 0:
            after = 'negative'

        # Store sign chart
        result = [before, turning_point, after]

    # Handle exactly two critical points
    elif len(points) == 2:
        # Generate numbers to test
        sorted_points = sorted_list(points)
        first_point = sorted_points[0]
        second_point = sorted_points[1]
        middle = (first_point + second_point) / 2
        before = first_point - 1
        after = second_point + 1

        # Test numbers
        if derivative(before) > 0:
            before = 'positive'
        elif derivative(before) < 0:
            before = 'negative'
        if derivative(middle) > 0:
            middle = 'positive'
        elif derivative(middle) < 0:
            middle = 'negative'
        if derivative(after) > 0:
            after = 'positive'
        elif derivative(after) < 0:
            after = 'negative'

        # Store sign chart
        result = [before, first_point, middle, second_point, after]

    # Handle more than two critical points
    else:
        # Separate numerical inputs from string inputs
        separated_points = separate_elements(points)
        numerical_points = separated_points['numerical']
        other_points = separated_points['other']

        # Generate numbers to test
        sorted_points = sorted_list(numerical_points)
        difference = sorted_points[1] - sorted_points[0]
        halved_difference = difference / 2
        before_first = sorted_points[0] - halved_difference
        between_first_second = sorted_points[0] + halved_difference
        between_second_third = sorted_points[1] + halved_difference
        between_third_fourth = sorted_points[2] + halved_difference
        between_fourth_last = sorted_points[3] + halved_difference
        after_last = sorted_points[4] + halved_difference
        test_points = [
            before_first, between_first_second, between_second_third,
            between_third_fourth, between_fourth_last, after_last
        ]

        # Test numbers
        signs = []
        for point in test_points:
            if derivative(point) > 0:
                signs.append('positive')
            elif derivative(point) < 0:
                signs.append('negative')

        # Store sign chart
        result = [
            signs[0], sorted_points[0], signs[1], sorted_points[1], signs[2],
            sorted_points[2], signs[3], sorted_points[3], signs[4],
            sorted_points[4], signs[5], *other_points
        ]
    return result