""" * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions. * Copyright (C) 2021-2024 Ad5001 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . """ from math import log10, floor from typing import Self from .assertion import Assertion from .base import AssertionInterface from .utils import repr_ class NumberComparisonAssertionInterface(AssertionInterface): def __init__(self, value, parent: AssertionInterface = None): super().__init__(value, parent) self._compare_stack = [] def _generate_compare_to(self) -> int: """ The number generated by the comparison stack. E.g. can parse one.hundred.million.and.thirty.three.thousand.and.twelve.hundred.and.seven as ['one', 'hundred', 'million', 'thirty', 'three', 'thousand', 'twelve', 'hundred', 'seven'] which results 100,034,207 """ minus = len(self._compare_stack) > 0 and self._compare_stack[0] == -1 if len(self._compare_stack) < (2 if minus else 1): raise RuntimeError("No number to compare the value to provided.") if minus: self._compare_stack.pop(0) # Compute the number add_stack = [self._compare_stack.pop(0)] for element in self._compare_stack: last_power = floor(log10(abs(add_stack[-1]))) current_power = floor(log10(abs(element))) if last_power < current_power: # E.g. one hundred add_stack[-1] *= element elif last_power == 1 and current_power == 0: # E.g thirty four add_stack[-1] += element elif last_power > current_power: # E.g a hundred and five add_stack.append(element) else: raise RuntimeError(f"Cannot chain two numbers with the same power ({add_stack[-1]} => {element}.") total = sum(add_stack) return -total if minus else total def _compare(self) -> Assertion: raise RuntimeError(f"No comparison method defined in {type(self).__name__}.") def __bool__(self) -> bool: return bool(self._compare()) def __call__(self, compare_to: int) -> Self: if type(compare_to) not in (float, int): raise RuntimeError(f"Cannot compare number ({self._value}) to non number ({repr_(compare_to)}).") self._compare_stack.append(compare_to) return self """ Chain self properties """ @property def and_(self) -> Self: return self @property def AND(self) -> Self: return self """ Number shorthands """ @property def once(self) -> Self: return self(1) @property def twice(self) -> Self: return self(2) @property def thrice(self) -> Self: return self(3) @property def minus(self) -> Self: return self(-1) @property def zero(self) -> Self: return self(0) @property def one(self) -> Self: return self(1) @property def two(self) -> Self: return self(2) @property def three(self) -> Self: return self(3) @property def four(self) -> Self: return self(4) @property def five(self) -> Self: return self(5) @property def six(self) -> Self: return self(6) @property def seven(self) -> Self: return self(7) @property def eight(self) -> Self: return self(8) @property def nine(self) -> Self: return self(9) @property def ten(self) -> Self: return self(10) @property def eleven(self) -> Self: return self(11) @property def twelve(self) -> Self: return self(12) @property def thirteen(self) -> Self: return self(13) @property def fourteen(self) -> Self: return self(14) @property def fifteen(self) -> Self: return self(15) @property def sixteen(self) -> Self: return self(16) @property def seventeen(self) -> Self: return self(17) @property def eighteen(self) -> Self: return self(18) @property def nineteen(self) -> Self: return self(19) @property def twenty(self) -> Self: return self(20) @property def thirty(self) -> Self: return self(30) @property def forty(self) -> Self: return self(40) @property def fifty(self) -> Self: return self(50) @property def sixty(self) -> Self: return self(60) @property def seventy(self) -> Self: return self(70) @property def eighty(self) -> Self: return self(80) @property def ninety(self) -> Self: return self(90) @property def hundred(self) -> Self: return self(100) @property def thousand(self) -> Self: return self(1_000) @property def million(self) -> Self: return self(1_000_000) @property def billion(self) -> Self: return self(1_000_000_000) class LessThanComparisonInterface(NumberComparisonAssertionInterface): def _compare(self) -> Assertion: compare = self._generate_compare_to() return Assertion( self._value < compare, f"The value ({repr_(self._value)}) is not less than to {repr_(compare)}.", self._not ) class MoreThanComparisonInterface(NumberComparisonAssertionInterface): def _compare(self) -> Assertion: compare = self._generate_compare_to() return Assertion( self._value > compare, f"The value ({repr_(self._value)}) is not more than to {repr_(compare)}.", self._not ) class AtLeastComparisonInterface(NumberComparisonAssertionInterface): def _compare(self) -> Assertion: compare = self._generate_compare_to() return Assertion( self._value >= compare, f"The value ({repr_(self._value)}) is not at least to {repr_(compare)}.", self._not ) class AtMostComparisonInterface(NumberComparisonAssertionInterface): def _compare(self) -> Assertion: compare = self._generate_compare_to() return Assertion( self._value <= compare, f"The value ({repr_(self._value)}) is not at least to {repr_(compare)}.", self._not ) class EqualComparisonInterface(NumberComparisonAssertionInterface): def _compare(self) -> Assertion: compare = self._generate_compare_to() return Assertion( self._value == compare, f"The value ({repr_(self._value)}) is not equal to {repr_(compare)}.", self._not ) @property def to(self) -> Self: return self class NumberInterface(AssertionInterface): def __call__(self, value): return EqualComparisonInterface(self._value, self)(value) @property def equals(self) -> EqualComparisonInterface: return EqualComparisonInterface(self._value, self) @property def equal(self) -> EqualComparisonInterface: return EqualComparisonInterface(self._value, self) @property def exactly(self) -> EqualComparisonInterface: return EqualComparisonInterface(self._value, self) @property def of(self) -> EqualComparisonInterface: return EqualComparisonInterface(self._value, self) @property def less_than(self) -> LessThanComparisonInterface: return LessThanComparisonInterface(self._value, self) @property def more_than(self) -> MoreThanComparisonInterface: return MoreThanComparisonInterface(self._value, self) @property def at_least(self) -> AtLeastComparisonInterface: return AtLeastComparisonInterface(self._value, self) @property def at_most(self) -> AtMostComparisonInterface: return AtMostComparisonInterface(self._value, self)