Module game_qu.math.piecewise_function

Expand source code
from copy import deepcopy

from game_qu.math.derivative import Derivative
from game_qu.math.function import Function
from game_qu.base.utility_functions import modified_mod, is_within_bounds, min_value
from game_qu.math.indefinite_integral import IndefiniteIntegral


class PiecewiseFunction(Function):
    """ A function that is made up of multiple functions. The function uses different functions depending on what the x
        coordinate is and if it falls within the other function"""

    functions = []
    is_repeating = False
    x_coordinates_can_be_less_than_min = True
    min_x_coordinate = 0
    max_x_coordinate = 0

    def __init__(self, functions):
        """Initializes the object with the functions"""

        self.set_functions(functions)

    def get_functions(self):
        """
             Returns:
                BoundedFunction: all the functions of the piecewise function"""

        return self.functions

    def set_functions(self, functions):
        """Sets the functions of the piecewise function

             Returns:
                PiecewiseFunction: 'self'"""

        self.functions = functions
        self.update_function_bounds_fully()
        return self

    def get_piecewise_function_with_functions(self, functions):
        """
             Returns:
                PiecewiseFunction: a piecewise function with functions attribute being set to 'functions' (does not modify the current piecewise function)"""

        return self.get_copy().set_functions(functions)

    def get_copy(self):
        """
             Returns:
                PiecewiseFunction: a copy of the current piecewise_function"""

        # return deepcopy(self)
        new_functions = []
        copy = PiecewiseFunction(new_functions)
        for val in self.get_functions():
            new_functions.append(val)

        copy.set_is_repeating(self.is_repeating)
        copy.set_x_coordinates_can_be_less_than_min(self.x_coordinates_can_be_less_than_min)
        return copy


    def get_x_coordinates_can_be_less_than_min(self):
        """
             Returns:
                bool: whether the x coordinates this function accepts can be less than the min x coordinate"""

        return self.x_coordinates_can_be_less_than_min

    def set_x_coordinates_can_be_less_than_min(self, x_coordinates_can_be_less_than_min):
        """ Sets whether the x coordinates this function accepts can be less than the min x coordinate

             Returns:
                BoundedFunction: 'self'"""

        self.x_coordinates_can_be_less_than_min = x_coordinates_can_be_less_than_min
        return self

    def get_bounded_function_with_x_coordinates_less_than_min(self, x_coordinates_can_be_less_than_min):
        """
             Returns:
                PiecewiseFunction: a piecewise function with the is repeating attribute set to 'x_coordinates_can_be_less_than_min' (does not modify the current piecewise function)"""

        return self.get_copy().set_x_coordinates_can_be_less_than_min(x_coordinates_can_be_less_than_min)

    def get_is_repeating(self):
        """
             Returns:
                boolean: whether the piecewise function repeats"""

        return self.is_repeating

    def set_is_repeating(self, is_repeating):
        """Sets the is_repeating attribute to 'is_repeating'

             Returns:
                PiecewiseFunction: 'self'"""

        self.is_repeating = is_repeating
        return self

    def get_piecewise_function_with_is_repeating(self, is_repeating):
        """
             Returns:
                PiecewiseFunction: a piecewise function with the is repeating attribute set to 'is_repeating' (does not modify the current piecewise function)"""

        return self.get_copy().set_is_repeating(is_repeating)

    def update_function_bounds_fully(self):
        """Updates the function bounds for operations like remove (has to check every function in the list)"""

        if len(self.functions) == 0:
            return

        self.functions = sorted(self.functions, key=lambda x: x.get_min_x_coordinate())
        self.min_x_coordinate = self.functions[0].get_min_x_coordinate()

        max_index = len(self.functions) - 1
        self.max_x_coordinate = self.functions[max_index].get_max_x_coordinate()

    def update_function_bounds_for_added_function(self, function):
        """Updates the function bounds when a function is added (do not have to check every function in list)"""

        self.min_x_coordinate = min(self.min_x_coordinate, function.get_min_x_coordinate())
        self.max_x_coordinate = max(self.max_x_coordinate, function.get_max_x_coordinate())

    def validate_function_bounds_do_not_overlap(self):
        """Raises a ValueError if the function bounds overlap (if there are overlapping bounds the piecewise function is invalidated)"""

        for i in range(len(self.functions)):
            for j in range(len(self.functions)):
                function1 = self.functions[i]
                function2 = self.functions[j]

                a, b = function1.get_bounds()
                c, d = function2.get_bounds()

                # If the function1's bounds fall within function2's bounds (case 1) or it crosses the bounds of
                # function2 (case 2) then this is no longer a valid piecewise function.
                is_invalid = a <= c <= b
                distance_between_c_and_a = a - c
                function1_bound_size = b - a
                is_invalid |= distance_between_c_and_a >= function1_bound_size

                if is_invalid:
                        raise ValueError("The bounds of each function within the piecewise function must not overlap")

    def clear_functions(self):
        """ Clears all functions from the piecewise function

            Returns:
                PiecewiseFunction: 'self'"""

        self.functions.clear()
        self.min_x_coordinate = 0
        self.max_x_coordinate = 0
        return self

    def get_piecewise_function_with_cleared_functions(self):
        """
             Returns a new PiecewiseFunction with cleared functions (does not modify the current piecewise function)

             Returns:
                PiecewiseFunction: new piecewise function with cleared functions"""

        return self.get_copy().clear_functions()

    def add_function(self, new_function):
        """ Adds a new function to the piecewise function

            Args:
                new_function (Function): function to be added

            Returns:
                PiecewiseFunction: 'self'"""

        self.functions.append(new_function)
        self.validate_function_bounds_do_not_overlap()
        self.update_function_bounds_fully()
        return self

    def get_piecewise_function_with_added_function(self, new_function):
        """
             Returns: a new PiecewiseFunction with the added function (does not modify the current piecewise function)
            
            Args:
                new_function (Function): function to be added
            
             Returns:
                PiecewiseFunction: new piecewise function with the added function"""

        return self.get_copy().add_function(new_function)

    def remove_function_at_index(self, index):
        """ Removes a function at the specified index from the piecewise function
            
            Args:
                index (int): index of the function to be removed
            
            Returns:
                PiecewiseFunction: 'self'"""

        if 0 <= index < len(self.functions):
            del self.functions[index]

        self.update_function_bounds_fully()
        return self

    def get_piecewise_function_with_function_removed_at_index(self, index):
        """
             Returns: a new PiecewiseFunction with a function removed at the specified index (does not modify the current piecewise function)
            Args:
                index (int): index of the function to be removed

             Returns:
               PiecewiseFunction: new piecewise function with the function removed at the specified index"""

        return self.get_copy().remove_function_at_index(index)

    def remove_function(self, function):
        """ Removes the specified function from the piecewise function

            Args:
                function (Function): function to be removed

            Returns:
                PiecewiseFunction: 'self'"""

        self.functions.remove(function)
        self.update_function_bounds_fully()
        return self

    def get_piecewise_function_with_function_removed(self, function):
        """
             Returns: a new PiecewiseFunction with the specified function removed (does not modify the current piecewise function)
            Args:
                function (Function): function to be removed

             Returns:
                PiecewiseFunction: new piecewise function with the specified function removed"""

        return self.get_copy().remove_function(function)

    def get_y_coordinate(self, x_coordinate):
        """
             Returns:
                float: the y coordinate associated with that x coordinate"""

        return self.get_function(x_coordinate).get_y_coordinate(x_coordinate)

    def get_function(self, x_coordinate):
        """
             Returns:
                BoundedFunction: the function that controls the piecewise function at the x coordinate"""

        if len(self.functions) == 0:
            raise ValueError("There must be a function in functions in order for the piecewise function to operate")

        if self.is_repeating:
            x_coordinate = modified_mod(x_coordinate, self.bounds_size())

        if not is_within_bounds(x_coordinate, self.min_x_coordinate, self.max_x_coordinate):
            if not self.x_coordinates_can_be_less_than_min:
                raise ValueError("The x coordinate must be greater")

            else:
                return self.get_before_piecewise_function().get_function(x_coordinate)

        for function in self.functions:
            if is_within_bounds(x_coordinate, *function.get_bounds()):
                return function

        raise ValueError("You should not get this value error! This is an implementation error in the code")



    def get_before_piecewise_function(self):
        """
             Returns:
                PiecewiseFunction: a piecewise function that 'comes before' the original"""

        before_piecewise_function = self.get_copy()
        new_x_start = self.min_x_coordinate - self.bounds_size()
        # The relative positions of functions stay the same, so I am just performing a 'domain shift'
        x_position_in_original_function = lambda x: self.get_x_relative_position(new_x_start, x) + self.min_x_coordinate
        before_piecewise_function.get_y_coordinate = lambda x: self.get_y_coordinate(x_position_in_original_function(x))

        return before_piecewise_function

    def get_x_relative_position(self, start, x_coordinate):
        """
             Returns:
                float: the distance x is from start (the relative position within the interval [start, end])"""

        return start - x_coordinate


    def get_min_x_coordinate(self):
        """
             Returns:
                float: the min x coordinate of the piecewise function (min x coordinate of min bounded function)"""

        return self.min_x_coordinate

    def get_max_x_coordinate(self):
        """
             Returns:
                float: the max x coordinate of the piecewise function (max x coordinate of max bounded function)"""

        return self.max_x_coordinate

    def get_bounds(self):
        """
             Returns:
                list[float]: {min_x_coordinate, max_x_coordinate}; the bounds of the peicewise function"""

        return [self.min_x_coordinate, self.max_x_coordinate]

    def bounds_size(self):
        """
             Returns:
                float: the size of the bounds (max - min)"""

        return self.max_x_coordinate - self.min_x_coordinate

    def get_indefinite_integral(self):
        """ Finds and returns the indefinite integral. Raises an AttributeError if any of the functions do not have the
            method: 'get_indefinite_integral'
     
            Returns:
                PiecewiseFunction: the indefinite integral of the polynomial"""

        new_functions = []
        for function in self.functions:
            new_functions.append(function.get_indefinite_integral())

        indefinite_integral = self.get_copy().get_piecewise_function_with_functions(new_functions)
        return indefinite_integral

    def evaluate_area(self, start, end):
        """
             Returns:
                float: the value gotten from using the bounds for the indefinite integral"""

        indefinite_integral = self.get_indefinite_integral()
        area = 0
        current_start = start

        for x in range(len(indefinite_integral.get_functions())):
            bounded_function = indefinite_integral.get_functions()[x]
            min_x, max_x = bounded_function.get_bounds()

            if is_within_bounds(current_start, min_x, max_x):
                end_x = min_value(max_x, end)
                new_area = bounded_function.get_y_coordinate(end_x) - bounded_function.get_y_coordinate(current_start)
                area += new_area
                current_start = end_x

            if current_start == end:
                break

        return area

    def get_derivative(self):
        """ Finds and returns the derivative. Raises an AttributeError if any of the functions do not have the
            method: 'get_derivative'
     
            Returns:
                PiecewiseFunction: the derivative of the polynomial"""

        new_functions = []
        for function in self.functions:
            new_functions.append(function.get_derivative())

        return self.get_piecewise_function_with_functions(new_functions)

    def evaluate_derivative_at_point(self, x_coordinate):
        """
             Returns:
                float: the value of the derivative evaluated at the 'x_coordinate'"""

        return self.get_derivative().get_y_coordinate(x_coordinate)

