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!
— Functionpush!(
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.
Base.insert!
— Functioninsert!(
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.
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.calcIntensity
— MethodcalcIntensity(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.
Lifting.calcRPE
— MethodcalcRPE(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.
Lifting.calcReps
— MethodcalcReps(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.
Lifting.intensityArb
— MethodintensityArb(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
.
calcIntensity
works over a much wider range of RPE and rep combinations.
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.calcIntensityRatio
— MethodcalcIntensityRatio(
actualReps::Integer,
actualRPE::Real,
targetReps::Integer,
targetRPE::Real,
)
Calculate the ratio between targetIntensity/actualIntensity
.
All RPE values are capped to 10.
Lifting.calcRPERatio
— MethodcalcRPERatio(
actualReps::Integer,
actualIntensity::Real,
targetReps::Integer,
targetIntensity::Real,
)
Calculate the ratio between targetRPE/actualRPE
.
All intensity values are capped to 1.
Lifting.calcRepRatio
— MethodcalcRepRatio(
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.
Lifting.calcRepMax
— MethodcalcRepMax(
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.
The last purely mathematical function is calcWeights
.
Lifting.calcWeights
— MethodcalcWeights(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
.
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.makeDays
— MethodmakeDays()
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
.
makeDays
must be explicitly imported either with import Lifting: makeDays
or Lifting.makeDays
for it to be automatically used in updateMaxes!
.
Lifting.adjustMaxes!
— MethodadjustMaxes!(
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.
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.
Lifting.adjustMaxes
— MethodadjustMaxes(
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)
`.
Lifting.updateMaxes!
— MethodupdateMaxes!(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.
Lifting.updateMaxes
— MethodupdateMaxes(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.
Lifting.calcTrainingMaxLogs
— MethodcalcTrainingMaxLogs(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.