Skip to content

Commit 8115f5e

Browse files
committed
Start redesign
but forgot to pull, so interms commit to merge real quick.
1 parent e6b4b99 commit 8115f5e

7 files changed

Lines changed: 162 additions & 55 deletions

File tree

docs/make.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ makedocs(;
4444
"Home" => "index.md",
4545
"Interface" => "interface.md",
4646
"Stopping criteria" => "stopping_criterion.md",
47+
"Notation" => "notation.md",
4748
"References" => "references.md",
4849
],
4950
plugins = [bib, links],

docs/src/interface.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,28 @@
1-
# Main Interface types
1+
# The algorithm interface
2+
3+
## General design ideas
4+
5+
The interface this package provides is based on three ingredients of running an algorithm
6+
consists of:
7+
8+
* a [`Problem`](@ref) that is to be solved and contains all information that is algorithm independent.
9+
This is _static information_ in the sense that it does not change during the runtime of the algorithm
10+
* an [`Algorithm`](@ref) that includes all of the _settings_ and _parameters_ that an algorithm.
11+
this is also information that is _static_
12+
* a [`State`](@ref) that contains all remaining data, especially data that might vary during the iteration,
13+
temporary caches, for example the current iteration the algorithm run is in and the current iterate, respectively.
14+
15+
The combination of the static information should be enough to initialize the varying data.
16+
17+
This general scheme is a guiding principle of the package, splitting information into _static_
18+
or _configuration_ types or data that allows to [`initialize`](@ref) a correspondint _variable_ data type.
19+
20+
The order of arguments is given by two ideas
21+
22+
1. for non-mutating functions the order should be from the most fixed data to the most variable one.
23+
For example the three types just mentioned would be ordered like `f(problem, algorithm, state)`
24+
2. For mutating functions the variable that is mutated comes first, for the remainder the guiding principle from 1 continues.
25+
The main case here is `f!(state, problem, algorithm)`.
226

