gnucash maint: [balsheet-pnl] unrealized-gain calculator is now much faster.
Christopher Lam
clam at code.gnucash.org
Tue Nov 26 09:03:27 EST 2019
Updated via https://github.com/Gnucash/gnucash/commit/1af8e272 (commit)
from https://github.com/Gnucash/gnucash/commit/ff298b36 (commit)
commit 1af8e272c7603cd08bad11a2f9374e234710783c
Author: Christopher Lam <christopher.lck at gmail.com>
Date: Tue Nov 26 21:33:33 2019 +0800
[balsheet-pnl] unrealized-gain calculator is now much faster.
Previous code would call gnc:account-get-comm-value-at-date for each
report-date; this function generates qof-query, retrieves account
splits, scans them to accumulate split->transaction->currency and
split->value into a commodity collector.
This commit will hook into the existing gnc:account-accumulate
function, accumulating the same split->transaction->currency and
split->value into a collector.
Note we must make a copy of the accumulator at each report-date
via (gnc:collector+ val-coll) otherwise the same val-coll will be
mutated through subsequent splits.
For a multicolumn balsheet, for every account with N old splits, and
reporting on M report dates, it would run in O(N*M) time. This
algorithm will hook into existing accumulator, i.e. I think O(1).
The majority speed-up however comes from avoiding M qof-queries per
report.
diff --git a/gnucash/report/standard-reports/balsheet-pnl.scm b/gnucash/report/standard-reports/balsheet-pnl.scm
index de0d44e49..d8a48d471 100644
--- a/gnucash/report/standard-reports/balsheet-pnl.scm
+++ b/gnucash/report/standard-reports/balsheet-pnl.scm
@@ -38,10 +38,11 @@
;; the column-data record. the gnc:account-accumulate-at-dates will
;; create a record for each report-date with split-data as follows:
(define-record-type :col-datum
- (make-datum last-split split-balance)
+ (make-datum last-split split-balance split-value-balance)
col-datum?
(last-split col-datum-get-last-split)
- (split-balance col-datum-get-split-balance))
+ (split-balance col-datum-get-split-balance)
+ (split-value-balance col-datum-get-split-value-balance))
(define FOOTER-TEXT
(gnc:make-html-text
@@ -785,14 +786,20 @@ also show overall period profit & loss."))
(map
(lambda (acc)
(let* ((comm (xaccAccountGetCommodity acc))
+ (val-coll (gnc:make-commodity-collector))
(amt->monetary (lambda (amt) (gnc:make-gnc-monetary comm amt))))
(cons acc
(gnc:account-accumulate-at-dates
acc report-dates
- #:nosplit->elt (make-datum #f (amt->monetary 0))
+ #:nosplit->elt (make-datum #f (amt->monetary 0)
+ (gnc:make-commodity-collector))
#:split->elt
(lambda (s)
- (make-datum s (amt->monetary (xaccSplitGetBalance s))))))))
+ (val-coll 'add
+ (xaccTransGetCurrency (xaccSplitGetParent s))
+ (xaccSplitGetValue s))
+ (make-datum s (amt->monetary (xaccSplitGetBalance s))
+ (gnc:collector+ val-coll)))))))
accounts))
;; an alist of (cons account account-balances) whereby
@@ -945,6 +952,8 @@ also show overall period profit & loss."))
(split (vector-ref date-splits col-idx)))
(gnc:split-anchor-text split))))
+ ;; a list of collectors whereby collector is the sum of
+ ;; asset and liabilities at report dates
(asset-liability-balances
(let ((asset-liab-balances
(map cdr (filter
@@ -955,6 +964,8 @@ also show overall period profit & loss."))
(map (const (gnc:make-commodity-collector)) report-dates)
(apply map gnc:monetaries-add asset-liab-balances))))
+ ;; a list of collectors whereby collector is the sum of
+ ;; incomes and expenses at report dates
(income-expense-balances
(let ((inc-exp-balances
(map cdr
@@ -967,6 +978,30 @@ also show overall period profit & loss."))
(map gnc:commodity-collector-get-negated
(apply map gnc:monetaries-add inc-exp-balances)))))
+ ;; an (cons account list-of-collectors) whereby each
+ ;; collector is the split-value-balances at report
+ ;; dates. split-value-balance determined by transaction currency.
+ (accounts-value-balances
+ (map
+ (lambda (acc)
+ (cons acc (let ((cols-data (assoc-ref accounts-cols-data acc)))
+ (map col-datum-get-split-value-balance cols-data))))
+ accounts))
+
+ ;; a list of collectors whereby each collector is the sum
+ ;; of asset and liability split-value-balances at report
+ ;; dates
+ (asset-liability-value-balances
+ (let ((asset-liab-value-balances
+ (map cdr (filter
+ (lambda (acc-balances)
+ (member (car acc-balances) asset-liability))
+ accounts-value-balances))))
+ (if (null? asset-liab-value-balances)
+ (map (const (gnc:make-commodity-collector)) report-dates)
+ (apply map gnc:collector+ asset-liab-value-balances))))
+
+ ;; converts monetaries to common currency
(monetaries->exchanged
(lambda (monetaries target-currency price-source date)
(let ((exchange-fn (gnc:case-exchange-fn
@@ -978,6 +1013,10 @@ also show overall period profit & loss."))
(exchange-fn mon target-currency))
(monetaries 'format gnc:make-gnc-monetary #f)))))))
+ ;; the unrealized gain calculator retrieves the
+ ;; asset-and-liability report-date balance and
+ ;; value-balance, and calculates the difference,
+ ;; converted to report currency.
(unrealized-gain-fn
(lambda (col-idx)
(and common-currency
@@ -987,14 +1026,15 @@ also show overall period profit & loss."))
(asset-liability-balance
(list-ref asset-liability-balances col-idx))
(asset-liability-basis
- (gnc:accounts-get-comm-total-assets
- asset-liability
- (lambda (acc)
- (gnc:account-get-comm-value-at-date acc date #f))))
+ (list-ref asset-liability-value-balances col-idx))
(unrealized (gnc:collector- asset-liability-basis
asset-liability-balance)))
(monetaries->exchanged
unrealized common-currency price-source date)))))
+
+ ;; the retained earnings calculator retrieves the
+ ;; income-and-expense report-date balance, and converts
+ ;; to report currency.
(retained-earnings-fn
(lambda (col-idx)
(let* ((date (case price-source
Summary of changes:
gnucash/report/standard-reports/balsheet-pnl.scm | 56 ++++++++++++++++++++----
1 file changed, 48 insertions(+), 8 deletions(-)
More information about the gnucash-changes
mailing list