Classes

class PiecewiseFunction (functions)

A function that is made up of multiple functions. The function uses different functions depending on what the x coordinate is and if it falls within the other function

Initializes the object with the functions

Expand source code
class PiecewiseFunction(Function):
    """ A function that is made up of multiple functions. The function uses different functions depending on what the x
        coordinate is and if it falls within the other function"""

    functions = []
    is_repeating = False
    x_coordinates_can_be_less_than_min = True
    min_x_coordinate = 0
    max_x_coordinate = 0

    def __init__(self, functions):
        """Initializes the object with the functions"""

        self.set_functions(functions)

    def get_functions(self):
        """
             Returns:
                BoundedFunction: all the functions of the piecewise function"""

        return self.functions

    def set_functions(self, functions):
        """Sets the functions of the piecewise function

             Returns:
                PiecewiseFunction: 'self'"""

        self.functions = functions
        self.update_function_bounds_fully()
        return self

    def get_piecewise_function_with_functions(self, functions):
        """
             Returns:
                PiecewiseFunction: a piecewise function with functions attribute being set to 'functions' (does not modify the current piecewise function)"""

        return self.get_copy().set_functions(functions)

    def get_copy(self):
        """
             Returns:
                PiecewiseFunction: a copy of the current piecewise_function"""

        # return deepcopy(self)
        new_functions = []
        copy = PiecewiseFunction(new_functions)
        for val in self.get_functions():
            new_functions.append(val)

        copy.set_is_repeating(self.is_repeating)
        copy.set_x_coordinates_can_be_less_than_min(self.x_coordinates_can_be_less_than_min)
        return copy


    def get_x_coordinates_can_be_less_than_min(self):
        """
             Returns:
                bool: whether the x coordinates this function accepts can be less than the min x coordinate"""

        return self.x_coordinates_can_be_less_than_min

    def set_x_coordinates_can_be_less_than_min(self, x_coordinates_can_be_less_than_min):
        """ Sets whether the x coordinates this function accepts can be less than the min x coordinate

             Returns:
                BoundedFunction: 'self'"""

        self.x_coordinates_can_be_less_than_min = x_coordinates_can_be_less_than_min
        return self

    def get_bounded_function_with_x_coordinates_less_than_min(self, x_coordinates_can_be_less_than_min):
        """
             Returns:
                PiecewiseFunction: a piecewise function with the is repeating attribute set to 'x_coordinates_can_be_less_than_min' (does not modify the current piecewise function)"""

        return self.get_copy().set_x_coordinates_can_be_less_than_min(x_coordinates_can_be_less_than_min)

    def get_is_repeating(self):
        """
             Returns:
                boolean: whether the piecewise function repeats"""

        return self.is_repeating

    def set_is_repeating(self, is_repeating):
        """Sets the is_repeating attribute to 'is_repeating'

             Returns:
                PiecewiseFunction: 'self'"""

        self.is_repeating = is_repeating
        return self

    def get_piecewise_function_with_is_repeating(self, is_repeating):
        """
             Returns:
                PiecewiseFunction: a piecewise function with the is repeating attribute set to 'is_repeating' (does not modify the current piecewise function)"""

        return self.get_copy().set_is_repeating(is_repeating)

    def update_function_bounds_fully(self):
        """Updates the function bounds for operations like remove (has to check every function in the list)"""

        if len(self.functions) == 0:
            return

        self.functions = sorted(self.functions, key=lambda x: x.get_min_x_coordinate())
        self.min_x_coordinate = self.functions[0].get_min_x_coordinate()

        max_index = len(self.functions) - 1
        self.max_x_coordinate = self.functions[max_index].get_max_x_coordinate()

    def update_function_bounds_for_added_function(self, function):
        """Updates the function bounds when a function is added (do not have to check every function in list)"""

        self.min_x_coordinate = min(self.min_x_coordinate, function.get_min_x_coordinate())
        self.max_x_coordinate = max(self.max_x_coordinate, function.get_max_x_coordinate())

    def validate_function_bounds_do_not_overlap(self):
        """Raises a ValueError if the function bounds overlap (if there are overlapping bounds the piecewise function is invalidated)"""

        for i in range(len(self.functions)):
            for j in range(len(self.functions)):
                function1 = self.functions[i]
                function2 = self.functions[j]

                a, b = function1.get_bounds()
                c, d = function2.get_bounds()

                # If the function1's bounds fall within function2's bounds (case 1) or it crosses the bounds of
                # function2 (case 2) then this is no longer a valid piecewise function.
                is_invalid = a <= c <= b
                distance_between_c_and_a = a - c
                function1_bound_size = b - a
                is_invalid |= distance_between_c_and_a >= function1_bound_size

                if is_invalid:
                        raise ValueError("The bounds of each function within the piecewise function must not overlap")

    def clear_functions(self):
        """ Clears all functions from the piecewise function

            Returns:
                PiecewiseFunction: 'self'"""

        self.functions.clear()
        self.min_x_coordinate = 0
        self.max_x_coordinate = 0
        return self

    def get_piecewise_function_with_cleared_functions(self):
        """
             Returns a new PiecewiseFunction with cleared functions (does not modify the current piecewise function)

             Returns:
                PiecewiseFunction: new piecewise function with cleared functions"""

        return self.get_copy().clear_functions()

    def add_function(self, new_function):
        """ Adds a new function to the piecewise function

            Args:
                new_function (Function): function to be added

            Returns:
                PiecewiseFunction: 'self'"""

        self.functions.append(new_function)
        self.validate_function_bounds_do_not_overlap()
        self.update_function_bounds_fully()
        return self

    def get_piecewise_function_with_added_function(self, new_function):
        """
             Returns: a new PiecewiseFunction with the added function (does not modify the current piecewise function)
            
            Args:
                new_function (Function): function to be added
            
             Returns:
                PiecewiseFunction: new piecewise function with the added function"""

        return self.get_copy().add_function(new_function)

    def remove_function_at_index(self, index):
        """ Removes a function at the specified index from the piecewise function
            
            Args:
                index (int): index of the function to be removed
            
            Returns:
                PiecewiseFunction: 'self'"""

        if 0 <= index < len(self.functions):
            del self.functions[index]

        self.update_function_bounds_fully()
        return self

    def get_piecewise_function_with_function_removed_at_index(self, index):
        """
             Returns: a new PiecewiseFunction with a function removed at the specified index (does not modify the current piecewise function)
            Args:
                index (int): index of the function to be removed

             Returns:
               PiecewiseFunction: new piecewise function with the function removed at the specified index"""

        return self.get_copy().remove_function_at_index(index)

    def remove_function(self, function):
        """ Removes the specified function from the piecewise function

            Args:
                function (Function): function to be removed

            Returns:
                PiecewiseFunction: 'self'"""

        self.functions.remove(function)
        self.update_function_bounds_fully()
        return self

    def get_piecewise_function_with_function_removed(self, function):
        """
             Returns: a new PiecewiseFunction with the specified function removed (does not modify the current piecewise function)
            Args:
                function (Function): function to be removed

             Returns:
                PiecewiseFunction: new piecewise function with the specified function removed"""

        return self.get_copy().remove_function(function)

    def get_y_coordinate(self, x_coordinate):
        """
             Returns:
                float: the y coordinate associated with that x coordinate"""

        return self.get_function(x_coordinate).get_y_coordinate(x_coordinate)

    def get_function(self, x_coordinate):
        """
             Returns:
                BoundedFunction: the function that controls the piecewise function at the x coordinate"""

        if len(self.functions) == 0:
            raise ValueError("There must be a function in functions in order for the piecewise function to operate")

        if self.is_repeating:
            x_coordinate = modified_mod(x_coordinate, self.bounds_size())

        if not is_within_bounds(x_coordinate, self.min_x_coordinate, self.max_x_coordinate):
            if not self.x_coordinates_can_be_less_than_min:
                raise ValueError("The x coordinate must be greater")

            else:
                return self.get_before_piecewise_function().get_function(x_coordinate)

        for function in self.functions:
            if is_within_bounds(x_coordinate, *function.get_bounds()):
                return function

        raise ValueError("You should not get this value error! This is an implementation error in the code")



    def get_before_piecewise_function(self):
        """
             Returns:
                PiecewiseFunction: a piecewise function that 'comes before' the original"""

        before_piecewise_function = self.get_copy()
        new_x_start = self.min_x_coordinate - self.bounds_size()
        # The relative positions of functions stay the same, so I am just performing a 'domain shift'
        x_position_in_original_function = lambda x: self.get_x_relative_position(new_x_start, x) + self.min_x_coordinate
        before_piecewise_function.get_y_coordinate = lambda x: self.get_y_coordinate(x_position_in_original_function(x))

        return before_piecewise_function

    def get_x_relative_position(self, start, x_coordinate):
        """
             Returns:
                float: the distance x is from start (the relative position within the interval [start, end])"""

        return start - x_coordinate


    def get_min_x_coordinate(self):
        """
             Returns:
                float: the min x coordinate of the piecewise function (min x coordinate of min bounded function)"""

        return self.min_x_coordinate

    def get_max_x_coordinate(self):
        """
             Returns:
                float: the max x coordinate of the piecewise function (max x coordinate of max bounded function)"""

        return self.max_x_coordinate

    def get_bounds(self):
        """
             Returns:
                list[float]: {min_x_coordinate, max_x_coordinate}; the bounds of the peicewise function"""

        return [self.min_x_coordinate, self.max_x_coordinate]

    def bounds_size(self):
        """
             Returns:
                float: the size of the bounds (max - min)"""

        return self.max_x_coordinate - self.min_x_coordinate

    def get_indefinite_integral(self):
        """ Finds and returns the indefinite integral. Raises an AttributeError if any of the functions do not have the
            method: 'get_indefinite_integral'
     
            Returns:
                PiecewiseFunction: the indefinite integral of the polynomial"""

        new_functions = []
        for function in self.functions:
            new_functions.append(function.get_indefinite_integral())

        indefinite_integral = self.get_copy().get_piecewise_function_with_functions(new_functions)
        return indefinite_integral

    def evaluate_area(self, start, end):
        """
             Returns:
                float: the value gotten from using the bounds for the indefinite integral"""

        indefinite_integral = self.get_indefinite_integral()
        area = 0
        current_start = start

        for x in range(len(indefinite_integral.get_functions())):
            bounded_function = indefinite_integral.get_functions()[x]
            min_x, max_x = bounded_function.get_bounds()

            if is_within_bounds(current_start, min_x, max_x):
                end_x = min_value(max_x, end)
                new_area = bounded_function.get_y_coordinate(end_x) - bounded_function.get_y_coordinate(current_start)
                area += new_area
                current_start = end_x

            if current_start == end:
                break

        return area

    def get_derivative(self):
        """ Finds and returns the derivative. Raises an AttributeError if any of the functions do not have the
            method: 'get_derivative'
     
            Returns:
                PiecewiseFunction: the derivative of the polynomial"""

        new_functions = []
        for function in self.functions:
            new_functions.append(function.get_derivative())

        return self.get_piecewise_function_with_functions(new_functions)

    def evaluate_derivative_at_point(self, x_coordinate):
        """
             Returns:
                float: the value of the derivative evaluated at the 'x_coordinate'"""

        return self.get_derivative().get_y_coordinate(x_coordinate)

