Source code for src.one_rep_max_calc

"""
Definition of popular 1-repetition-maximum formulas.
"""

from loguru import logger  # type: ignore
import numpy as np  # type: ignore
import pandas as pd  # type: ignore
from src.one_rep_max import (  # type: ignore
    OneRepMaxStrategy,
    EpleyStrategy,
    BrzyckiStrategy
    )


[docs] class OneRepMaxCalculator: def __init__(self, strategy): self.strategy = strategy
[docs] def calculate(self, weight, reps): weight, reps = self.validate_inputs(weight, reps) return self.strategy.estimate(weight, reps)
[docs] @staticmethod def validate_inputs(weight, reps): weight_is_vectorized = isinstance(weight, (pd.Series, np.ndarray)) reps_is_vectorized = isinstance(reps, (pd.Series, np.ndarray)) if weight_is_vectorized and reps_is_vectorized and weight.shape != reps.shape: raise ValueError("Weight and reps must have the same shape when vectorized.") if isinstance(reps, (int, float)) and reps <= 0: raise ValueError("Reps must be positive.") if isinstance(reps, (np.ndarray, pd.Series)) and (reps <= 0).any(): raise ValueError("All reps values must be positive.") return weight, reps
[docs] class EpleyInvertedStrategy(OneRepMaxStrategy):
[docs] def estimate(self, one_rm, reps, progression): return np.log10(progression) * one_rm / (1 + reps / 30)
[docs] class BrzyckiInvertedStrategy(OneRepMaxStrategy):
[docs] def estimate(self, one_rm, reps, progression): return np.log10(progression) * one_rm * (37 - reps) / 36
[docs] class InvertedCalculator: def __init__(self, strategy): self.strategy = strategy
[docs] def calculate(self, one_rm, reps, progression): one_rm, reps, progression = self.validate_inputs( one_rm, reps, progression ) return self.strategy.estimate(one_rm, reps, progression)
[docs] @staticmethod def validate_inputs(one_rm, reps, progression): """Ensure that inputs are either scalars or Pandas Series.""" if isinstance(one_rm, (pd.Series, np.ndarray)) and isinstance(reps, (pd.Series, np.ndarray)): if one_rm.shape != reps.shape: raise ValueError("One RM and reps must have the same shape when using vectors.") elif isinstance(one_rm, (int, float)) and isinstance(reps, (int, float)): pass # Single values are acceptable else: raise TypeError( "Invalid input types." " Expected both one_rm and reps to be either scalars or pandas Series." ) if not isinstance(progression, (pd.Series, np.ndarray)): progression = np.array(progression) # Convert scalar to array for consistent operations return one_rm, reps, progression
[docs] def main() -> None: # Example usage epley_calculator = OneRepMaxCalculator(EpleyStrategy()) brzycki_calculator = OneRepMaxCalculator(BrzyckiStrategy()) epley_results = epley_calculator.calculate(100, 10) brzycki_results = brzycki_calculator.calculate(100, 10) logger.debug(f"{epley_results = }, {brzycki_results = }")
if __name__ == "__main__": main()