summaryrefslogtreecommitdiff
path: root/contrib/non-profit-audit-reports
diff options
context:
space:
mode:
authorBradley M. Kuhn <bkuhn@ebb.org>2013-01-09 15:20:50 -0500
committerBradley M. Kuhn <bkuhn@ebb.org>2013-02-18 14:08:45 -0500
commit0530b729e2b38931f653e226bc3c1cfc47d55d24 (patch)
tree187898203fa758e0378d6e93ea7888c66753a391 /contrib/non-profit-audit-reports
parentd13ab6a4026cfeec18fdd989862aecbe83caa20f (diff)
downloadfork-ledger-0530b729e2b38931f653e226bc3c1cfc47d55d24.tar.gz
fork-ledger-0530b729e2b38931f653e226bc3c1cfc47d55d24.tar.bz2
fork-ledger-0530b729e2b38931f653e226bc3c1cfc47d55d24.zip
Default to brute-force subset sum solution.
The dynamic programming version of the subset sum problem required far too much RAM for larger bank balances. Meanwhile, the brute-force is not to bad now that the loop tries the closer dates *first*.
Diffstat (limited to 'contrib/non-profit-audit-reports')
-rwxr-xr-xcontrib/non-profit-audit-reports/bank-reconcilation.plx52
1 files changed, 44 insertions, 8 deletions
diff --git a/contrib/non-profit-audit-reports/bank-reconcilation.plx b/contrib/non-profit-audit-reports/bank-reconcilation.plx
index 669a25b0..18d74067 100755
--- a/contrib/non-profit-audit-reports/bank-reconcilation.plx
+++ b/contrib/non-profit-audit-reports/bank-reconcilation.plx
@@ -5,6 +5,7 @@ use warnings;
use Math::BigFloat;
use Date::Manip;
+use Data::PowerSet;
Math::BigFloat->precision(-2);
my $ZERO = Math::BigFloat->new("0.00");
@@ -16,6 +17,30 @@ my $DEBUG = 0;
my $LEDGER_BIN = "/usr/local/bin/ledger";
######################################################################
+sub BruteForceSubSetSumSolver ($$$) {
+ my($numberList, $totalSought, $extractNumber) = @_;
+
+ my($P, $N) = (0, 0);
+ my $size = scalar(@{$numberList});
+ my %Q;
+ my(@L) =
+ map { { val => &$extractNumber($_), obj => $_ } } @{$numberList};
+
+ my $powerset = Data::PowerSet->new(@L);
+
+ while (my $set = $powerset->next) {
+ my $total = $ZERO;
+ foreach my $ee (@{$set}) {
+ $total += $ee->{val};
+ }
+ if ($totalSought == $total) {
+ my(@list) = map { $_->{obj} } @{$set};
+ return (1, \@list);
+ }
+ }
+ return (0, []);
+}
+######################################################################
sub DynamicProgrammingSubSetSumSolver ($$$) {
my($numberList, $totalSought, $extractNumber) = @_;
@@ -88,7 +113,7 @@ sub ParseNumber($) {
return Math::BigFloat->new($_[0]);
}
if (@ARGV < 4) {
- print STDERR "usage: $0 <ACCOUNT_REGEX> <END_DATE> <BANK_STATEMENT_BALANCE> <LEDGER_OPTIONS>\n";
+ print STDERR "usage: $0 [-d] <ACCOUNT_REGEX> <END_DATE> <BANK_STATEMENT_BALANCE> <LEDGER_OPTIONS>\n";
exit 1;
}
######################################################################
@@ -100,8 +125,18 @@ sub ConvertTwoDigitPrecisionToIntegerInEntry ($) {
return ConvertTwoDigitPrecisionToInteger($_[0]->{amount});
}
######################################################################
+my $firstArg = shift @ARGV;
+
+my $solver = \&BruteForceSubSetSumSolver;
+
+if ($firstArg eq '-d') {
+ $solver = \&DynamicProgrammingSubSetSumSolver;
+} else {
+ unshift(@ARGV, $firstArg);
+}
my($account, $endDate, $balanceSought, @mainLedgerOptions) = @ARGV;
+
$balanceSought = ParseNumber($balanceSought);
my $err;
@@ -139,7 +174,8 @@ while ($startDate ge $earliestStartDate) {
unless $amount =~ s/\s*\$\s*([\-\d\.\,]+)\s*$/$1/;
$amount = ParseNumber($amount);
- push(@entries, { date => $date, checkNum => $checkNum, amount => $amount });
+ push(@entries, { date => $date, checkNum => $checkNum,
+ payee => $payee, amount => $amount });
}
close FILE;
die "unable to properly run ledger command: @fullCommand: $!" unless ($? == 0);
@@ -148,21 +184,21 @@ while ($startDate ge $earliestStartDate) {
if (@entries == 1) {
@solution = ( (abs($entries[0]->{amount}) == abs($balanceSought)), \@entries);
} else {
- @solution = DynamicProgrammingSubSetSumSolver(\@entries, ConvertTwoDigitPrecisionToInteger($balanceSought),
- \&ConvertTwoDigitPrecisionToIntegerInEntry);
+ @solution = $solver->(\@entries,
+ ConvertTwoDigitPrecisionToInteger($balanceSought),
+ \&ConvertTwoDigitPrecisionToIntegerInEntry);
}
if ($VERBOSE) {
use Data::Dumper;
print STDERR "Solution for $formattedStartDate, $balanceSought: \n", Data::Dumper->Dump(\@solution);
}
- print STDERR "Solution Found: Dying" if ($solution[0]) and $VERBOSE;
-# last if ($solution[0]);
+ last if ($solution[0]);
}
-print "DONE LOOP: $startDate $earliestStartDate\n";
if ($solution[0]) {
print "FINAL SOLUTION: ";
foreach my $ee (@{$solution[1]}) {
- print "$ee->date, $ee->payee, $ee->amount\n";
+ print Data::Dumper->Dump($solution[1]);
+ print "$ee->{date}, $ee->{payee}, $ee->{amount}\n";
}
}
###############################################################################