packages feed

exchangealgebra 0.4.1.1 → 0.4.1.2

raw patch · 5 files changed

+61/−11 lines, 5 files

Files

ChangeLog.md view
@@ -1,5 +1,19 @@ # Changelog for ExchangeAlgebra +## 0.4.1.2 - 2026-06-11++### Fixed+- `incomeSummaryAccount` (both `ExchangeAlgebra.Algebra.Transfer` and+  `ExchangeAlgebra.Journal.Transfer`) crashed with `Non-exhaustive patterns in+  case` on a **balanced ledger** (credit == debit, i.e. zero net income). In that+  case `diffRL` reports the wildcard `Side` constructor, which the+  `case dc of { Credit -> …; Debit -> … }` did not handle. The fix adds a `Side`+  branch that returns the input ledger unchanged (no `NetIncome` / `NetLoss`+  posting is appended when net income is zero). Note that appending a `Zero`+  posting is **not** a correct alternative for the Journal version, since it is+  not an identity there. Covered by the new `testIncomeSummaryBalancedAlg` and+  `testIncomeSummaryBalancedJournal` regression tests.+ ## 0.4.1.1 - 2026-06-07  ### Fixed
exchangealgebra.cabal view
@@ -1,13 +1,13 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.37.0.+-- This file has been generated from package.yaml by hpack version 0.39.1. -- -- see: https://github.com/sol/hpack ----- hash: fe5fab919197e65dce7b698dc174e0447987248ecd7a81108d260e187a1a248f+-- hash: d3a05562cbe70211374afd6c39a40fd7f8ff7e7b23b90f74716875f339171ea4  name:           exchangealgebra-version:        0.4.1.1+version:        0.4.1.2 synopsis:       Exchange Algebra for bookkeeping and economic simulation description:    Please see the README on GitHub at <https://github.com/yakagika/ExchangeAlgebra#readme> category:       Accounting, Finance, Math
src/ExchangeAlgebra/Algebra/Transfer.hs view
@@ -535,12 +535,14 @@ -- * Closing transfer entries  -- | Income Summary Account: compute net income for the current period.+-- When the ledger is balanced (credit == debit, net income is zero), @diffRL@+-- reports the wildcard 'Side'; in that case the input is returned unchanged. incomeSummaryAccount :: (HatVal n, ExBaseClass b) => Alg n b -> Alg n b incomeSummaryAccount alg =  let (dc,diff) = diffRL alg-                         in let x = case dc of-                                        Credit -> diff :@ (toNot wiledcard) .~ NetIncome-                                        Debit  -> diff :@ (toNot wiledcard) .~ NetLoss-                         in alg .+  x+                         in case dc of+                                Credit -> alg .+ (diff :@ (toNot wiledcard) .~ NetIncome)+                                Debit  -> alg .+ (diff :@ (toNot wiledcard) .~ NetLoss)+                                Side   -> alg  -- | Net income transfer. Transfers NetIncome/NetLoss to RetainedEarnings. --
src/ExchangeAlgebra/Journal/Transfer.hs view
@@ -97,14 +97,16 @@  -- | Compute net income for the current period (Income Summary Account). -- Calculate the debit-credit difference and add it as NetIncome or NetLoss to the plank Note.+-- When the ledger is balanced (credit == debit, net income is zero), @diffRL@ reports the+-- wildcard 'Side'; in that case the journal is returned unchanged. -- -- Complexity: O(s) (s = total number of scalar entries) incomeSummaryAccount :: (Note n, HatVal v, ExBaseClass b) => Journal n v b -> Journal n v b incomeSummaryAccount js =  let (dc,diff) = diffRL js-                         in let x = case dc of-                                        Credit  -> diff :@ (toNot wiledcard) .~ NetIncome-                                        Debit -> diff :@ (toNot wiledcard) .~ NetLoss-                         in js .+  ( x .| plank)+                         in case dc of+                                Credit -> js .+ ((diff :@ (toNot wiledcard) .~ NetIncome) .| plank)+                                Debit  -> js .+ ((diff :@ (toNot wiledcard) .~ NetLoss)   .| plank)+                                Side   -> js  -- | Net income transfer (Journal version). Transfer NetIncome/NetLoss to RetainedEarnings for each Note. --
test/Spec.hs view
@@ -381,6 +381,36 @@         actual = EJT.finalStockTransfer transferJournalSample     assertEqual "Journal.finalStockTransfer matches composed transfer" (EJ.toMap ref) (EJ.toMap actual) +-- A ledger whose Debit and Credit sides are equal (net income is zero).+-- @diffRL@ reports the wildcard 'Side' here, which used to crash+-- @incomeSummaryAccount@ with "Non-exhaustive patterns" (regression for 0.4.1.2).+balancedTransferAlg :: TransferAlg+balancedTransferAlg = EA.fromList+    [ 5 :@ Not :<(Cash,  1, 1, Yen)   -- Assets  -> Debit  side+    , 5 :@ Not :<(Sales, 2, 1, Yen)   -- Revenue -> Credit side+    ]++balancedTransferJournal :: TransferJournal+balancedTransferJournal = balancedTransferAlg .| "balanced"++-- | Regression: a balanced ledger (credit == debit) must not crash+-- @incomeSummaryAccount@; it returns the input unchanged.+testIncomeSummaryBalancedAlg :: IO ()+testIncomeSummaryBalancedAlg = do+    let actual = EAT.incomeSummaryAccount balancedTransferAlg+    assertEqual+        "Algebra.incomeSummaryAccount on balanced ledger returns input unchanged"+        (EA.toList balancedTransferAlg)+        (EA.toList actual)++testIncomeSummaryBalancedJournal :: IO ()+testIncomeSummaryBalancedJournal = do+    let actual = EJT.incomeSummaryAccount balancedTransferJournal+    assertEqual+        "Journal.incomeSummaryAccount on balanced ledger returns input unchanged"+        (EJ.toMap balancedTransferJournal)+        (EJ.toMap actual)+ type SpillRestoreJournal = EJ.Journal (String, Int) Double (HatBase CountUnit)  testRestoreJournalFromBinarySpill :: IO ()@@ -802,6 +832,8 @@     testFilterByAxisWithDeltaUpdates     testFinalStockTransferAlgEquivalence     testFinalStockTransferJournalEquivalence+    testIncomeSummaryBalancedAlg+    testIncomeSummaryBalancedJournal     testRestoreJournalFromBinarySpill     testSimulateEx1Default     testCsvTranspose