log cram reps separately; fix std rev reps

This commit is contained in:
Damien Elmes 2012-03-11 14:06:59 +09:00
parent da07e15a87
commit 4a12ec62c1
2 changed files with 45 additions and 9 deletions

View file

@ -12,13 +12,11 @@ from anki.consts import *
from anki.hooks import runHook
# revlog types: 0=lrn, 1=rev, 2=relrn, 3=cram
# other queue types: -1=suspended, -2=buried
# queue types: 0=new/cram, 1=lrn, 2=rev, -1=suspended, -2=buried
# positive intervals are in days (rev), negative intervals in seconds (lrn)
# fixme:
# - should log cram reps as cramming
# - later we should set conf=None for the cram deck to catch where we're
# pulling from the original conf instead of the cram conf
class Scheduler(object):
name = "std"
@ -408,7 +406,9 @@ limit %d""" % (self._deckLimit(), self.reportLimit), lim=self.dayCutoff)
def _answerLrnCard(self, card, ease):
# ease 1=no, 2=yes, 3=remove
conf = self._lrnConf(card)
if card.type == 2:
if card.odid:
type = 3
elif card.type == 2:
type = 2
else:
type = 0
@ -671,21 +671,21 @@ did = ? and queue = 2 and due <= ? %s limit ?""" % order,
def _nextRevIvl(self, card, ease):
"Ideal next interval for CARD, given EASE."
delay = self._daysLate(card)
conf = self._cardConf(card)
conf = self._revConf(card)
fct = card.factor / 1000.0
if ease == 2:
interval = (card.ivl + delay/4) * 1.2
elif ease == 3:
interval = (card.ivl + delay/2) * fct
elif ease == 4:
interval = (card.ivl + delay) * fct * conf['rev']['ease4']
interval = (card.ivl + delay) * fct * conf['ease4']
# apply forgetting index transform
interval = self._ivlForFI(conf, interval)
# must be at least one day greater than previous interval; two if easy
return max(card.ivl + (2 if ease==4 else 1), int(interval))
def _ivlForFI(self, conf, ivl):
new, old = conf['rev']['fi']
new, old = conf['fi']
return ivl * math.log(1-new/100.0) / math.log(1-old/100.0)
def _daysLate(self, card):
@ -700,7 +700,7 @@ did = ? and queue = 2 and due <= ? %s limit ?""" % order,
def _adjRevIvl(self, card, idealIvl):
"Given IDEALIVL, return an IVL away from siblings."
idealDue = self.today + idealIvl
conf = self._cardConf(card)['rev']
conf = self._revConf(card)
# find sibling positions
dues = self.col.db.list(
"select due from cards where nid = ? and queue = 2"
@ -773,7 +773,7 @@ usn = ?, mod = ? where did = ?""", self.col.usn(), intTime(), did)
queue = "0"
else:
# due reviews stay in the review queue
queue = "(case when queue=2 and due <= %d then 2 else 0 end)"
queue = "(case when type=2 and (odue or due) <= %d then 2 else 0 end)"
queue %= self.today
self.col.db.executemany("""
update cards set
@ -854,6 +854,19 @@ did = ?, queue = %s, due = ?, mod = ?, usn = ? where id = ?""" % queue, data)
mult=conf['fmult'],
)
def _revConf(self, card):
conf = self._cardConf(card)
# normal deck
if not card.odid:
return conf['rev']
# dynamic deck; override some attributes, use original deck for others
oconf = self.col.decks.confForDid(card.odid)
return dict(
# original deck
ease4=oconf['rev']['ease4'],
fi=oconf['rev']['fi']
)
def _deckLimit(self):
return ids2str(self.col.decks.active())

View file

@ -467,6 +467,9 @@ def test_cram():
assert c.ivl == 138
assert c.odue == 138
assert c.queue == 1
# should be logged as a cram rep
assert d.db.scalar(
"select type from revlog order by id desc limit 1") == 3
# check ivls again
assert d.sched.nextIvl(c, 1) == 60
assert d.sched.nextIvl(c, 2) == 138*60*60*24
@ -501,6 +504,26 @@ def test_cram():
c.load()
assert c.ivl == 1
assert c.due == d.sched.today+1
# make it due
d.reset()
assert d.sched.counts() == (0,0,0)
c.due = 0
c.flush()
d.reset()
assert d.sched.counts() == (0,0,1)
# cram again, by default it's treated like a review
did = d.decks.newDyn("Cram")
d.sched.rebuildDyn(did)
d.reset()
assert d.sched.counts() == (1,0,0)
# but if cramRev is false, it's placed in the review queue instead
d.decks.get(did)['cramRev'] = False
d.sched.rebuildDyn(did)
d.reset()
assert d.sched.counts() == (0,0,1)
# should be able to answer it
c = d.sched.getCard()
d.sched.answerCard(c, 4)
def test_adjIvl():
d = getEmptyDeck()