Ancestors

Class variables

var functions
var is_repeating
var max_x_coordinate
var min_x_coordinate
var x_coordinates_can_be_less_than_min

Methods

def add_function(self, new_function)

Adds a new function to the piecewise function

Args

new_function : Function
function to be added

Returns

PiecewiseFunction
'self'
Expand source code
def add_function(self, new_function):
    """ Adds a new function to the piecewise function

        Args:
            new_function (Function): function to be added

        Returns:
            PiecewiseFunction: 'self'"""

    self.functions.append(new_function)
    self.validate_function_bounds_do_not_overlap()
    self.update_function_bounds_fully()
    return self
def bounds_size(self)

Returns

float
the size of the bounds (max - min)
Expand source code
def bounds_size(self):
    """
         Returns:
            float: the size of the bounds (max - min)"""

    return self.max_x_coordinate - self.min_x_coordinate
def clear_functions(self)

Clears all functions from the piecewise function

Returns

PiecewiseFunction
'self'
Expand source code
def clear_functions(self):
    """ Clears all functions from the piecewise function

        Returns:
            PiecewiseFunction: 'self'"""

    self.functions.clear()
    self.min_x_coordinate = 0
    self.max_x_coordinate = 0
    return self
def evaluate_area(self, start, end)

Returns

float
the value gotten from using the bounds for the indefinite integral
Expand source code
def evaluate_area(self, start, end):
    """
         Returns:
            float: the value gotten from using the bounds for the indefinite integral"""

    indefinite_integral = self.get_indefinite_integral()
    area = 0
    current_start = start

    for x in range(len(indefinite_integral.get_functions())):
        bounded_function = indefinite_integral.get_functions()[x]
        min_x, max_x = bounded_function.get_bounds()

        if is_within_bounds(current_start, min_x, max_x):
            end_x = min_value(max_x, end)
            new_area = bounded_function.get_y_coordinate(end_x) - bounded_function.get_y_coordinate(current_start)
            area += new_area
            current_start = end_x

        if current_start == end:
            break

    return area