327
```@autodocs
428
Modules = [AlgorithmsInterface]

docs/src/notation.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Notation
2+
3+
Throughout the package we use the following abbreviations and variable names,
4+
where the longer names are usually used in the documentation and as keywords.
5+
The shorter ones are often used in code when their name does not cause ambiguities.
6+
7+
| Name | Variable | Comment |
8+
| ---- | -------- | ------- |
9+
| [`Algorithm`](@ref) | `algorithm`, `a` | |
10+
| [`Problem`](@ref) | `problem`, `p` | |
11+
| [`State`](@ref) | `state`, `s` | |
12+
| [`StoppingCriterion`](@ref) | `stopping_criterion`, `sc` | |
13+
| [`StoppingCriterionState`](@ref) | `stopping_criterion_state`, `scs` | |

src/interface/algorithm.jl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,30 @@ A concrete algorithm contains all static parameters that characterise the algori
77
Together with a [`Problem`](@ref) an `Algorithm` subtype should be able to initialize
88
or reset a [`State`](@ref).
99
10+
## Usual fields
11+
12+
Usually this should include the following. If you use this naming scheme, default functions
13+
e.g. as accessors
14+
15+
* `stopping_criterion` a [`StoppingCriterion`](@ref)
16+
17+
## Methods
18+
19+
The following methods should be implemented for an [`Algorithm`](@ref)
20+
21+
* [`get_stopping_criterion`](@ref) to return the algorithms stopping criterion.
1022
## Example
1123
1224
For a [gradient descent](https://en.wikipedia.org/wiki/Gradient_descent) algorithm
1325
the algorithm would specify which step size selection to use.
1426
"""
1527
abstract type Algorithm end
28+
29+
"""
30+
get_stopping_criterion(a::Algorithm)
31+
32+
Return the [`StoppingCriterion`](@ref) of the [`Algorithm`](@ref) `a`.
33+
34+
The default assumes that the criterion is stored in `s.stopping_criterion_state`.
35+
"""
36+
get_stopping_criterion(a::Algorithm) = a.stopping_criterion

src/interface/interface.jl

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
_doc_init_state = """
22
s = initialize_state(p::Problem, a::Algorithm; kwargs...)
3-
initialize_state!(p::Problem, a::Algorithm, s::State; kwargs...)
3+
initialize_state!(s::State, p::Problem, a::Algorithm; kwargs...)
44
55
Initialize a [`State`](@ref) `s` base on a [`Problem`](@ref) `p` and an [`Algorithm`](@ref).
66
The `kwargs...` should allow to initialize for example the initial point.
@@ -19,10 +19,14 @@ initialize_state!(::State, ::Problem, ::Algorithm; kwargs...)
1919

2020
@doc """
2121
is_finished(p::Problem, a::Algorithm, s::State)
22+
23+
Return `true` if the [`Algorithm`](@ref) `a` solving the [`Problem`](@ref) `p`
24+
with current [`State`](@ref) `s` is finished
2225
"""
2326
function is_finished(p::Problem, a::Algorithm, s::State)
24-
sc = get_stopping_criterion(s)
25-
return sc(p, a, s)
27+
scs = get_stopping_criterion_state(s)
28+
sc = get_stopping_criterion(a)
29+
return scs(p, a, s, sc)
2630
end
2731

2832
# has to be defined before used in solve but is documented alphabetically after
@@ -46,12 +50,12 @@ end
4650
solve!(p::Problem, a::Algorithm, s::State; kwargs...)
4751
4852
Solve the [`Problem`](@ref) `p` using the [`Algorithm`](@ref) `a`
49-
working on the [`State`](@ref).
53+
modifying on the [`State`](@ref).
5054
51-
All keyword arguments are passed to the [`initialize_state!`](@ref) function.
55+
All keyword arguments are passed to the [`initialize_state!`](@ref)`(s, p, a)` function.
5256
"""
53-
function solve!(p::Problem, a::Algorithm, s::State; kwargs...)
54-
initialize_state!(p, a, s; kwargs...)
57+
function solve!(s::State, p::Problem, a::Algorithm; kwargs...)
58+
initialize_state!(s, p, a; kwargs...)
5559
while !is_finished(p, a, s)
5660
increment!(s)
5761
step!(p, a, s)
@@ -60,9 +64,9 @@ end
6064

6165
function step! end
6266
@doc """
63-
step!(p::Problem, a::Algorithm, s::State)
67+
step!(s::State, p::Problem, a::Algorithm)
6468
6569
Perform the current step of an [`Algorithm`](@ref) `a` solving [`Problem`](@ref) `p`
66-
starting from [`State`](@ref) `s`.
70+
modifying the algorithms [`State`](@ref) `s`.
6771
"""
68-
step!(p::Problem, a::Algorithm, s::State)
72+
step!(state::State, p::Problem, a::Algorithm)

src/interface/state.jl

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,27 @@ An abstract type to represent the state an iterative algorithm is in.
66
The state consists of any information that describes the current step the algorithm is in
77
and keeps all information needed from one step to the next.
88
9-
Usually this should include
9+
## Usual fields
10+
11+
Usually this should include the following. If you use this naming scheme, default functions
12+
e.g. as accessors
1013
1114
* `iteration` – the current iteration step ``k`` that is is currently performed or was last performed
12-
* `stopping_criterion` – a `StoppingCriterion` that indicates whether the algorithm
15+
* `stopping_criterion_state` – a [`StoppingCriterionState`](@ref) that indicates whether an [`Algorithm`](@ref)
1316
will stop after this iteration or has stopped.
1417
* `iterate` the current iterate ``x^{(k)}```.
1518
1619
These variable names given in this list are the defaults for which the accessors are implemented,
1720
such that if your concrete `MyState <: State` follows this convention, you do not have to reimplement
1821
their accessors.
1922
20-
# Methods
23+
## Methods
24+
2125
The following methods should be implemented for a state
26+
2227
* [`get_iteration`](@ref)`(s)` to return the current iteration number
2328
* [`increment!](@ref)`(s)`
24-
* [`get_stopping_criterion`](@ref) return the [`StoppingCriterion`](@ref)
29+
* [`get_stopping_criterion_state`](@ref) return the [`StoppingCriterionState`](@ref)
2530
* [`get_iterate`](@ref) return the current iterate ``x^{(k)}``.
2631
"""
2732
abstract type State end
@@ -57,10 +62,10 @@ function increment!(s::State)
5762
end
5863

5964
"""
60-
get_stopping_criterion(s::State)
65+
get_stopping_criterion_state(s::State)
6166
62-
Return the [`StoppingCriterion`](@ref) of the [`State`](@ref) `s`.
67+
Return the [`StoppingCriterionState`](@ref) of the [`State`](@ref) `s`.
6368
64-
The default assumes that the criterion is stored in `s.stopping_criterion`.
69+
The default assumes that the criterion is stored in `s.stopping_criterion_state`.
6570
"""
66-
get_stopping_criterion(s::State) = s.stopping_criterion
71+
get_stopping_criterion(s::State) = s.stopping_criterion_state

src/stopping_criterion.jl

Lines changed: 75 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,73 @@
11
@doc """
22
StoppingCriterion
33
4-
An abstract type to represent a stopping criterion of an solver.
4+
An abstract type to represent a stopping criterion.
55
6-
Any concrete stopping criterion should be implemented as a functor,
7-
that takes the “usual tuple” `(p, a, s)` of a [`Problem`](@ref) `p`,
8-
an [`Algorithm`](@ref) and a [`State`](@ref) as input, where this criterion
9-
should usually be part of the [`State`](@ref) itself.
10-
11-
## Methods
6+
A concrete [`StoppingCriterion`](@ref) `sc` should also implement a
7+
[`initialize(sc::StoppingCriterion)`](@ref) function to create its accompaying
8+
[`StoppingCriterionState`](@ref).
9+
It should usually implement
1210
13-
A concrete `StoppingCriterion` `sc` should provide the following functions
14-
besides the above-mentioned functor is it itself
15-
16-
* `get_reason(sc)` a human readable text of about one line of length providing a reason
17-
why this stopping criterion indicated to stop. An empty string if it did not indicate to stop
18-
* `get_summary(sc)` a short summary of this stopping criterion, and whether it was reached,
19-
e.g. a short string like `"Max Iterations (15): reached"`
2011
* `indicates_convergence(sc)` a boolean whether or not this stopping criterion would indicate
2112
that the algorithm has converged, if it indicates to stop.
22-
* `show(io::IO, sc)` to display its constructor and the `get_summary`
13+
* `show(io::IO, scs)` for use in REPL and display within an [`Algorithm`](@ref).
2314
"""
2415
abstract type StoppingCriterion end
2516

17+
@doc """
18+
StoppingCriterionState
19+
20+
An abstract type to represent a stopping criterion state withinn a [`State`](@ref).
21+
22+
Any concrete stopping criterion should be implemented as a functor,
23+
that takes the “usual tuple” `(problem, algorithm, state, stopping_criterion)`
24+
of a [`Problem`](@ref) `p`, an [`Algorithm`](@ref) and a [`State`](@ref) as input,
25+
as well as the corresponding [`StoppingCriterion`](@ref). Though this is usually stored¨
26+
in the [`Algorithm`](@ref) `algorithm`, the extra parameter allows both for more flexibility and
27+
for multiple dispatch.
28+
The concrete [`StoppingCriterionState`](@ref) should be part of the [`State`](@ref) `state`.
29+
30+
The functor might modify the stopping criterion state.
31+
"""
32+
abstract type StoppingCriterionState end
33+
2634
function get_reason end
2735
@doc """
28-
get_reason(sc::StoppingCriterion)
36+
get_reason(sc::StoppingCriterion, scs::StoppingCriterionState)
2937
30-
Provide a reason in human readable text as to why a [`StoppingCriterion`](@ref) indicated
31-
to stop. If it does not indicate to stop, this should return an empty string.
38+
Provide a reason in human readable text as to why a [`StoppingCriterion`](@ref) `sc
39+
with [`StoppingCriterionState`](@ref) `scs` indicated to stop.
40+
If it does not indicate to stop, this should return an empty string.
3241
33-
Providing the iteration at which this indicated to stop would be preferrable.
42+
Providing the iteration at which this indicated to stop in the reason would be preferable.
3443
"""
35-
get_reason(::StoppingCriterion)
44+
get_reason(::StoppingCriterion, ::StoppingCriterionState)
3645

3746
function indicates_convergence end
3847
@doc """
3948
indicates_convergence(sc::StoppingCriterion)
4049
41-
Return whether or not a [`StoppingCriterion`](@ref) indicates convergence of an algorithm
42-
if it would indicate to stop.
50+
Return whether or not a [`StoppingCriterion`](@ref) `sc` indicates convergence.
4351
"""
44-
indicates_convergence(::StoppingCriterion)
52+
indicates_convergence(sc::StoppingCriterion)
53+
54+
@doc """
55+
indicates_convergence(sc::StoppingCriterion, ::StoppingCriterionState)
4556
57+
Return whether or not a [`StoppingCriterion`](@ref) `sc` indicates convergence
58+
when it is in [`StoppingCriterionState`](@ref)
59+
60+
By default this checks whether the [`StoppingCriterion`](@ref) has actually stopped.
61+
If so it returns whether `sc` itself indicates convergence, otherwise it returns `false`,
62+
since the algorithm has then not yet stopped.
63+
"""
64+
function indicates_convergence(sc::StoppingCriterion, scs::StoppingCriterionState)
65+
return length(get_reason(sc, scs)) > 0 ? indicates_convergence(sc) : false
66+
end
4667

4768
function get_summary end
4869
@doc """
49-
get_summary(sc::StoppingCriterion)
70+
get_summary(sc::StoppingCriterion, scs::StoppingCriterionState)
5071
5172
Provide a summary of the status of a stopping criterion – its parameters and whether
5273
it currently indicates to stop. It should not be longer than one line
@@ -59,42 +80,60 @@ For the [`StopAfterIteration`](@ref) criterion, the summary looks like
5980
Max Iterations (15): not reached
6081
```
6182
"""
62-
get_summary(sc::StoppingCriterion)
83+
get_summary(sc::StoppingCriterion, scs::StoppingCriterionState)
6384

6485
@doc raw"""
6586
StopAfterIteration <: StoppingCriterion
6687
67-
A functor for a stopping criterion to stop after a maximal number of iterations.
88+
A simple stopping criterion to stop after a maximal number of iterations.
6889
6990
# Fields
7091
7192
* `max_iterations` stores the maximal iteration number where to stop at
72-
* `at_iteration` indicates at which iteration (including `i=0`) the stopping criterion
73-
was fulfilled and is `-1` while it is not fulfilled.
7493
7594
# Constructor
7695
7796
StopAfterIteration(maxIter)
7897
7998
initialize the functor to indicate to stop after `maxIter` iterations.
8099
"""
81-
mutable struct StopAfterIteration <: StoppingCriterion
82-
max_iterations::Int
100+
struct StopAfterIteration <: StoppingCriterion
101+
max_iterations::Int
102+
end
103+
104+
"""
105+
DefaultStoppingCriterionState <: StoppingCriterionState
106+
107+
A [`StoppingCriterionState`](@ref) that does not require any information besides
108+
storing the iteration number when it (last) indicated to stop).
109+
110+
# Field
111+
* `at_iteration::Int` store the iteration number this state
112+
indicated to stop.
113+
* `0` means already at the start it indicated to stop
114+
* any negative number means that it did not yet indicate to stop.
115+
"""
116+
mutable struct DefaultStoppingCriterionState
83117
at_iteration::Int
84-
StopAfterIteration(k::Int) = new(k, -1)
118+
DefaultStoppingCriterionState() = new(-1)
119+
end
120+
121+
initialize(::Problem, ::Algorithm, ::State, ::StopAfterIteration) = DefaultStoppingCriterionState()
122+
function initialize!(scs::DefaultStoppingCriterionState, ::Problem, ::Algorithm, ::State, ::StopAfterIteration)
123+
scs.indicated_convergence_at = -1
124+
return scs
85125
end
86-
function (sc::StopAfterIteration)(::Problem, ::Algorithm, s::State)
126+
127+
function (sc::DefaultStoppingCriterionState)(::Problem, ::Algorithm, s::State, sc::StopAfterIteration)
87128
k = get_iteration(s)
88-
if k == 0 # reset on init
89-
sc.at_iteration = -1
90-
end
129+
(k == 0) && (sc.at_iteration = -1)
91130
if k >= sc.max_iterations
92131
sc.at_iteration = k
93132
return true
94133
end
95134
return false
96135
end
97-
function get_reason(c::StopAfterIteration)
136+
function get_reason(c::StopAfterIteration, scs::DefaultStoppingCriterionState)
98137
if c.at_iteration >= c.max_iterations
99138
return "At iteration $(c.at_iteration) the algorithm reached its maximal number of iterations ($(c.max_iterations)).\n"
100139
end

0 commit comments

Comments
 (0)