Search in sources :

Example 6 with REVIEWS

use of com.ichi2.anki.CardBrowser.Column.REVIEWS in project Anki-Android by ankidroid.

the class SchedV2Test method test_review_limits.

@Test
public void test_review_limits() throws Exception {
    Collection col = getColV2();
    Deck parent = col.getDecks().get(addDeck("parent"));
    Deck child = col.getDecks().get(addDeck("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(QUEUE_TYPE_REV);
        c.setType(CARD_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(10, tree.getChildren().get(0).getRevCount());
    // .counts() should match
    col.getDecks().select(child.getLong("id"));
    col.reset();
    assertEquals(new Counts(0, 0, 10), col.getSched().counts());
    // answering a card in the child should decrement parent count
    Card c = getCard();
    col.getSched().answerCard(c, BUTTON_THREE);
    assertEquals(new Counts(0, 0, 9), col.getSched().counts());
    tree = col.getSched().deckDueTree().get(1);
    assertEquals(4, tree.getRevCount());
    assertEquals(9, tree.getChildren().get(0).getRevCount());
}
Also used : Note(com.ichi2.libanki.Note) Model(com.ichi2.libanki.Model) Collection(com.ichi2.libanki.Collection) Deck(com.ichi2.libanki.Deck) DeckConfig(com.ichi2.libanki.DeckConfig) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 7 with REVIEWS

use of com.ichi2.anki.CardBrowser.Column.REVIEWS in project Anki-Android by ankidroid.

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.
    mSettings = new Settings(context);
    metaInfo.setStatsCalculated(true);
    Collection col = CollectionHelper.getInstance().getCol(context);
    int maxCards = 0;
    double lastElement = 0;
    int zeroIndex = 0;
    int[] valueLabels = { R.string.statistics_relearn, R.string.statistics_mature, R.string.statistics_young, R.string.statistics_learn };
    int[] colors = { R.attr.stats_relearn, R.attr.stats_mature, R.attr.stats_young, R.attr.stats_learn };
    int[] axisTitles = { type.ordinal(), R.string.stats_cards, R.string.stats_cumulative_cards };
    PlottableSimulationResult simuationResult = calculateDueAsPlottableSimulationResult(type, col, dids);
    ArrayList<int[]> dues = simuationResult.getNReviews();
    double[][] seriesList = 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 > maxCards)
            // Y-Axis: Max. value
            maxCards = 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
        seriesList[TIME][t] = data[TIME];
        seriesList[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];
        seriesList[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];
        seriesList[REVIEW_TYPE_MATURE_PLUS_1][t] = data[REVIEW_TYPE_LEARN_PLUS_1] + // Y-Axis: # Young
        data[REVIEW_TYPE_YOUNG_PLUS_1];
        // Y-Axis: # Learn
        seriesList[REVIEW_TYPE_RELEARN_PLUS_1][t] = data[REVIEW_TYPE_LEARN_PLUS_1];
        if (data[TIME] > lastElement)
            // X-Axis: Max. value (only for TYPE_LIFE)
            lastElement = data[TIME];
        if (data[TIME] == 0) {
            // Because we retrieve dues in the past and we should not cumulate them
            zeroIndex = t;
        }
    }
    // # X values
    int maxElements = dues.size() - 1;
    switch(type) {
        case TYPE_MONTH:
            // X-Axis: Max. value
            lastElement = 31;
            break;
        case TYPE_YEAR:
            // X-Axis: Max. value
            lastElement = 52;
            break;
        default:
    }
    // X-Axis: Min. value
    double firstElement = 0;
    // Day starting at zeroIndex, Cumulative # cards
    double[][] cumulative = simuationResult.getNInState();
    double count = // Y-Axis: Max. cumulative value
    cumulative[CARD_TYPE_NEW_PLUS_1][cumulative[CARD_TYPE_NEW_PLUS_1].length - 1] + cumulative[CARD_TYPE_YOUNG_PLUS_1][cumulative[CARD_TYPE_YOUNG_PLUS_1].length - 1] + cumulative[CARD_TYPE_MATURE_PLUS_1][cumulative[CARD_TYPE_MATURE_PLUS_1].length - 1];
    // some adjustments to not crash the chartbuilding with empty data
    if (maxElements == 0) {
        maxElements = 10;
    }
    if (count == 0) {
        count = 10;
    }
    if (firstElement == lastElement) {
        firstElement = 0;
        lastElement = 6;
    }
    if (maxCards == 0)
        maxCards = 10;
    metaInfo.setmDynamicAxis(true);
    metaInfo.setmHasColoredCumulative(true);
    metaInfo.setmType(type);
    metaInfo.setmTitle(R.string.stats_forecast);
    metaInfo.setmBackwards(true);
    metaInfo.setmValueLabels(valueLabels);
    metaInfo.setmColors(colors);
    metaInfo.setmAxisTitles(axisTitles);
    metaInfo.setmMaxCards(maxCards);
    metaInfo.setmMaxElements(maxElements);
    metaInfo.setmFirstElement(firstElement);
    metaInfo.setmLastElement(lastElement);
    metaInfo.setmZeroIndex(zeroIndex);
    metaInfo.setmCumulative(cumulative);
    metaInfo.setmMcount(count);
    metaInfo.setmSeriesList(seriesList);
    metaInfo.setDataAvailable(!dues.isEmpty());
    return metaInfo;
}
Also used : Collection(com.ichi2.libanki.Collection)

