diff --git a/docs/DeveloperGuide.adoc b/docs/DeveloperGuide.adoc index d96724b6e2c..968f3281011 100644 --- a/docs/DeveloperGuide.adoc +++ b/docs/DeveloperGuide.adoc @@ -243,6 +243,70 @@ Step 3. The user executes `activity t/Lunch p/Alex p/David` command to create an ** Pros: Easy to implement. Low possibility of bugs. ** Cons: Significantly decreases usability of the application. +// tag::algorithm[] +=== Debt simplification algorithm +The algorithm is inspired by https://pure.tue.nl/ws/portalfiles/portal/2062204/623903.pdf[this paper]. + +We can gurantee the removal of all needless payments. +The amount of money each person has to hand is minimized. +We are unable to minimize the number of transactions made. +The paper gives an overview of that problem and why it is NP-complete (subset-sum). + +==== Operation details +The amounts each person owes to another is represented by a graph in an adjacency matrix. +The algorithm represents the payments to be made as a matrix. +There are some other data structures to facilitate its operation, but the code is generally well commented and they are not major player so we will skip them. +Also note that the matrices are necesarrily skew-symmetric: for example if A owes B $10, then B owes A $-10. + +To rephrase our gurantee in this context will be: we want to minimize weights. +We do not care about the number of edges. +Certainly we do not mean each person repeatedly pays out $1, $1, $1! +Our idea of "minimum weights" refer to the total amount someone has to handle. + +The lower bound for the amount someone has to handle is the balance. +We create a balance sheeet for the users which is expanded as people enter the activity. +Each expense added, the algorithm retrieves from it: +* who is involved, +* who paid, +* how much has been paid, +splits everything correctly, and updates all the data structures appropriately. + +Someone's balance is positive if he received more than he owes. +Then, a negative balance indicates them lending more than they received. +The algorithm simply finds any two people whose balances have opposing signs. +It is unimportant what is the magnitude of their balances (we do not need to take them in any order). +What then happens is then the person with the smallest magnitude of balance neutralizes his balance by paying or being paid by the other party. +The algorithm terminates when all balances are 0. + +==== Proof of optimality +This is a short proof of optimality since we want it to be called "algorithm", not "heuristic". + +In essence what we are constructing is a bipartite graph. +The algorithm never allows someone who owes to be paid, or someone who is owed to pay even more. +Hence we can classify all nodes into those with leaving edges (payers) and those with entering edges (payee). + +In a bipartite graph the amount each person handles is minimized. +To see why, we have to keep in mind that the algorithm always neutralizes one of the parties' balance. +That is to say, we will not be left with the case where someone who could pay off all his debts "overpaying". +In such a case, someone will then have to pay him back, which means it is no longer bipartite. + +==== Time and Space complexity +We take O(N^2) space and O(N) time. +Updating of the balance sheet and matrices by the expense command is performed in O(1) time. + +==== Design Considerations + +===== Aspect: Precision + +* **Alternative 1 (current choice):** Just use `double`. +** *Pros*: Easy, straightforward, good enough. +** *Cons*: Floating point precision might stack up. +** *Reason for choice*: For everyday purposes it is highly unlikely currencies (normally at most 2 decimal points) require any higher precision. This is for normal friends, not stockbrokers. + +* **Alternative 2:** Implement a `Rational` class for rational numbers. +** Pros: Guranteed precision. +** Cons: Seems overkill and needlessly over-engineered. + === List feature The List mechanism is facilitated by the combination of three classes `MainWindow`, `Model` and `Context`.