[balsheet-pnl] speed up by pre-generating account report-date splits

previous code was very inefficient: if an account had N old splits and
balance-sheet reported on M recent dates, it would scan splitlist
multiple times: (1) to retrieve splits, (2) filter until
column-date, (3) find the last one. i.e. total O(N * M * 3).

this algorithm pre-generates the account's report-date splits by
scanning each account only once, creating M splits which are queried
by get-cell-anchor-fn via list-ref. i.e. O(N)

it is immedialtely converted to a vector because we want O(1)
access. from get-cell-anchor-fn

a future optimisation may scan the accounts' splitlists once per
report run, acquiring all required data (i.e. last period split,
split->balance, closing entries) in 1 pass, to generate a column-data
record.
This commit is contained in:
Christopher Lam 2019-11-21 09:57:51 +08:00
parent dda3da8416
commit b3493509d1

View File

@ -30,6 +30,7 @@
(use-modules (gnucash gnc-module))
(use-modules (gnucash gettext))
(use-modules (srfi srfi-1))
(use-modules (srfi srfi-2))
(gnc:module-load "gnucash/report/report-system" 0)
@ -901,19 +902,25 @@ also show overall period profit & loss."))
((eq? report-type 'balsheet)
(let* ((get-cell-monetary-fn
(lambda (account col-idx)
(let ((account-balance-list (assoc account accounts-balances)))
(let ((account-balance-list (assoc-ref accounts-balances account)))
(and account-balance-list
(list-ref account-balance-list (1+ col-idx))))))
(list-ref account-balance-list col-idx)))))
;; an alist of account->last-split at date boundary
(accounts-splits-dates
(map
(lambda (acc)
(cons acc (list->vector
(gnc:account-accumulate-at-dates
acc report-dates #:split->elt identity))))
accounts))
(get-cell-anchor-fn
(lambda (account col-idx)
(and (not (pair? account))
(let* ((splits (xaccAccountGetSplitList account))
(split-date (compose xaccTransGetDate xaccSplitGetParent))
(date (list-ref report-dates col-idx))
(valid-split? (lambda (s) (< (split-date s) date)))
(valid-splits (filter valid-split? splits)))
(and (pair? valid-splits)
(gnc:split-anchor-text (last valid-splits)))))))
(and-let* (((not (pair? account)))
(date-splits (assoc-ref accounts-splits-dates account))
(split (vector-ref date-splits col-idx)))
(gnc:split-anchor-text split))))
(asset-liability-balances
(let ((asset-liab-balances