use of com.ichi2.anki.CardBrowser.Column.REVIEWS in project AnkiChinaAndroid by ankichinateam.
the class Sched method deckDueList.
/**
* Returns [deckname, did, rev, lrn, new]
*/
@Override
@Nullable
public List<DeckDueTreeNode> deckDueList(@Nullable CollectionTask collectionTask, long did) {
_checkDay();
mCol.getDecks().checkIntegrity();
ArrayList<Deck> decks = deckLimitWithParent(did, mCol);
// ArrayList<Deck> decks = mCol.getDecks().allSorted();
Timber.i("show decks" + did + " size:" + decks.size());
HashMap<String, Integer[]> lims = new HashMap<>();
ArrayList<DeckDueTreeNode> data = new ArrayList<>();
long time = SystemClock.elapsedRealtime();
for (Deck deck : decks) {
if (collectionTask != null && collectionTask.isCancelled()) {
return null;
}
String deckName = deck.getString("name");
String p = Decks.parent(deckName);
// new
int nlim = _deckNewLimitSingle(deck);
int rlim = _deckRevLimitSingle(deck);
if (!TextUtils.isEmpty(p)) {
Integer[] parentLims = lims.get(Decks.normalizeName(p));
// 'temporary for diagnosis of bug #6383'
Assert.that(parentLims != null, "Deck %s is supposed to have parent %s. It has not be found.", deckName, p);
nlim = Math.min(nlim, parentLims[0]);
// review
rlim = Math.min(rlim, parentLims[1]);
}
// long time = SystemClock.elapsedRealtime();
int _new = _newForDeck(deck.getLong("id"), nlim);
// Timber.i("cost time for new:"+(SystemClock.elapsedRealtime()-time));
// learning
int lrn = _lrnForDeck(deck.getLong("id"));
// Timber.i("cost time for lrn:"+(SystemClock.elapsedRealtime()-time));
// reviews
int rev = _revForDeck(deck.getLong("id"), rlim);
// Timber.i("cost time for rev:"+(SystemClock.elapsedRealtime()-time));
// save to list
double[] datas = did == ALL_DECKS_ID ? _getCardDataCount(deck.getLong("id")) : new double[] { 0, 0, 0 };
// Timber.i("cost time for datas:"+(SystemClock.elapsedRealtime()-time));
// Timber.i("add deck in tree:%s", deckName);
data.add(new DeckDueTreeNode(mCol, deck.getString("name"), deck.getLong("id"), rev, lrn, _new, datas));
// add deck as a parent
lims.put(Decks.normalizeName(deck.getString("name")), new Integer[] { nlim, rlim });
}
Timber.i("cost time for datas:" + (SystemClock.elapsedRealtime() - time));
return data;
}
use of com.ichi2.anki.CardBrowser.Column.REVIEWS in project AnkiChinaAndroid by ankichinateam.
the class SchedV2 method deckDueList.
// Overridden
@Nullable
public List<DeckDueTreeNode> deckDueList(@Nullable CollectionTask collectionTask, long did) {
_checkDay();
mCol.getDecks().checkIntegrity();
// ArrayList<Deck> decks = mCol.getDecks().allSorted();
ArrayList<Deck> decks = deckLimitWithParent(did, mCol);
Timber.i("show decks" + did + " size:" + decks.size());
HashMap<String, Integer[]> lims = new HashMap<>();
ArrayList<DeckDueTreeNode> data = new ArrayList<>();
HashMap<Long, HashMap> childMap = mCol.getDecks().childMap();
for (Deck deck : decks) {
if (collectionTask != null && collectionTask.isCancelled()) {
return null;
}
String deckName = deck.getString("name");
String p = Decks.parent(deckName);
// new
int nlim = _deckNewLimitSingle(deck);
Integer plim = null;
if (!TextUtils.isEmpty(p)) {
Integer[] parentLims = lims.get(Decks.normalizeName(p));
// 'temporary for diagnosis of bug #6383'
Assert.that(parentLims != null, "Deck %s is supposed to have parent %s. It has not be found.", deckName, p);
nlim = Math.min(nlim, parentLims[0]);
// reviews
plim = parentLims[1];
}
int _new = _newForDeck(deck.getLong("id"), nlim);
// learning
int lrn = _lrnForDeck(deck.getLong("id"));
// reviews
int rlim = _deckRevLimitSingle(deck, plim);
int rev = _revForDeck(deck.getLong("id"), rlim, childMap);
double[] datas = did == ALL_DECKS_ID ? _getCardDataCount(deck.getLong("id")) : new double[] { 0, 0, 0 };
// save to list
// Timber.i("add deck in tree:%s", deckName);
data.add(new DeckDueTreeNode(mCol, deck.getString("name"), deck.getLong("id"), rev, lrn, _new, datas));
// add deck as a parent
lims.put(Decks.normalizeName(deck.getString("name")), new Integer[] { nlim, rlim });
}
return data;
}
use of com.ichi2.anki.CardBrowser.Column.REVIEWS in project AnkiChinaAndroid by ankichinateam.
the class AdvancedStatistics method calculateDueAsMetaInfo.
/**
* Determine forecast statistics based on a computation or simulation of future reviews.
* Returns all information required by stats.java to plot the 'forecast' chart based on these statistics.
* The chart will display:
* - The forecasted number of reviews per review type (relearn, mature, young, learn) as bars
* - The forecasted number of cards in each state (new, young, mature) as lines
* @param metaInfo Object which will be filled with all information required by stats.java to plot the 'forecast' chart and returned by this method.
* @param type Type of 'forecast' chart for which to determine forecast statistics. Accepted values:
* Stats.TYPE_MONTH: Determine forecast statistics for next 30 days with 1-day chunks
* Stats.TYPE_YEAR: Determine forecast statistics for next year with 7-day chunks
* Stats.TYPE_LIFE: Determine forecast statistics for next 2 years with 30-day chunks
* @param context Contains The collection which contains the decks to be simulated.
* Also used for access to the database and access to the creation time of the collection.
* The creation time of the collection is needed since due times of cards are relative to the creation time of the collection.
* So we could pass mCol here.
* @param dids Deck id's
* @return @see #metaInfo
*/
public StatsMetaInfo calculateDueAsMetaInfo(StatsMetaInfo metaInfo, Stats.AxisType type, Context context, String dids) {
if (!AnkiDroidApp.getSharedPrefs(context).getBoolean("advanced_statistics_enabled", false)) {
return metaInfo;
}
// To indicate that we calculated the statistics so that Stats.java knows that it shouldn't display the standard Forecast chart.
Settings = new Settings(context);
metaInfo.setStatsCalculated(true);
Collection mCol = CollectionHelper.getInstance().getCol(context);
double[][] mSeriesList;
int[] mValueLabels;
int[] mColors;
int[] mAxisTitles;
int mMaxCards = 0;
int mMaxElements;
double mFirstElement;
double mLastElement = 0;
int mZeroIndex = 0;
double[][] mCumulative;
double mMcount;
mValueLabels = new int[] { R.string.statistics_relearn, R.string.statistics_mature, R.string.statistics_young, R.string.statistics_learn };
mColors = new int[] { R.attr.stats_relearn, R.attr.stats_mature, R.attr.stats_young, R.attr.stats_learn };
mAxisTitles = new int[] { type.ordinal(), R.string.stats_cards, R.string.stats_cumulative_cards };
PlottableSimulationResult simuationResult = calculateDueAsPlottableSimulationResult(type, mCol, dids);
ArrayList<int[]> dues = simuationResult.getNReviews();
mSeriesList = new double[REVIEW_TYPE_COUNT_PLUS_1][dues.size()];
for (int t = 0; t < dues.size(); t++) {
int[] data = dues.get(t);
int nReviews = data[REVIEW_TYPE_LEARN_PLUS_1] + data[REVIEW_TYPE_YOUNG_PLUS_1] + data[REVIEW_TYPE_MATURE_PLUS_1] + data[REVIEW_TYPE_RELEARN_PLUS_1];
if (nReviews > mMaxCards)
// Y-Axis: Max. value
mMaxCards = nReviews;
// In the bar-chart, the bars will be stacked on top of each other.
// For the i^{th} bar counting from the bottom we therefore have to
// provide the sum of the heights of the i^{th} bar and all bars below it.
// X-Axis: Day / Week / Month
mSeriesList[TIME][t] = data[TIME];
mSeriesList[REVIEW_TYPE_LEARN_PLUS_1][t] = data[REVIEW_TYPE_LEARN_PLUS_1] + data[REVIEW_TYPE_YOUNG_PLUS_1] + data[REVIEW_TYPE_MATURE_PLUS_1] + // Y-Axis: # Cards
data[REVIEW_TYPE_RELEARN_PLUS_1];
mSeriesList[REVIEW_TYPE_YOUNG_PLUS_1][t] = data[REVIEW_TYPE_LEARN_PLUS_1] + data[REVIEW_TYPE_YOUNG_PLUS_1] + // Y-Axis: # Mature cards
data[REVIEW_TYPE_MATURE_PLUS_1];
mSeriesList[REVIEW_TYPE_MATURE_PLUS_1][t] = data[REVIEW_TYPE_LEARN_PLUS_1] + // Y-Axis: # Young
data[REVIEW_TYPE_YOUNG_PLUS_1];
// Y-Axis: # Learn
mSeriesList[REVIEW_TYPE_RELEARN_PLUS_1][t] = data[REVIEW_TYPE_LEARN_PLUS_1];
if (data[TIME] > mLastElement)
// X-Axis: Max. value (only for TYPE_LIFE)
mLastElement = data[TIME];
if (data[TIME] == 0) {
// Because we retrieve dues in the past and we should not cumulate them
mZeroIndex = t;
}
}
// # X values
mMaxElements = dues.size() - 1;
switch(type) {
case TYPE_MONTH:
// X-Axis: Max. value
mLastElement = 31;
break;
case TYPE_YEAR:
// X-Axis: Max. value
mLastElement = 52;
break;
default:
}
// X-Axis: Min. value
mFirstElement = 0;
// Day starting at mZeroIndex, Cumulative # cards
mCumulative = simuationResult.getNInState();
mMcount = // Y-Axis: Max. cumulative value
mCumulative[CARD_TYPE_NEW_PLUS_1][mCumulative[CARD_TYPE_NEW_PLUS_1].length - 1] + mCumulative[CARD_TYPE_YOUNG_PLUS_1][mCumulative[CARD_TYPE_YOUNG_PLUS_1].length - 1] + mCumulative[CARD_TYPE_MATURE_PLUS_1][mCumulative[CARD_TYPE_MATURE_PLUS_1].length - 1];
// some adjustments to not crash the chartbuilding with empty data
if (mMaxElements == 0) {
mMaxElements = 10;
}
if (mMcount == 0) {
mMcount = 10;
}
if (mFirstElement == mLastElement) {
mFirstElement = 0;
mLastElement = 6;
}
if (mMaxCards == 0)
mMaxCards = 10;
metaInfo.setmDynamicAxis(true);
metaInfo.setmHasColoredCumulative(true);
metaInfo.setmType(type);
metaInfo.setmTitle(R.string.stats_forecast);
metaInfo.setmBackwards(true);
metaInfo.setmValueLabels(mValueLabels);
metaInfo.setmColors(mColors);
metaInfo.setmAxisTitles(mAxisTitles);
metaInfo.setmMaxCards(mMaxCards);
metaInfo.setmMaxElements(mMaxElements);
metaInfo.setmFirstElement(mFirstElement);
metaInfo.setmLastElement(mLastElement);
metaInfo.setmZeroIndex(mZeroIndex);
metaInfo.setmCumulative(mCumulative);
metaInfo.setmMcount(mMcount);
metaInfo.setmSeriesList(mSeriesList);
metaInfo.setDataAvailable(dues.size() > 0);
return metaInfo;
}
use of com.ichi2.anki.CardBrowser.Column.REVIEWS in project AnkiChinaAndroid by ankichinateam.
the class SchedV2 method _earlyReviewIvl.
/**
* next interval for card when answered early+correctly
*/
private int _earlyReviewIvl(@NonNull Card card, @Consts.BUTTON_TYPE int ease) {
if (card.getODid() == 0 || card.getType() != Consts.CARD_TYPE_REV || card.getFactor() == 0) {
throw new RuntimeException("Unexpected card parameters");
}
if (ease <= 1) {
throw new RuntimeException("Ease must be greater than 1");
}
long elapsed = card.getIvl() - (card.getODue() - mToday);
@NonNull JSONObject conf = _revConf(card);
double easyBonus = 1;
// early 3/4 reviews shouldn't decrease previous interval
double minNewIvl = 1;
double factor;
if (ease == Consts.BUTTON_TWO) {
factor = conf.optDouble("hardFactor", 1.2);
// hard cards shouldn't have their interval decreased by more than 50%
// of the normal factor
minNewIvl = factor / 2;
} else if (ease == 3) {
factor = card.getFactor() / 1000.0;
} else {
// ease == 4
factor = card.getFactor() / 1000.0;
double ease4 = conf.getDouble("ease4");
// 1.3 -> 1.15
easyBonus = ease4 - (ease4 - 1) / 2;
}
double ivl = Math.max(elapsed * factor, 1);
// cap interval decreases
ivl = Math.max(card.getIvl() * minNewIvl, ivl) * easyBonus;
return _constrainedIvl(ivl, conf, 0, false);
}
use of com.ichi2.anki.CardBrowser.Column.REVIEWS in project AnkiChinaAndroid by ankichinateam.
the class SchedV2Test method test_review_limits.
@Test
public void test_review_limits() throws Exception {
Collection col = getColV2();
Deck parent = col.getDecks().get(col.getDecks().id("parent"));
Deck child = col.getDecks().get(col.getDecks().id("parent::child"));
DeckConfig pconf = col.getDecks().getConf(col.getDecks().confId("parentConf"));
DeckConfig cconf = col.getDecks().getConf(col.getDecks().confId("childConf"));
pconf.getJSONObject("rev").put("perDay", 5);
col.getDecks().updateConf(pconf);
col.getDecks().setConf(parent, pconf.getLong("id"));
cconf.getJSONObject("rev").put("perDay", 10);
col.getDecks().updateConf(cconf);
col.getDecks().setConf(child, cconf.getLong("id"));
Model m = col.getModels().current();
m.put("did", child.getLong("id"));
col.getModels().save(m, false);
// add some cards
for (int i = 0; i < 20; i++) {
Note note = col.newNote();
note.setItem("Front", "one");
note.setItem("Back", "two");
col.addNote(note);
// make them reviews
Card c = note.cards().get(0);
c.setQueue(CARD_TYPE_REV);
c.setType(QUEUE_TYPE_REV);
c.setDue(0);
c.flush();
}
// position 0 is default deck. Different from upstream
DeckDueTreeNode tree = col.getSched().deckDueTree().get(1);
// (('parent', 1514457677462, 5, 0, 0, (('child', 1514457677463, 5, 0, 0, ()),)))
assertEquals("parent", tree.getFullDeckName());
// paren, tree.review_count)t
assertEquals(5, tree.getRevCount());
assertEquals(5, tree.getChildren().get(0).getRevCount());
// .counts() should match
col.getDecks().select(child.getLong("id"));
col.reset();
assertArrayEquals(new int[] { 0, 0, 5 }, col.getSched().counts());
// answering a card in the child should decrement parent count
Card c = col.getSched().getCard();
col.getSched().answerCard(c, 3);
assertArrayEquals(new int[] { 0, 0, 4 }, col.getSched().counts());
tree = col.getSched().deckDueTree().get(1);
assertEquals(4, tree.getRevCount());
assertEquals(4, tree.getChildren().get(0).getRevCount());
}
Aggregations