brownbat / autoEaseFactor

Adjust ease factors in Anki based off of performance in order to hit a target success rate.
GNU General Public License v3.0
37 stars 8 forks source link

[Request] Could I intergrate this addon w/ induction booster? #17

Closed phu54321 closed 4 years ago

phu54321 commented 4 years ago

Hello, I'm the author of induction booster addon. This add-on sets each review's initial interval to match the target recall rate of first reviews.

I really like your addon This add-on does the job really well for non-first reviews, so the addon could cooperate well with the booster. Maybe I could integrate two addons to co-op more easily.

I've currently implemented the following features.

  1. Induction of initial boosts. (1)
  2. Boosting cards reviewed on non-addon-installed environments (AnkiDroid, etc) on sync. (2)
  3. Boosting non-first reviews, but your algorithm seems superior to mine. (3)

What I'd like to do:

  1. Add integration with your addon to mine:

    • Scrap (3).
    • Booster reads your addon config (target recall rate) and uses that for (1)
    • Booster calls code of your addon to achieve (2).
  2. Furthermore, add your addon as a dependency of mine: induction booster will auto-install auto ease factor addon when installed.

  3. Alternatively, autoEaseFactor could merge my addon's code. My addon is AGPL currently but I could make that zlib if you'd like. I could contribute the code for (1) and (2) as a PR. Maybe you'd have a different ideas recarding (1), so you could read the rationale of my algorithm on this code: For this case I'd like both (1: boosting initial interval) and (2: applying new interval to non-addon-installed PCs too) to be integratd.

        # avg = sum(1 / expectedRetentionRate if correct else 0 for correct, expectedRetentionRate, firstIvl in frLog) / len(frLog)
        # If current interval is well-calculated, avg should be 1
        #   : (1 / expectedRetentionRate) added with (realRetentionRate) probability
        #   :           0         added with (1 - realRetentionRate) probability
        # so if average deviates from 1, it means that retention rate is either too much or too less expected.

        # e^k(calculatedInterval) = targetRetentionRate
        # (expected retention rate) = e^k(firstIvl) = targetRetentionRate ^ (firstIvl / calculatedInterval)
        # find `calculatedInterval` so that the average of
        #   : targetRetentionRate ^ -(firstIvl / calculatedInterval)   for correct answers
        #   :           0                                                         for incorrect answers
        # is 1.
        def avg(ivl):
            return sum(
                targetRetentionRate ** (-firstIvl / ivl) if correct else 0
                for correct, firstIvl in frLog
            ) / len(frLog)

        for ivl in range(2, 20):
            if avg(ivl) <= 1.001:  # using exact value of 1.00 seems a bit unstable.
                ivl -= 1
                break

Thanks for reading this suggestion!

brownbat commented 4 years ago

It is surreal to read a comment thread with people talking about this little add on I'm mostly tinkering on to improve my own experience.

I'm glad we're working on improving similar issues and happy to share ideas and code. I like that you're tackling the starting interval (with more deck stats, if I'm reading it correctly?), something mine doesn't really touch as much, but has been on my wishlist for a while.

Honestly there are a lot of settings in deck options that can be overwhelming for someone new to Anki, it would be great if an algorithm could just handle all of that.

So you mention a few paths: fully consolidate the two add-ons, make this one a dependency, or just have you fold some of this code into your add-on...

I've been thinking over a few ideas to shift this algorithm so it gets more data about which cards are easy and which are hard, and treat them differently early on, maybe with a little more randomness and learning like A/B testing. That's really long term, but my only worry is that if I make those deeper changes it might conflict with your work.

I'll think about it more, but I think for now the best approach is for you to just copy the code here and pull it into induction booster, see if you can get both ideas working together in your add-on in the short term, rather than making this a dependency, or completely merging them, or waiting for me to finish those changes.

I inherited the licensing from other authors, so I can't just public domain it; but I'm really happy to see it used in other people's code if you can get it to work on your end.

If yours ends up being the more successful complete add-on and takes off, I'm super happy with that, I'm not trying to monetize this or anything, whatever helps the most people.

If you give that a shot, definitely let me know how it goes, happy to keep sharing ideas.

phu54321 commented 4 years ago

Thanks for the response :) I'll then copy the code here to my repo then 👍

phu54321 commented 4 years ago

Integrated here.

Will be released after some testing. Thanks for allowing me to use the code.