prune and update balance report docs

This commit is contained in:
Simon Michael 2009-03-15 11:11:27 +00:00
parent aaf8a0caf6
commit 7fba880fef

View File

@ -2,14 +2,9 @@
A ledger-compatible @balance@ command.
ledger's balance command is easy to use but hard to describe precisely.
Here are some attempts.
I. high level description with examples
---------------------------------------
We'll use sample.ledger, which has the following account tree:
ledger's balance command is easy to use but not easy to describe
precisely. In the examples below we'll use sample.ledger, which has the
following account tree:
@
assets
@ -28,8 +23,9 @@ We'll use sample.ledger, which has the following account tree:
@
The balance command shows accounts with their aggregate balances.
Subaccounts are displayed with more indentation. Each balance is the sum
of any transactions in that account plus any balances from subaccounts:
Subaccounts are displayed indented below their parent. Each balance is the
sum of any transactions in that account plus any balances from
subaccounts:
@
$ hledger -f sample.ledger balance
@ -45,15 +41,25 @@ of any transactions in that account plus any balances from subaccounts:
$1 liabilities:debts
@
Usually, the non-interesting accounts are elided or omitted. To be
precise, an interesting account is one with: a non-zero balance, or a
balance different from its single subaccount, or two or more interesting
subaccounts. (More subtleties to be filled in here.)
Usually, the non-interesting accounts are elided or omitted. Above,
@checking@ is omitted because it has no subaccounts and a zero balance.
@bank@ is elided because it has only a single displayed subaccount
(@saving@) and it would be showing the same balance as that ($1). Ditto
for @liabilities@. We will return to this in a moment.
So, above, @checking@ is omitted because it has no interesting subaccounts
and a zero balance. @bank@ is elided because it has only a single
interesting subaccount (saving) and it would be showing the same balance
($1). Ditto for @liabilities@.
The --depth argument can be used to limit the depth of the balance report.
So, to see just the top level accounts:
@
$ hledger -f sample.ledger balance --depth 1
$-1 assets
$2 expenses
$-2 income
$1 liabilities
@
This time liabilities has no displayed subaccounts (due to --depth) and
is not elided.
With one or more account pattern arguments, the balance command shows
accounts whose name matches one of the patterns, plus their parents
@ -76,237 +82,15 @@ Also, the balance report shows the total of all displayed accounts, when
that is non-zero. Here, it is displayed because the accounts shown add up
to $-1.
Here is a more precise definition of \"interesting\" accounts in ledger's
balance report:
II. Some notes for the implementation
-------------------------------------
- a simple balance report shows top-level accounts
- with an account pattern, it shows accounts whose leafname matches, plus their parents
- with the subtotal option, it also shows all subaccounts of the above
- zero-balance leaf accounts are removed
- the resulting account tree is displayed with each account's aggregated
balance, with boring parents prefixed to the next line
- a boring parent has the same balance as its child and is not explicitly
matched by the display options.
- the sum of the balances shown is displayed at the end, if it is non-zero
III. John's description 2009/02
-------------------------------
johnw: \"Since you've been re-implementing the balance report in Haskell, I thought
I'd share with you in pseudocode how I rewrote it for Ledger 3.0, since
the old method never stopped with the bugs. The new scheme uses a 5 stage
algorithm, with each stage gathering information for the next:
STEP 1
Based on the user's query, walk through all the transactions in their
journal, finding which ones to include in the account subtotals. For each
transaction that matches, mark the account as VISITED.
STEP 2
Recursively walk the accounts tree, depth-first, computing aggregate
totals and aggregate \"counts\" (number of transactions contributing to the
aggregate total).
STEP 3
Walk the account tree again, breadth-first, and for every VISITED account,
check whether it matches the user's \"display predicate\". If so, mark the
account as MATCHING.
STEP 4
Do an in-order traversal of the account tree. Except for the top-most
account (which serves strictly as a container for the other accounts):
a. If the account was MATCHING, or two or more of its children are
MATCHING or had descendents who were MATCHING, display the account.
b. Otherwise, if the account had *any* children or descendants who
were VISITED and *no* children or descendants who were MATCHING,
then apply the display predicate from STEP 3 to the account. If
it matches, also print this account. (This step allows -E to
report empty accounts which otherwise did match the original
query).
STEP 5
When printing an account, display a \"depth spacer\" followed by the \"partial name\".
tal
The partial name is found by taking the base account's name, then
prepending to it every non-MATCHING parent until a MATCHING parent is
found.
The depth spacer is found by outputting two spaces for every MATCHING parent.
This way, \"Assets:Bank:Checking\" might be reported as:
Assets
Bank
Checking
or
Assets
Bank:Checking
or
Assets:Bank:Checking
Depending on whether the parents were or were not reported for their own reasons.
\"
\"I just had to add one more set of tree traversals, to correctly determine
whether a final balance should be displayed
without --flat, sort at each level in the hierarchy
with --flat, sort across all accounts\"
IV. A functional description
-----------------------------
1. filter the transactions, keeping only those included in the calculation.
Remember the subset of accounts involved. (VISITED)
2. generate a full account & balance tree from all transactions
3. Remember the subset of VISITED accounts which are matched for display.
(MATCHING)
4. walk through the account tree:
a. If the account is in MATCHING, or two or more of its children are or
have descendants who are, display it.
b. Otherwise, if the account has any children or descendants in VISITED
but none in MATCHING, and it is matched for display, display it.
(allows -E to report empty accounts which otherwise did match the
original query).
5. when printing an account, display a \"depth spacer\" followed by the
\"partial name\". The partial name is found by taking the base account's
name, then prepending to it every non-MATCHING parent until a MATCHING
parent is found. The depth spacer is two spaces per MATCHING parent.
6. I just had to add one more set of tree traversals, to correctly
determine whether a final balance should be displayed
7. without --flat, sort at each level in the hierarchy
with --flat, sort across all accounts
V. Another functional description with new terminology
------------------------------------------------------
- included transactions are those included in the calculation, specified
by -b, -e, -p, -C, -R, account patterns and description patterns.
- included accounts are the accounts referenced by included transactions.
- matched transactions are the included transactions which match the
display predicate, specified by -d.
- matched accounts are the included accounts which match the display
predicate, specified by -d, --depth, -E, -s
- an account name tree is the full hierarchy of account names implied by a
set of transactions
- an account tree is an account name tree augmented with the aggregate
balances and transaction counts for each named account
- the included account tree is the account tree for the included transactions
- a matched account tree contains one or more matched accounts
- to generate the balance report, walk through the included account tree
and display each account if
- it is matching
- or it has two more more matching subtrees
- or it has included offspring but no matching offspring
- to display an account, display an indent then the \"partial name\". The
partial name is the account's name, prefixed by each unmatched parent
until a matched parent is found. The indent is two spaces per matched
parent.
VI. John's description 2009/03/11
---------------------------------
johnw: \"Well, I had to rewrite the balance reporting code yet again,
because it wouldn't work with --depth correctly. Here's the new algorithm.
STEP 1: Walk all postings, looking for those that match the user's query.
As a match is found, mark its account VISITED.
STEP 2: Do a traversal of all accounts, sorting as need be, and collect
them all into an ordered list.
STEP 3: Keeping that list on the side, do a *depth-first* traversal of
the account tree.
visited = 0
to_display = 0
(visited, to_display) += <recurse for all immediate children>
if account is VISITED or (no --flat and visited > 0):
if account matches display predicate and
(--flat or to_display != 1):
mark account as TO_DISPLAY
to_display = 1
visited = 1
return (visited, to_display)
STEP 4: top_displayed = 0
for every account in the ordered list:
if account has been marked TO_DISPLAY:
mark account as DISPLAYED
format the account and print
if --flat and account is DISPLAYED:
top_displayed += 1
if no --flat:
for every top-most account:
if account is DISPLAYED or any children or DISPLAYED:
top_displayed += 1
if no --no-total and top_displayed > 1 and
top-most accounts sum to a non-zero balance:
output separator
output balance sum account as DISPLAYED
format the account and print
if --flat and account is DISPLAYED:
top_displayed += 1
if no --flat:
for every top-most account:
if account is DISPLAYED or any children or DISPLAYED:
top_displayed += 1
if no --no-total and top_displayed > 1 and
top-most accounts sum to a non-zero balance:
output separator
output balance sum
\"
- an account which has just one interesting subaccount branch, and which
is not at the report's maximum depth, is interesting if the balance is
different from the subaccount's, and otherwise boring.
- any other account is interesting if it has a non-zero balance, or the -E
flag is used.
-}