# method


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

Each question, hint and lesson uses one way to teach: its `method`. The
tutor picks the method before it writes the prompt. So the tag is known,
not guessed. When a question closes, its outcome counts for its method:
solid 1, shaky 0.5, a miss 0.

The counts give each method a Beta posterior, for each subject and over
all subjects.
[`choose`](https://vedicreader.github.io/abhyasa/method.html#choose)
uses them in two ways:

- Drill: a weak concept gets your best method.
- Explore: a concept that is not weak sometimes gets another method. You
  set the chance (`explore` in the profile). First
  [`choose`](https://vedicreader.github.io/abhyasa/method.html#choose)
  tries a method that got better recently. Else it uses a random draw (a
  Thompson sample).

The counts are in one `stats` document on the shelf. This document is
only a cache: `method_stats` builds it again from the attempts.

Import the modules that this notebook uses.

## The methods

`METHODS` maps each method to the line that the prompt gets.
`EXAMPLES_TO` maps the profile’s “examples that help” to methods, to set
the prior.

## The stats document

`stats` reads the stats document. It gives empty counts when there is no
document. `set_stats` writes the document. A lock makes sure that two
closes at the same time do not lose a count.

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/abhyasa/blob/main/abhyasa/method.py#L39"
target="_blank" style="float:right; font-size:smaller">source</a>

### Learning.set_stats

``` python
def set_stats(
    **kv
):
```

*Change fields of the stats document.*

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/abhyasa/blob/main/abhyasa/method.py#L33"
target="_blank" style="float:right; font-size:smaller">source</a>

### Learning.stats

``` python
def stats()->fastcore.basics.AttrDict:
```

*The cached stats: method counts for each subject (`*` is all), recent
credits, and calibration.*

## Credit

[`credit`](https://vedicreader.github.io/abhyasa/method.html#credit)
adds one outcome to the counts and returns the new stats. It keeps the
last 8 credits of each method, to find a method that gets better.

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/abhyasa/blob/main/abhyasa/method.py#L58"
target="_blank" style="float:right; font-size:smaller">source</a>

### Learning.credit_method

``` python
def credit_method(
    method:str, subject:str, kind:str
):
```

*Count outcome `kind` for `method` in the stats document.*

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/abhyasa/blob/main/abhyasa/method.py#L46"
target="_blank" style="float:right; font-size:smaller">source</a>

### credit

``` python
def credit(
    st, method:str, subject:str, kind:str
)->dict:
```

*The stats `st` with one outcome `kind` added for `method`, in `subject`
and in `*`.*

Solid adds 1 to `a`. A miss adds 1 to `b`. Shaky adds half to each. An
unknown outcome or method changes nothing.

``` python
st = credit(credit(credit(EMPTY, 'code', 'ml', 'solid'), 'code', 'ml', 'fragile'), 'maths', 'ml', 'gap')
test_eq(st['methods']['ml'], {'code': [1.5, .5], 'maths': [0., 1.]})
test_eq(st['methods']['*'], st['methods']['ml'])
test_eq(st['recent'], {'code': [1., .5], 'maths': [0.]})
test_eq(credit(st, 'code', 'ml', 'closed'), st)
```

## The posterior

[`posterior`](https://vedicreader.github.io/abhyasa/method.html#posterior)
gives `(a, b)` for a method: Beta(1, 1), plus 2 on `a` for a method in
the profile’s examples. For a subject, it adds the subject counts and
the `*` counts. It scales the `*` counts down to at most 4
pseudo-counts. So a new subject starts from what works for you in other
subjects.

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/abhyasa/blob/main/abhyasa/method.py#L75"
target="_blank" style="float:right; font-size:smaller">source</a>

### improving

``` python
def improving(
    st, m:str
)->tuple | None:
```

*`(right, n)` over the last 5 credits of `m`, when they are at least 0.2
above its mean over all; else None.*

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/abhyasa/blob/main/abhyasa/method.py#L73"
target="_blank" style="float:right; font-size:smaller">source</a>

### mean

``` python
def mean(
    ab
)->float:
```

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/abhyasa/blob/main/abhyasa/method.py#L63"
target="_blank" style="float:right; font-size:smaller">source</a>

### posterior

``` python
def posterior(
    st, m:str, subject:str='', prior:tuple=()
)->tuple:
```

*The Beta `(a, b)` of method `m` in `subject`.*

With no counts, the prior decides.
[`improving`](https://vedicreader.github.io/abhyasa/method.html#improving)
finds a method that got better recently.

``` python
test_eq(posterior(EMPTY, 'code'), (1., 1.))
test_eq(posterior(EMPTY, 'code', prior=['code']), (3., 1.))
gm = dict(methods={'*': {'maths': [2., 4.]}}, recent={'maths': [0., 0., 1., 1., 1., 1.]})
test_eq(improving(gm, 'maths'), (4, 5))
test_is(improving(dict(gm, recent={'maths': [1., 0., 0., 0.]}), 'maths'), None)
```

## Choose a method

[`choose`](https://vedicreader.github.io/abhyasa/method.html#choose)
returns `(method, note)`. The note goes in the line that says why you
get this question.

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/abhyasa/blob/main/abhyasa/method.py#L89"
target="_blank" style="float:right; font-size:smaller">source</a>

### choose

``` python
def choose(
    st, subject:str='', weak:bool=False, rng:NoneType=None, explore:str='sometimes', prior:tuple=()
)->tuple:
```

*The method for the next question, and a note on why. A weak concept
gets the best method; else, sometimes, another one.*

A weak concept gets the best method. With `explore='never'`,
[`choose`](https://vedicreader.github.io/abhyasa/method.html#choose)
always gives the best method. With `sometimes`, it tries a method that
got better at times. It still gives the best method most of the time.

``` python
cs = dict(methods={'*': {'code': [7., 2.], 'maths': [2., 4.]}}, recent={'maths': [0., 0., 1., 1., 1., 1.]})
m, note = choose(cs, 'ml', weak=True)
test_eq(m, 'code'); assert note.startswith('drill with code: 7 of 9')
test_eq({choose(cs, 'ml', rng=random.Random(i), explore='never')[0] for i in range(30)}, {'code'})
picks = [choose(cs, 'ml', rng=random.Random(i)) for i in range(60)]
assert any(n.startswith('trying maths: you got better') for _, n in picks)
test_eq(sum(m == 'code' for m, _ in picks) > 30, True)   # with `sometimes`, the best method still comes most of the time
```

## In plain words, and from the attempts

[`methods_text`](https://vedicreader.github.io/abhyasa/method.html#methods_text)
says what works, for a prompt and for the page. `method_stats` builds
the counts again from the attempts, in order.

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/abhyasa/blob/main/abhyasa/method.py#L116"
target="_blank" style="float:right; font-size:smaller">source</a>

### Learning.method_stats

``` python
def method_stats(
    n:int=2000
)->dict:
```

*Count every final attempt with a method again, oldest first, and save
the counts. Return the stats.*

------------------------------------------------------------------------

<a
href="https://github.com/vedicreader/abhyasa/blob/main/abhyasa/method.py#L107"
target="_blank" style="float:right; font-size:smaller">source</a>

### methods_text

``` python
def methods_text(
    st, subject:str='', n:int=3
)->str:
```

*The methods with counts, best first, as one line; empty when nothing is
counted.*

The counts that `credit_method` keeps match a rebuild from the attempts.

``` python
ml_ = temp_learning(); ml_.put('Ranking', 'Order items by a score.', 'ml')
for m, k in (('code', 'solid'), ('code', 'fragile'), ('maths', 'gap')):
    ml_.record('ranking', f'{m} {k}?', final=True, method=m, outcome=k); ml_.credit_method(m, 'ml', k); time.sleep(.01)
inc = ml_.stats()
test_eq(ml_.method_stats()['methods'], inc.methods)
assert methods_text(inc, 'ml').startswith('Ways that work for you: code 2 of 2')
```
