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'" )
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
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
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
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
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
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
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
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
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
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
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'" )
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
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