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