<commit_before>from fractions import Fraction
from decimal import Decimal

__author__ = 'satbek'

# allows support for up to len(GREEK_LETTERS) variables (currently 15)
GREEK_LETTERS = 'αβγδεηθλπρστμφω'


class Angle:
    """
    Defines a geometric angle in terms of a list of Fractions.

    NOTES:
    _coefficients contains n elements, where 0 <= n <= len(GREEK_LETTERS) + 1.

    Below are different cases for n. When {{1}}:
    1. n == 0, the angle is unknown.
    2. n == 1, the angle is constant.
       _coefficients = [90] --> 90 degrees
       _coefficients = [-30] --> -30 degrees
    3. n == 2, the angle has one variable (first letter of GREEK_LETTERS) and a constant term.
       _coefficients = [1, 45] --> α + 45
       _coefficients = [-1, -30] --> -α - 30
       _coefficients = [-1, 0] --> -α
    4. n == 3, the angle has two variables (first two letters of GREEK_LETTERS) and a constant term.
       _coefficients = [1, 1, 30] --> α + β + 30
       _coefficients = [0, -1, 30] --> -β + 30
       _coefficients = [-1, -1, 120] --> -α - β + 120
       _coefficients = [1, 1, 0] --> α + β
    ... and so on.

    The angle can be in either of two states: known or unknown.
    If len(_coefficients) == 0, then the angle is said to be unknown.
    Otherwise, the angle is said to be known.

    USAGE:
    a = Angle([])
    a.is_known() # False
    print(a) # x

    b = Angle([Fraction(1,2), Fraction(90)])
    print(b) # 1/2α + 90

    c = Angle([1.5, 2, -45]) # int and float values are implicitly converted to Fraction
    print(c) # 3/2α + 2β - 45

    d = Angle([Fraction(1,2), 40.5]) # Fraction, int, float values can be mixed
    print(d) # 1/2α + 81/2


    {{1}} To explain more easily, I used integers as coefficients. However, keep in mind that _coefficients
    contains ONLY objects of built-in Fraction class.
    """

    def __init__(self, coefficients):
        """
        PRE1: len(coefficients) <= 16
        PRE2: isinstance(coef, (Fraction, int, float)) is True for every coef in self._coefficients
        """

        # (Converted): non-Fraction coefficients[i] is implicitly converted to Fraction
        # for all i, such that 0 <= i < len(coefficients)
        for i in range(len(coefficients)):
            coef = coefficients[i]
            if isinstance(coef, (int, float)):
                coefficients[i] = Fraction(Decimal(str(coef)))

        # (Complement): i = len(coefficients)
        self._coefficients = coefficients

    def __add__(self, an_angle):
        """
        Intent: Implementation of "+" arithmetic operation.
                This method is invoked when there is something to be added to self.

        Usage:
        Angle + Angle
        Angle + int
        Angle + float

        PRE1: self.is_known()
        PRE2: is_instance(an_angle, (Angle, int, float))
        PRE3: EITHER !is_instance(an_angle, Angle) OR
              an_angle.is_known() AND self.get_dimension() = an_angle.get_dimension()
        """

        # (Converted): temp_angle is an Angle instance, where
        # temp_angle = an_angle AND
        # temp_angle.get_dimension() = self.get_dimension() AND
        # temp_angle.get_coefficients()[i] is Fraction instance for all i, such that
        # 0 <= i < temp_angle.get_dimension()
        if isinstance(an_angle, (int, float)):
            temp = [Fraction(0)] * (self.get_dimension() - 1) + [Fraction(Decimal(str(an_angle)))]
            temp_angle = Angle(temp)

        # (Added): self + an_angle is returned
            return self + temp_angle
        return Angle(list(map(sum, zip(self._coefficients, an_angle.get_coefficients()))))

    def __radd__(self, an_angle):
        """
        Intent: Implementation of "+" arithmetic operation.
                This method is invoked when self is to be added to something.

        Usage:
        int + Angle
        float + Angle
        """

        # delegated to self.__add__
        return self + an_angle

    def __sub__(self, an_angle):
        """
        Intent: Implementation of "-" arithmetic operation.
                This method is invoked when there is something to be subtracted from self.

        Usage:
        Angle - Angle
        Angle - int
        Angle - float

        PRE1: self.is_known()
        PRE2: is_instance(an_angle, (Angle, int, float))
        PRE3: EITHER !is_instance(an_angle, Angle) OR
              an_angle.is_known() AND self.get_dimension() = an_angle.get_dimension()
        """

        # (Converted and Negated): negated_angle is an Angle instance, where
        # negated_angle = -an_angle AND
        # negated_angle.get_dimension() = self.get_dimension() AND
        # negated_angle.get_coefficients()[i] is Fraction instance for all i, such that
        # 0 <= i < temp_angle.get_dimension()
        negated_coefs = None
        if isinstance(an_angle, (int, float)):
            negated_coefs = [Fraction(0)] * (len(self._coefficients) - 1) + [Fraction(Decimal(str(-an_angle)))]
        elif isinstance(an_angle, Angle):
            negated_coefs = list(map(lambda x: -x, an_angle.get_coefficients()))
        negated_angle = Angle(negated_coefs)

        # (Subtracted): self - an_angle is returned
        return self + negated_angle

    def __rsub__(self, an_angle):
        """
        Intent: Implementation of "-" arithmetic operation.
                This method is invoked when self is to be subtracted from something.

        Usage:
        int - Angle
        float - Angle
        """

        # an_angle - self = negated_self + an_angle
        negated_self = Angle(list(map(lambda x: -x, self._coefficients)))

        # delegated to self.__add__
        return negated_self + an_angle

    def __truediv__(self, a_number):
        """
        Intent: Implementation of "/" arithmetic operation.
                This method is invoked when self is to be divided by a real number.

        Usage:
        Angle / int
        Angle / float

        PRE1: self.is_known()
        PRE2: is_instance(a_number, (int, float))
        """

        # (Divided): self / a_number is returned
        result_coefficients = list(map(lambda x: x / Fraction(Decimal(str(a_number))), self._coefficients))
        return Angle(result_coefficients)

    def __mul__(self, other):
        """
        Implements binary arithmetic operation '*'.
        Angle * int
        Angle * float

        PRE1: self is known
        PRE1: other is an instance of int|float
        """

        # PRE1
        if not self.is_known():
            raise Exception('Self is unknown.')

        # PRE2
        if not isinstance(other, (int, float)):
            raise Exception('Wrong type provided.')

        results_coefficients = list(map(lambda x: x * Fraction(Decimal(str(other))), self._coefficients))
        return Angle(results_coefficients)

    def __rmul__(self, other):
        """
        Implements binary arithmetic operation '*'.<commit_msg>refactored __add__ after professor"s notes<commit_after>from fractions import Fraction
from decimal import Decimal

__author__ = 'satbek'

# allows support for up to len(GREEK_LETTERS) variables (currently 15)
GREEK_LETTERS = 'αβγδεηθλπρστμφω'


class Angle:
    """
    Defines a geometric angle in terms of a list of Fractions.

    NOTES:
    _coefficients contains n elements, where 0 <= n <= len(GREEK_LETTERS) + 1.

    Below are different cases for n. When {{1}}:
    1. n == 0, the angle is unknown.
    2. n == 1, the angle is constant.
       _coefficients = [90] --> 90 degrees
       _coefficients = [-30] --> -30 degrees
    3. n == 2, the angle has one variable (first letter of GREEK_LETTERS) and a constant term.
       _coefficients = [1, 45] --> α + 45
       _coefficients = [-1, -30] --> -α - 30
       _coefficients = [-1, 0] --> -α
    4. n == 3, the angle has two variables (first two letters of GREEK_LETTERS) and a constant term.
       _coefficients = [1, 1, 30] --> α + β + 30
       _coefficients = [0, -1, 30] --> -β + 30
       _coefficients = [-1, -1, 120] --> -α - β + 120
       _coefficients = [1, 1, 0] --> α + β
    ... and so on.

    The angle can be in either of two states: known or unknown.
    If len(_coefficients) == 0, then the angle is said to be unknown.
    Otherwise, the angle is said to be known.

    USAGE:
    a = Angle([])
    a.is_known() # False
    print(a) # x

    b = Angle([Fraction(1,2), Fraction(90)])
    print(b) # 1/2α + 90

    c = Angle([1.5, 2, -45]) # int and float values are implicitly converted to Fraction
    print(c) # 3/2α + 2β - 45

    d = Angle([Fraction(1,2), 40.5]) # Fraction, int, float values can be mixed
    print(d) # 1/2α + 81/2


    {{1}} To explain more easily, I used integers as coefficients. However, keep in mind that _coefficients
    contains ONLY objects of built-in Fraction class.
    """

    def __init__(self, coefficients):
        """
        PRE1: len(coefficients) <= 16
        PRE2: isinstance(coef, (Fraction, int, float)) is True for every coef in self._coefficients
        """

        # (Converted): non-Fraction coefficients[i] is implicitly converted to Fraction
        # for all i, such that 0 <= i < len(coefficients)
        for i in range(len(coefficients)):
            coef = coefficients[i]
            if isinstance(coef, (int, float)):
                coefficients[i] = Fraction(Decimal(str(coef)))

        # (Complement): i = len(coefficients)
        self._coefficients = coefficients

    def __add__(self, an_angle):
        """
        Intent: Implementation of "+" arithmetic operation.
                This method is invoked when there is something to be added to self.

        Usage:
        Angle + Angle
        Angle + int
        Angle + float

        PRE1: self.is_known()
        PRE2: is_instance(an_angle, (Angle, int, float))
        PRE3: EITHER !is_instance(an_angle, Angle) OR
              an_angle.is_known() AND self.get_dimension() = an_angle.get_dimension()
        """

        # (Converted): an_angle is an Angle instance, where
        # an_angle.get_dimension() = self.get_dimension() AND
        # an_angle.get_coefficients()[i] is Fraction instance for all i,
        # such that 0 <= i < an_angle.get_dimension()
        if isinstance(an_angle, (int, float)):
            temp = [Fraction(0)] * (self.get_dimension() - 1) + [Fraction(Decimal(str(an_angle)))]
            an_angle = Angle(temp)

        # (Added): self + an_angle is returned
            return self + an_angle
        return Angle(list(map(sum, zip(self._coefficients, an_angle.get_coefficients()))))

    def __radd__(self, an_angle):
        """
        Intent: Implementation of "+" arithmetic operation.
                This method is invoked when self is to be added to something.

        Usage:
        int + Angle
        float + Angle
        """

        # delegated to self.__add__
        return self + an_angle

    def __sub__(self, an_angle):
        """
        Intent: Implementation of "-" arithmetic operation.
                This method is invoked when there is something to be subtracted from self.

        Usage:
        Angle - Angle
        Angle - int
        Angle - float

        PRE1: self.is_known()
        PRE2: is_instance(an_angle, (Angle, int, float))
        PRE3: EITHER !is_instance(an_angle, Angle) OR
              an_angle.is_known() AND self.get_dimension() = an_angle.get_dimension()
        """

        # (Converted and Negated): negated_angle is an Angle instance, where
        # negated_angle = -an_angle AND
        # negated_angle.get_dimension() = self.get_dimension() AND
        # negated_angle.get_coefficients()[i] is Fraction instance for all i, such that
        # 0 <= i < temp_angle.get_dimension()
        negated_coefs = None
        if isinstance(an_angle, (int, float)):
            negated_coefs = [Fraction(0)] * (len(self._coefficients) - 1) + [Fraction(Decimal(str(-an_angle)))]
        elif isinstance(an_angle, Angle):
            negated_coefs = list(map(lambda x: -x, an_angle.get_coefficients()))
        negated_angle = Angle(negated_coefs)

        # (Subtracted): self - an_angle is returned
        return self + negated_angle

    def __rsub__(self, an_angle):
        """
        Intent: Implementation of "-" arithmetic operation.
                This method is invoked when self is to be subtracted from something.

        Usage:
        int - Angle
        float - Angle
        """

        # an_angle - self = negated_self + an_angle
        negated_self = Angle(list(map(lambda x: -x, self._coefficients)))

        # delegated to self.__add__
        return negated_self + an_angle

    def __truediv__(self, a_number):
        """
        Intent: Implementation of "/" arithmetic operation.
                This method is invoked when self is to be divided by a real number.

        Usage:
        Angle / int
        Angle / float

        PRE1: self.is_known()
        PRE2: is_instance(a_number, (int, float))
        """

        # (Divided): self / a_number is returned
        result_coefficients = list(map(lambda x: x / Fraction(Decimal(str(a_number))), self._coefficients))
        return Angle(result_coefficients)

    def __mul__(self, other):
        """
        !!!
        Implements binary arithmetic operation '*'.
        Angle * int
        Angle * float

        PRE1: self is known
        PRE1: other is an instance of int|float
        """

        # PRE1
        if not self.is_known():
            raise Exception('Self is unknown.')

        # PRE2
        if not isinstance(other, (int, float)):
            raise Exception('Wrong type provided.')

        results_coefficients = list(map(lambda x: x * Fraction(Decimal(str(other))), self._coefficients))
        return Angle(results_coefficients)

    def __rmul__(self, other):
        """
        Implements binary arithmetic operation '*'.
{'fraction_non_alphanumeric': 0.10729459206452077, 'fraction_numerical': 0.015698134946352704, 'mean_word_length': 2.223021582733813, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '713825', 'n_tokens_mistral': 4530, 'n_tokens_neox': 4076, 'n_words': 1325}