Example 8 with REVIEWS

use of com.ichi2.anki.CardBrowser.Column.REVIEWS in project Anki-Android by ankidroid.

the class OverviewStatsBuilderTest method testInfoHtmlStringMonth.

@Test
@Config(qualifiers = "en")
public void testInfoHtmlStringMonth() {
    OverviewStatsBuilder statsTester = new OverviewStatsBuilder(new WebView(getTargetContext()), getCol(), 42L, Stats.AxisType.TYPE_MONTH);
    String HTML = statsTester.createInfoHtmlString();
    assertEquals(HTML, "<center><style>\n" + "h1, h3 { margin-bottom: 0; margin-top: 1em; text-transform: capitalize; }\n" + ".pielabel { text-align:center; padding:0px; color:white; }\n" + "body {color:#FFFFFF;}\n" + "</style><h1>Today</h1>Studied <b>0 cards</b> in <b>0 minutes</b> today<br>Again count: <b>0</b><br>Learn: <b>0</b>, review: <b>0</b>, relearn: <b>0</b>, filtered: <b>0</b><br>No mature cards were studied today<h1>1 month</h1><h3>FORECAST</h3>Total: <b>0</b> reviews<br>Average: <b>0.0</b> reviews/day<br>Due tomorrow: <b>0</b><br><h3>REVIEW COUNT</h3>Days studied: <b>0%</b> (0 of 30)<br>Total: <b>0</b> reviews<br>Average for days studied: <b>0.0</b> reviews/day<br>If you studied every day: <b>0.0</b> reviews/day<br><h3>REVIEW TIME</h3>Days studied: <b>0%</b> (0 of 30)<br>Total: <b>0</b> minutes<br>Average for days studied: <b>0.0</b> minutes/day<br>If you studied every day: <b>0.0</b> minutes/day<br>Average answer time: <b>0.0s</b> (<b>0.00</b> cards/minute)<br><h3>ADDED</h3>Total: <b>0</b> cards<br>Average: <b>0.0</b> cards/day<br><h3>INTERVALS</h3>Average interval: <b>0.0</b> hours<br>Longest interval: <b>0.0</b> hours<h3>ANSWER BUTTONS</h3>Learning: <b>0.00%</b> correct (0 of 0)<br>Young: <b>0.00%</b> correct (0 of 0)<br>Mature: <b>0.00%</b> correct (0 of 0)<h3>CARD TYPES</h3>Total cards: <b>0</b><br>Total notes: <b>0</b><br>Lowest ease: <b>0%</b><br>Average ease: <b>0%</b><br>Highest ease: <b>0%</b></center>");
}
Also used : WebView(android.webkit.WebView) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test) Config(org.robolectric.annotation.Config)

Example 9 with REVIEWS

use of com.ichi2.anki.CardBrowser.Column.REVIEWS in project AnkiChinaAndroid by ankichinateam.

the class SchedTest method test_cram_resched.

