Functions and Methods

function getBetter!(me::Person, args...)
    newArgs = []
    improvements = []
    for arg in args
        improve, arg = action(me, arg)
        push!(newArgs, arg)
        push!(improvements, improve)
    end
    me += improvements
    me.goal ? getBetter!(me, newArgs...) : return me, newArgs
end

Utility

No citizen has a right to be an amateur in the matter of physical training… what a disgrace it is for a man to grow old without ever seeing the beauty and strength of which his body is capable.

  • Socrates on strong men

There are various utility functions and methods that enable the programme to work, these can be treated as black boxes.

Creating a programme's schedule is done by pushing the exercise and progression to a vector, push! and insert! have been defined to let users do so.

Base.push!Function
push!(
    A::AbstractArray{T, 1} where {T},
    exercise::Exercise,
    progression::Progression,
    i::Integer = 1,
)

Calculates set weights using exercise.trainingMax and progression.setScheme, then unrolls the relevant data into a named tuple and pushes it to the end of vector A. See insert! which does the same but at a specified index of A.

source
Base.insert!Function
insert!(
    A::AbstractArray{T, 1} where {T},
    index::Integer,
    exercise::Exercise,
    progression::Progression,
    i::Integer = 1,
)

Calculates set weights using exercise.trainingMax and progression.setScheme, then unrolls the relevant data into a named tuple and pushes it to index index of vector A. See push! which does the same but in the last index of A.

source

Analysis

The shortest path between two truths in the real domain passes through the complex domain.

  • Jacques Hadamard on complex analysis being real analysis' daddy

One of the purposes of Lifting.jl is to provide an analytic approach to training as well as automatically and dynamically adjust weights based on performance.

The building blocks of these more complex functions are calcIntensity, calcRPE, calcReps. We also have a more primitive function intensityArb to calculate intensity that is used in various programmes I've found.

Lifting.calcIntensityMethod
calcIntensity(reps::Integer, rpe::Real)

This function calculates a set's intensity as a function of reps and RPE. It does a disconcertedly good job of reproducing RPE charts. It is defined as follows:

$z = \dfrac{1}{a + b (x + 10 - y) + (x - 1) \left(\dfrac{c}{x} + \dfrac{d}{y}\right)},$

where $z \equiv$ intensity, $x \equiv$ reps, $y \equiv$ RPE, $a = 0.995,~ b = 0.0333,~c = 0.0025,~d = 0.1$.

We cap rpe to 10 and intensity to 1.

source
Lifting.calcRPEMethod
calcRPE(reps::Integer, intensity::Real)

Solving calcIntensity for rpe yields the following function:

$x = \dfrac{\sqrt{\left(a y z - b y^2 z + 10 b y z + c y z - d z - y\right)^2 + 4 c y z (b y z + d z)} - a y z + b y^2 z - 10 b y z - c y z + d z + y}{2 z (b y + d)},$

where the variables are the same as calcIntensity.

We cap intensity to 1 and the rpe to 10.

source
Lifting.calcRepsMethod
calcReps(intensity::Real, rpe::Real)

Solving calcIntensity for reps yields the following function:

$y = \dfrac{\sqrt{\left(a x z + b x^2 z + 10 b x z + c x z - c z - x\right)^2 + 4 b x z \left(d x^2 z - d x z\right)} + a x z + b x^2 z + 10 b x z + c x z - c z - x}{2 b x z},$

where the variables are the same as calcIntensity.

We cap intensity to 1 and rpe to 10.

source
Lifting.intensityArbMethod
intensityArb(var::Integer)

Calculates intensity given an arbitrary variable. I've seen this used as a proxy for reps at a given RPE. I've seen var be anything between the number of reps to the number of reps + 2, 4, 6, 8 depending on a target rpe. This makes for a good rough guide. It is defined as

$z = \dfrac{1}{a + b x},$

where $x \equiv$ var and the constants are the same as calcIntensity.

Note

calcIntensity works over a much wider range of RPE and rep combinations.

source

We also need to calculate ratios and rep maxes if we want to update our programme dynamically so there are functions for that too. This is done with calcIntensityRatio, calcRPERatio, calcRepRatio, calcRepMax.

Lifting.calcIntensityRatioMethod
calcIntensityRatio(
    actualReps::Integer,
    actualRPE::Real,
    targetReps::Integer,
    targetRPE::Real,
)

Calculate the ratio between targetIntensity/actualIntensity.

All RPE values are capped to 10.

source
Lifting.calcRPERatioMethod
calcRPERatio(
    actualReps::Integer,
    actualIntensity::Real,
    targetReps::Integer,
    targetIntensity::Real,
)