def evaluate_derivative_at_point(self, x_coordinate)

Returns

float
the value of the derivative evaluated at the 'x_coordinate'
Expand source code
def evaluate_derivative_at_point(self, x_coordinate):
    """
         Returns:
            float: the value of the derivative evaluated at the 'x_coordinate'"""

    return self.get_derivative().get_y_coordinate(x_coordinate)
def get_before_piecewise_function(self)

Returns

PiecewiseFunction
a piecewise function that 'comes before' the original
Expand source code
def get_before_piecewise_function(self):
    """
         Returns:
            PiecewiseFunction: a piecewise function that 'comes before' the original"""

    before_piecewise_function = self.get_copy()
    new_x_start = self.min_x_coordinate - self.bounds_size()
    # The relative positions of functions stay the same, so I am just performing a 'domain shift'
    x_position_in_original_function = lambda x: self.get_x_relative_position(new_x_start, x) + self.min_x_coordinate
    before_piecewise_function.get_y_coordinate = lambda x: self.get_y_coordinate(x_position_in_original_function(x))

    return before_piecewise_function
def get_bounded_function_with_x_coordinates_less_than_min(self, x_coordinates_can_be_less_than_min)

Returns

PiecewiseFunction
a piecewise function with the is repeating attribute set to 'x_coordinates_can_be_less_than_min' (does not modify the current piecewise function)
Expand source code
def get_bounded_function_with_x_coordinates_less_than_min(self, x_coordinates_can_be_less_than_min):
    """
         Returns:
            PiecewiseFunction: a piecewise function with the is repeating attribute set to 'x_coordinates_can_be_less_than_min' (does not modify the current piecewise function)"""

    return self.get_copy().set_x_coordinates_can_be_less_than_min(x_coordinates_can_be_less_than_min)