@Test
public void test_cram_resched() throws Exception {
    // add card
    Collection col = getColV1();
    Note note = col.newNote();
    note.setItem("Front", "one");
    col.addNote(note);
    // cram deck
    long did = col.getDecks().newDyn("Cram");
    Deck cram = col.getDecks().get(did);
    cram.put("resched", false);
    col.getDecks().save(cram);
    col.getSched().rebuildDyn(did);
    col.reset();
    // graduate should return it to new
    Card c = col.getSched().getCard();
    assertEquals(60, col.getSched().nextIvl(c, 1));
    assertEquals(600, col.getSched().nextIvl(c, 2));
    assertEquals(0, col.getSched().nextIvl(c, 3));
    assertEquals("(end)", col.getSched().nextIvlStr(getTargetContext(), c, 3));
    col.getSched().answerCard(c, 3);
    assertEquals(CARD_TYPE_NEW, c.getType());
    assertEquals(QUEUE_TYPE_NEW, c.getQueue());
    // undue reviews should also be unaffected
    c.setIvl(100);
    c.setQueue(CARD_TYPE_REV);
    c.setType(QUEUE_TYPE_REV);
    c.setDue(col.getSched().getToday() + 25);
    c.setFactor(STARTING_FACTOR);
    c.flush();
    Card cardcopy = c.clone();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = col.getSched().getCard();
    assertEquals(600, col.getSched().nextIvl(c, 1));
    assertEquals(0, col.getSched().nextIvl(c, 2));
    assertEquals(0, col.getSched().nextIvl(c, 3));
    col.getSched().answerCard(c, 2);
    assertEquals(100, c.getIvl());
    assertEquals(col.getSched().getToday() + 25, c.getDue());
    // check failure too
    c = cardcopy;
    c.flush();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = col.getSched().getCard();
    col.getSched().answerCard(c, 1);
    col.getSched().emptyDyn(did);
    c.load();
    assertEquals(100, c.getIvl());
    assertEquals(col.getSched().getToday() + 25, c.getDue());
    // fail+grad early
    c = cardcopy;
    c.flush();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = col.getSched().getCard();
    col.getSched().answerCard(c, 1);
    col.getSched().answerCard(c, 3);
    col.getSched().emptyDyn(did);
    c.load();
    assertEquals(100, c.getIvl());
    assertEquals(col.getSched().getToday() + 25, c.getDue());
    // due cards - pass
    c = cardcopy;
    c.setDue(-25);
    c.flush();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = col.getSched().getCard();
    col.getSched().answerCard(c, 3);
    col.getSched().emptyDyn(did);
    c.load();
    assertEquals(100, c.getIvl());
    assertEquals(-25, c.getDue());
    // fail
    c = cardcopy;
    c.setDue(-25);
    c.flush();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = col.getSched().getCard();
    col.getSched().answerCard(c, 1);
    col.getSched().emptyDyn(did);
    c.load();
    assertEquals(100, c.getIvl());
    assertEquals(-25, c.getDue());
    // fail with normal grad
    c = cardcopy;
    c.setDue(-25);
    c.flush();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = col.getSched().getCard();
    col.getSched().answerCard(c, 1);
    col.getSched().answerCard(c, 3);
    c.load();
    assertEquals(100, c.getIvl());
    assertEquals(-25, c.getDue());
// lapsed card pulled into cram
// col.getSched()._cardConf(c)['lapse']['mult']=0.5
// col.getSched().answerCard(c, 1)
// col.getSched().rebuildDyn(did)
// col.reset()
// c = col.getSched().getCard()
// col.getSched().answerCard(c, 2)
// print c.__dict__
}
Also used : Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) Deck(com.ichi2.libanki.Deck) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 10 with REVIEWS

use of com.ichi2.anki.CardBrowser.Column.REVIEWS in project Anki-Android by ankidroid.

the class SchedTest method test_cram_resched.

