[OCaml] High Intensity Training Online
1
(** Interprets recorded training against Heavy Duty rules. *)
2
3
type assessment =
4
| Progressing
5
| Stalled
6
| Decompensating
7
(** [Stalled] is a halt: progress has stopped but strength holds.
8
[Decompensating] is worse: the trainee loses strength (HD1, "The
9
Economics of Growth and Recovery": "before decompensating, i.e., lose
10
strength and mass"). HD1 names both and applies the same corrective.
11
*)
12
13
type error = Insufficient_data
14
15
val pp_assessment : Format.formatter -> assessment -> unit
16
val pp_error : Format.formatter -> error -> unit
17
18
val stall_window : Recovery.duration
19
(** 14 days. *)
20
21
val assess : Evidence.Observation.t list -> (assessment, error) result
22
(** [Error Insufficient_data] when the record cannot yet support a judgment: too
23
few observations, or a record that never advanced but is younger than the
24
stall window. This is an ordinary state of a young record, not a fault. *)
25
26
type remedy =
27
| Lay_off_then_reduce of {
28
lay_off : Recovery.duration;
29
drop_stimuli_per_workout : int;
30
extra_rest : Recovery.duration;
31
}
32
33
val remedy : assessment -> remedy option
34
(** [Some] for [Stalled] and [Decompensating]. HD1 applies one corrective to a
35
halt and to decompensation alike ("when progress comes to a halt or you
36
start decompensating ... you should decrease them"). The corrective never
37
adds work. *)
38
39
val pp_remedy : Format.formatter -> remedy -> unit
40
41
val load_increase_trigger : int
42
(** 12 reps, regardless of the prescribed range. *)
43
44
val load_increase : current:float -> float * float
45
(** 10-20% increase window. *)
46
47
type load_verdict = Hold | Increase of float * float | Too_heavy
48
49
val judge_load :
50
rep_range:Prescription.Rep_range.t ->
51
Evidence.Stimulus.Effort.t ->
52
load_verdict
53
(** Only the range floor matters: below it is [Too_heavy]. At twelve reps the
54
verdict is [Increase]. *)
55
56
val pp_load_verdict : Format.formatter -> load_verdict -> unit
57
58
type workout_comparison = {
59
exercise : Exercise.t;
60
previous : Evidence.Stimulus.Effort.t;
61
current : Evidence.Stimulus.Effort.t;
62
}
63
(** One exercise in a workout with a most-recent earlier observation. The
64
baseline is strictly before the workout started, so correcting a saved
65
workout never compares an exercise against itself. *)
66
67
val workout_comparisons :
68
Evidence.Log.t -> Evidence.Workout.t -> workout_comparison list
69
(** Distinct exercises with a prior baseline, in workout performance order. *)
70
71
val workout_changes :
72
Evidence.Log.t -> Evidence.Workout.t -> workout_comparison list
73
(** The comparisons that show progressive overload: more load, or equal load and
74
more reps. One extra rep counts. *)
75
76
(** Counts recorded workouts that show each overtraining risk. *)
77
type diagnostic =
78
| Excess_volume of int
79
| Extensions_on_every_stimulus of int
80
| Trained_under_recovered of int
81
82
val diagnose : Evidence.Log.t -> diagnostic list
83
val pp_diagnostic : Format.formatter -> diagnostic -> unit
84
85
val workout_progress : Evidence.Log.t -> Evidence.Workout.t -> int
86
(** How many distinct exercises in the workout beat their most recent earlier
87
observation in the log. Progress is more reps or load. One extra rep counts.
88
An exercise with no earlier observation does not count. The baseline is the
89
latest observation strictly before the workout started, so correcting a
90
saved workout never compares an exercise against itself. *)
91
92
val previous_observation :
93
Evidence.Observation.t list ->
94
Evidence.Observation.t ->
95
Evidence.Observation.t option
96
(** The most recent observation of the target's exercise strictly before the
97
target was performed, from the given series. This applies the baseline rule
98
of {!workout_comparisons} over a bare observation list. A caller can then
99
compare imported evidence against the observations before it. *)
100