def get_bounds(self)

Returns

list[float]
{min_x_coordinate, max_x_coordinate}; the bounds of the peicewise function
Expand source code
def get_bounds(self):
    """
         Returns:
            list[float]: {min_x_coordinate, max_x_coordinate}; the bounds of the peicewise function"""

    return [self.min_x_coordinate, self.max_x_coordinate]
def get_copy(self)

Returns

PiecewiseFunction
a copy of the current piecewise_function
Expand source code
def get_copy(self):
    """
         Returns:
            PiecewiseFunction: a copy of the current piecewise_function"""

    # return deepcopy(self)
    new_functions = []
    copy = PiecewiseFunction(new_functions)
    for val in self.get_functions():
        new_functions.append(val)

    copy.set_is_repeating(self.is_repeating)
    copy.set_x_coordinates_can_be_less_than_min(self.x_coordinates_can_be_less_than_min)
    return copy
def get_derivative(self)

Finds and returns the derivative. Raises an AttributeError if any of the functions do not have the method: 'get_derivative'

Returns

PiecewiseFunction
the derivative of the polynomial
Expand source code
def get_derivative(self):
    """ Finds and returns the derivative. Raises an AttributeError if any of the functions do not have the
        method: 'get_derivative'
 
        Returns:
            PiecewiseFunction: the derivative of the polynomial"""

    new_functions = []
    for function in self.functions:
        new_functions.append(function.get_derivative())

    return self.get_piecewise_function_with_functions(new_functions)