@Test
public void test_cram_resched() throws Exception {
    // add card
    Collection col = getColV1();
    Note note = col.newNote();
    note.setItem("Front", "one");
    col.addNote(note);
    // cram deck
    long did = addDynamicDeck("Cram");
    Deck cram = col.getDecks().get(did);
    cram.put("resched", false);
    col.getDecks().save(cram);
    col.getSched().rebuildDyn(did);
    col.reset();
    // graduate should return it to new
    Card c = getCard();
    assertEquals(60, col.getSched().nextIvl(c, BUTTON_ONE));
    assertEquals(600, col.getSched().nextIvl(c, BUTTON_TWO));
    assertEquals(0, col.getSched().nextIvl(c, BUTTON_THREE));
    assertEquals("(end)", col.getSched().nextIvlStr(getTargetContext(), c, BUTTON_THREE));
    col.getSched().answerCard(c, BUTTON_THREE);
    assertEquals(CARD_TYPE_NEW, c.getType());
    assertEquals(QUEUE_TYPE_NEW, c.getQueue());
    // undue reviews should also be unaffected
    c.setIvl(100);
    c.setQueue(QUEUE_TYPE_REV);
    c.setType(CARD_TYPE_REV);
    c.setDue(col.getSched().getToday() + 25);
    c.setFactor(STARTING_FACTOR);
    c.flush();
    Card cardcopy = c.clone();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = getCard();
    assertEquals(600, col.getSched().nextIvl(c, BUTTON_ONE));
    assertEquals(0, col.getSched().nextIvl(c, BUTTON_TWO));
    assertEquals(0, col.getSched().nextIvl(c, BUTTON_THREE));
    col.getSched().answerCard(c, BUTTON_TWO);
    assertEquals(100, c.getIvl());
    assertEquals(col.getSched().getToday() + 25, c.getDue());
    // check failure too
    c = cardcopy;
    c.flush();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = getCard();
    col.getSched().answerCard(c, BUTTON_ONE);
    col.getSched().emptyDyn(did);
    c.load();
    assertEquals(100, c.getIvl());
    assertEquals(col.getSched().getToday() + 25, c.getDue());
    // fail+grad early
    c = cardcopy;
    c.flush();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = getCard();
    col.getSched().answerCard(c, BUTTON_ONE);
    col.getSched().answerCard(c, BUTTON_THREE);
    col.getSched().emptyDyn(did);
    c.load();
    assertEquals(100, c.getIvl());
    assertEquals(col.getSched().getToday() + 25, c.getDue());
    // due cards - pass
    c = cardcopy;
    c.setDue(-25);
    c.flush();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = getCard();
    col.getSched().answerCard(c, BUTTON_THREE);
    col.getSched().emptyDyn(did);
    c.load();
    assertEquals(100, c.getIvl());
    assertEquals(-25, c.getDue());
    // fail
    c = cardcopy;
    c.setDue(-25);
    c.flush();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = getCard();
    col.getSched().answerCard(c, BUTTON_ONE);
    col.getSched().emptyDyn(did);
    c.load();
    assertEquals(100, c.getIvl());
    assertEquals(-25, c.getDue());
    // fail with normal grad
    c = cardcopy;
    c.setDue(-25);
    c.flush();
    col.getSched().rebuildDyn(did);
    col.reset();
    c = getCard();
    col.getSched().answerCard(c, BUTTON_ONE);
    col.getSched().answerCard(c, BUTTON_THREE);
    c.load();
    assertEquals(100, c.getIvl());
    assertEquals(-25, c.getDue());
// lapsed card pulled into cram
// col.getSched()._cardConf(c)['lapse']['mult']=0.5
// col.getSched().answerCard(c, 1)
// col.getSched().rebuildDyn(did)
// col.reset()
// c = getCard()
// col.getSched().answerCard(c, 2)
// print c.__dict__
}
Also used : Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) Deck(com.ichi2.libanki.Deck) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Aggregations

Deck (com.ichi2.libanki.Deck)8 RobolectricTest (com.ichi2.anki.RobolectricTest)7 Test (org.junit.Test)7 Collection (com.ichi2.libanki.Collection)6 Nullable (androidx.annotation.Nullable)4 Card (com.ichi2.libanki.Card)4 Note (com.ichi2.libanki.Note)4 ArrayList (java.util.ArrayList)4 WebView (android.webkit.WebView)3 Config (org.robolectric.annotation.Config)3 NonNull (androidx.annotation.NonNull)2 DeckConfig (com.ichi2.libanki.DeckConfig)2 Model (com.ichi2.libanki.Model)2 JSONObject (com.ichi2.utils.JSONObject)2 HashMap (java.util.HashMap)2 Decks (com.ichi2.libanki.Decks)1