use of com.ichi2.utils.Computation 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.utils.Computation in project Anki-Android by ankidroid.
the class AbstractFlashcardViewer method undo.
protected void undo() {
if (isUndoAvailable()) {
Resources res = getResources();
String undoName = getCol().undoName(res);
new UndoService.Undo().runWithHandler(answerCardHandler(false).alsoExecuteAfter(computation -> UIUtils.showThemedToast(AbstractFlashcardViewer.this, res.getString(R.string.undo_succeeded, undoName), false)));
}
}
use of com.ichi2.utils.Computation 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;
}
use of com.ichi2.utils.Computation in project AnkiChinaAndroid by ankichinateam.
the class SchedV2 method _deckRevLimitSingle.
/**
* Maximal number of rev card still to see today in deck d. It's computed as:
* the number of rev card to see by day according to the deck optinos
* minus the number of rev cards seen today in deck d or a descendant
* plus the number of extra cards to see today in deck d, a parent or a descendant.
*
* Respects the limits of its ancestor, either given as parentLimit, or through direct computation.
*/
private int _deckRevLimitSingle(@Nullable Deck d, Integer parentLimit) {
// invalid deck selected?
if (d == null) {
return 0;
}
if (d.getInt("dyn") != 0) {
return mDynReportLimit;
}
long did = d.getLong("id");
@NonNull DeckConfig c = mCol.getDecks().confForDid(did);
int lim = Math.max(0, c.getJSONObject("rev").getInt("perDay") - d.getJSONArray("revToday").getInt(1));
// So currentCard does not have to be taken into consideration in this method
if (currentCardIsInQueueWithDeck(Consts.QUEUE_TYPE_REV, did)) {
lim--;
}
if (parentLimit != null) {
return Math.min(parentLimit, lim);
} else if (!d.getString("name").contains("::")) {
return lim;
} else {
for (@NonNull Deck parent : mCol.getDecks().parents(did)) {
// pass in dummy parentLimit so we don't do parent lookup again
lim = Math.min(lim, _deckRevLimitSingle(parent, lim));
}
return lim;
}
}
use of com.ichi2.utils.Computation in project Anki-Android by ankidroid.
the class SchedV2 method _deckRevLimitSingle.
/**
* Maximal number of rev card still to see today in deck d. It's computed as:
* the number of rev card to see by day according to the deck optinos
* minus the number of rev cards seen today in deck d or a descendant
* plus the number of extra cards to see today in deck d, a parent or a descendant.
*
* Respects the limits of its ancestor, either given as parentLimit, or through direct computation.
* @param parentLimit Limit of the parent, this is an upper bound on the limit of this deck
* @param considerCurrentCard whether the current card should be taken from the limit (if it belongs to this deck)
*/
private int _deckRevLimitSingle(@Nullable Deck d, Integer parentLimit, boolean considerCurrentCard) {
// invalid deck selected?
if (d == null) {
return 0;
}
if (d.isDyn()) {
return mDynReportLimit;
}
long did = d.getLong("id");
@NonNull DeckConfig c = mCol.getDecks().confForDid(did);
int lim = Math.max(0, c.getJSONObject("rev").getInt("perDay") - d.getJSONArray("revToday").getInt(1));
// So currentCard does not have to be taken into consideration in this method
if (considerCurrentCard && currentCardIsInQueueWithDeck(Consts.QUEUE_TYPE_REV, did)) {
lim--;
}
return lim;
}
Aggregations