def get_function(self, x_coordinate)

Returns

BoundedFunction
the function that controls the piecewise function at the x coordinate
Expand source code
def get_function(self, x_coordinate):
    """
         Returns:
            BoundedFunction: the function that controls the piecewise function at the x coordinate"""

    if len(self.functions) == 0:
        raise ValueError("There must be a function in functions in order for the piecewise function to operate")

    if self.is_repeating:
        x_coordinate = modified_mod(x_coordinate, self.bounds_size())

    if not is_within_bounds(x_coordinate, self.min_x_coordinate, self.max_x_coordinate):
        if not self.x_coordinates_can_be_less_than_min:
            raise ValueError("The x coordinate must be greater")

        else:
            return self.get_before_piecewise_function().get_function(x_coordinate)

    for function in self.functions:
        if is_within_bounds(x_coordinate, *function.get_bounds()):
            return function

    raise ValueError("You should not get this value error! This is an implementation error in the code")
def get_functions(self)

Returns

BoundedFunction
all the functions of the piecewise function
Expand source code
def get_functions(self):
    """
         Returns:
            BoundedFunction: all the functions of the piecewise function"""

    return self.functions
def get_indefinite_integral(self)

Finds and returns the indefinite integral. Raises an AttributeError if any of the functions do not have the method: 'get_indefinite_integral'