Calculate the ratio between targetRPE/actualRPE.

All intensity values are capped to 1.

source
Lifting.calcRepRatioMethod
calcRepRatio(
    actualIntensity::Real,
    actualRPE::Real,
    targetIntensity::Real,
    targetRPE::Real,
)

Calculate the ratio between targetReps/actualReps.

All intensity values are capped to 1 and all rpe values to 10.

source
Lifting.calcRepMaxMethod
calcRepMax(
    weight::Real,
    actualReps::Integer,
    actualRPE::Real,
    targetReps::Integer,
    targetRPE::Real,
)

Calculates the rep weight for a target number of reps, targetReps, at a target rpe, targetRPE, given an actual number of reps, actualReps, and an actual rpe, actualRPE and weight. It's just the weight multiplied by the intensity ratio.

source

The last purely mathematical function is calcWeights.

Lifting.calcWeightsMethod
calcWeights(exercise::Exercise, setScheme::SetScheme)

This function calculates and updates the weights for each set according to the training max specified in exercise.trainingMax and the intensities of the sets in setScheme.

source

In order to calculate and/or adjust training maxes as well as set the next cycle's weights according to a programme's goals we have makeDays, calcWeights, adjustMaxes!, adjustMaxes, updateMaxes! and updateMaxes. For calculating training maxes from logs we have calcTrainingMaxLogs.

Lifting.makeDaysMethod
makeDays()

Generic function that can be explicitly typed by the user to create their programme's daily schedule. Typed makeDays functions are used by updateMaxes! to update the training days with the new training maxes calculated by adjustMaxes!. See the example in Programme to see how to define typed makeDays.

Warning

makeDays must be explicitly imported either with import Lifting: makeDays or Lifting.makeDays for it to be automatically used in updateMaxes!.

source
Lifting.adjustMaxes!Method
adjustMaxes!(
    name::AbstractString,
    dict::Dict{Any, Any},
    actualReps::Integer;
    weight = missing,
)

Adjusts a programme's training maxes using what is expected by the programme and the actual reps, actualReps, performed at the programme's highest intensity for the exercise contained in dict[name]. However, if weight is provided, updateMaxes! will use that to calculate the new training max instead of whatever the programme prescribes.

Note

Adjustments made to training max are calculated based on what the programme expects vs actual performance. So if you spectacularly fail a set, the adjustment down will be relatively aggressive. Conversely if you absolutely smash it, the adjustment up will be relatively aggressive. Downward adjustments are more aggressive than upward ones.

source
Lifting.adjustMaxesMethod
adjustMaxes(
    name::AbstractString,
    dict::Dict{Any, Any},
    actualReps::Integer;
    weight = missing,
)

Does the same as adjustMaxes! but without updating the programme's training maxes. It returns a tuple with the new training max and the would-be change to the programme's training max, (trainingMax, change)`.

source
Lifting.updateMaxes!Method
updateMaxes!(prog::Programme, names, reps; idx = missing)

names are the keys of the exercises you want to update, reps contains the reps performed at the corresponding exercise's maximum intensity set of the cycle, idx is optional in case each entry of reps is a vector and you would like to specifically use an index instead of the last entry.

Updates the programme's training maxes and adjusts the set weights for the next training cycle. It uses adjustMaxes to update training maxes and makeDays to calculate new set weights according to what is expected by the programme vs actual performance. All this is done on a per exercise basis.

See updateMaxes for a non-mutating version of this function.

source
Lifting.updateMaxesMethod
updateMaxes(prog::Programme, names, reps; idx = missing)

The arguments are the same as updateMaxes!.

Calculates the would-be new training maxes and changes to the old training maxes for the next cycle according to what is expected by the programme vs actual performance but does not update the programme in any way. Returns a tuple (trainingMaxes, change) where each entry in the tuple is an array whose entries correspond 1 to 1 to the exercises in names. The new value for trainingMax is not necessarily going to equal to the old value of trainingMax + change, because change is calculated based on how far off the new value for trainingMax is from the old value of trainingMax, and the result is rounded according to the exercise's roundBase and roundMode.

This is essentially calls adjustMaxes for all the arguments in names. In order to see what a programme's training days would look like under these new training maxes, the easiest thing to do is to create a deepcopy() of the programme and run updateMaxes! on it.

source
Lifting.calcTrainingMaxLogsMethod
calcTrainingMaxLogs(prog::Programme, names, reps, weight)

This function does something similar to updateMaxes but for the whole history of entries instead of a single point in time. This is useful for analysing progress.

source