Returns

PiecewiseFunction
the indefinite integral of the polynomial
Expand source code
def get_indefinite_integral(self):
    """ Finds and returns the indefinite integral. Raises an AttributeError if any of the functions do not have the
        method: 'get_indefinite_integral'
 
        Returns:
            PiecewiseFunction: the indefinite integral of the polynomial"""

    new_functions = []
    for function in self.functions:
        new_functions.append(function.get_indefinite_integral())

    indefinite_integral = self.get_copy().get_piecewise_function_with_functions(new_functions)
    return indefinite_integral
def get_is_repeating(self)

Returns

boolean
whether the piecewise function repeats
Expand source code
def get_is_repeating(self):
    """
         Returns:
            boolean: whether the piecewise function repeats"""

    return self.is_repeating
def get_max_x_coordinate(self)

Returns

float
the max x coordinate of the piecewise function (max x coordinate of max bounded function)
Expand source code
def get_max_x_coordinate(self):
    """
         Returns:
            float: the max x coordinate of the piecewise function (max x coordinate of max bounded function)"""

    return self.max_x_coordinate
def get_min_x_coordinate(self)

Returns

float
the min x coordinate of the piecewise function (min x coordinate of min bounded function)
Expand source code
def get_min_x_coordinate(self):
    """
         Returns:
            float: the min x coordinate of the piecewise function (min x coordinate of min bounded function)"""

    return self.min_x_coordinate
def get_piecewise_function_with_added_function(self, new_function)

Returns: a new PiecewiseFunction with the added function (does not modify the current piecewise function)

Args

new_function : Function
function to be added

Returns: PiecewiseFunction: new piecewise function with the added function

Expand source code
def get_piecewise_function_with_added_function(self, new_function):
    """
         Returns: a new PiecewiseFunction with the added function (does not modify the current piecewise function)
        
        Args:
            new_function (Function): function to be added
        
         Returns:
            PiecewiseFunction: new piecewise function with the added function"""

    return self.get_copy().add_function(new_function)
def get_piecewise_function_with_cleared_functions(self)

Returns a new PiecewiseFunction with cleared functions (does not modify the current piecewise function)

Returns

PiecewiseFunction
new piecewise function with cleared functions
Expand source code
def get_piecewise_function_with_cleared_functions(self):
    """
         Returns a new PiecewiseFunction with cleared functions (does not modify the current piecewise function)

         Returns:
            PiecewiseFunction: new piecewise function with cleared functions"""

    return self.get_copy().clear_functions()
def get_piecewise_function_with_function_removed(self, function)

Returns: a new PiecewiseFunction with the specified function removed (does not modify the current piecewise function)

Args

function : Function
function to be removed

Returns: PiecewiseFunction: new piecewise function with the specified function removed

Expand source code
def get_piecewise_function_with_function_removed(self, function):
    """
         Returns: a new PiecewiseFunction with the specified function removed (does not modify the current piecewise function)
        Args:
            function (Function): function to be removed

         Returns:
            PiecewiseFunction: new piecewise function with the specified function removed"""

    return self.get_copy().remove_function(function)
def get_piecewise_function_with_function_removed_at_index(self, index)

Returns: a new PiecewiseFunction with a function removed at the specified index (does not modify the current piecewise function)

Args

index : int
index of the function to be removed

Returns: PiecewiseFunction: new piecewise function with the function removed at the specified index

Expand source code
def get_piecewise_function_with_function_removed_at_index(self, index):
    """
         Returns: a new PiecewiseFunction with a function removed at the specified index (does not modify the current piecewise function)
        Args:
            index (int): index of the function to be removed

         Returns:
           PiecewiseFunction: new piecewise function with the function removed at the specified index"""

    return self.get_copy().remove_function_at_index(index)
def get_piecewise_function_with_functions(self, functions)

Returns

PiecewiseFunction
a piecewise function with functions attribute being set to 'functions' (does not modify the current piecewise function)
Expand source code
def get_piecewise_function_with_functions(self, functions):
    """
         Returns:
            PiecewiseFunction: a piecewise function with functions attribute being set to 'functions' (does not modify the current piecewise function)"""

    return self.get_copy().set_functions(functions)
def get_piecewise_function_with_is_repeating(self, is_repeating)

Returns

PiecewiseFunction
a piecewise function with the is repeating attribute set to 'is_repeating' (does not modify the current piecewise function)
Expand source code
def get_piecewise_function_with_is_repeating(self, is_repeating):
    """
         Returns:
            PiecewiseFunction: a piecewise function with the is repeating attribute set to 'is_repeating' (does not modify the current piecewise function)"""

    return self.get_copy().set_is_repeating(is_repeating)
def get_x_coordinates_can_be_less_than_min(self)

Returns

bool
whether the x coordinates this function accepts can be less than the min x coordinate
Expand source code
def get_x_coordinates_can_be_less_than_min(self):
    """
         Returns:
            bool: whether the x coordinates this function accepts can be less than the min x coordinate"""

    return self.x_coordinates_can_be_less_than_min
def get_x_relative_position(self, start, x_coordinate)

Returns

float
the distance x is from start (the relative position within the interval [start, end])
Expand source code
def get_x_relative_position(self, start, x_coordinate):
    """
         Returns:
            float: the distance x is from start (the relative position within the interval [start, end])"""

    return start - x_coordinate
def remove_function(self, function)

Removes the specified function from the piecewise function

Args

function : Function
function to be removed

Returns

PiecewiseFunction
'self'
Expand source code
def remove_function(self, function):
    """ Removes the specified function from the piecewise function

        Args:
            function (Function): function to be removed

        Returns:
            PiecewiseFunction: 'self'"""

    self.functions.remove(function)
    self.update_function_bounds_fully()
    return self
def remove_function_at_index(self, index)

Removes a function at the specified index from the piecewise function

Args

index : int
index of the function to be removed

Returns

PiecewiseFunction
'self'
Expand source code
def remove_function_at_index(self, index):
    """ Removes a function at the specified index from the piecewise function
        
        Args:
            index (int): index of the function to be removed
        
        Returns:
            PiecewiseFunction: 'self'"""

    if 0 <= index < len(self.functions):
        del self.functions[index]

    self.update_function_bounds_fully()
    return self
def set_functions(self, functions)

Sets the functions of the piecewise function

Returns

PiecewiseFunction
'self'
Expand source code
def set_functions(self, functions):
    """Sets the functions of the piecewise function

         Returns:
            PiecewiseFunction: 'self'"""

    self.functions = functions
    self.update_function_bounds_fully()
    return self
def set_is_repeating(self, is_repeating)

Sets the is_repeating attribute to 'is_repeating'

Returns

PiecewiseFunction
'self'
Expand source code
def set_is_repeating(self, is_repeating):
    """Sets the is_repeating attribute to 'is_repeating'

         Returns:
            PiecewiseFunction: 'self'"""

    self.is_repeating = is_repeating
    return self
def set_x_coordinates_can_be_less_than_min(self, x_coordinates_can_be_less_than_min)

Sets whether the x coordinates this function accepts can be less than the min x coordinate

Returns

BoundedFunction
'self'
Expand source code
def set_x_coordinates_can_be_less_than_min(self, x_coordinates_can_be_less_than_min):
    """ Sets whether the x coordinates this function accepts can be less than the min x coordinate

         Returns:
            BoundedFunction: 'self'"""

    self.x_coordinates_can_be_less_than_min = x_coordinates_can_be_less_than_min
    return self
def update_function_bounds_for_added_function(self, function)

Updates the function bounds when a function is added (do not have to check every function in list)

Expand source code
def update_function_bounds_for_added_function(self, function):
    """Updates the function bounds when a function is added (do not have to check every function in list)"""

    self.min_x_coordinate = min(self.min_x_coordinate, function.get_min_x_coordinate())
    self.max_x_coordinate = max(self.max_x_coordinate, function.get_max_x_coordinate())
def update_function_bounds_fully(self)

Updates the function bounds for operations like remove (has to check every function in the list)

Expand source code
def update_function_bounds_fully(self):
    """Updates the function bounds for operations like remove (has to check every function in the list)"""

    if len(self.functions) == 0:
        return

    self.functions = sorted(self.functions, key=lambda x: x.get_min_x_coordinate())
    self.min_x_coordinate = self.functions[0].get_min_x_coordinate()

    max_index = len(self.functions) - 1
    self.max_x_coordinate = self.functions[max_index].get_max_x_coordinate()
def validate_function_bounds_do_not_overlap(self)

Raises a ValueError if the function bounds overlap (if there are overlapping bounds the piecewise function is invalidated)

Expand source code
def validate_function_bounds_do_not_overlap(self):
    """Raises a ValueError if the function bounds overlap (if there are overlapping bounds the piecewise function is invalidated)"""

    for i in range(len(self.functions)):
        for j in range(len(self.functions)):
            function1 = self.functions[i]
            function2 = self.functions[j]

            a, b = function1.get_bounds()
            c, d = function2.get_bounds()

            # If the function1's bounds fall within function2's bounds (case 1) or it crosses the bounds of
            # function2 (case 2) then this is no longer a valid piecewise function.
            is_invalid = a <= c <= b
            distance_between_c_and_a = a - c
            function1_bound_size = b - a
            is_invalid |= distance_between_c_and_a >= function1_bound_size

            if is_invalid:
                    raise ValueError("The bounds of each function within the piecewise function must not overlap")

Inherited members