chiark / gitweb /
New Summary section
authorIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sun, 27 Dec 2009 19:06:59 +0000 (19:06 +0000)
committerIan Jackson <ian@liberator.relativity.greenend.org.uk>
Sun, 27 Dec 2009 19:06:59 +0000 (19:06 +0000)
yarrg/CommodsWeb.pm
yarrg/web/routetrade

index 5e12003..9a60836 100644 (file)
@@ -52,7 +52,7 @@ BEGIN {
                      &to_json_shim &to_json_protecttags
                      &set_ctype_utf8 &webdatadir
                      &expected_error &dbw_lookup_string
-                     &printable &tr_datarow &escerrq
+                     &printable &tr_datarow &tr_datarow_s &escerrq
                      &prettyprint_age &meta_prettyprint_age);
     %EXPORT_TAGS = ( );
 
@@ -210,18 +210,23 @@ sub printable ($) { # printable($m)  where $m is the Mason request object
     return 0;
 }
 
-sub tr_datarow ($$) {
+sub tr_datarow_s ($$) {
     my ($m, $lineno) = @_;
     $lineno &= 1;
     if (!printable($m)) {
-       $m->print("<tr class=\"datarow$lineno\">");
+       return "<tr class=\"datarow$lineno\">";
     } else {
-       $m->print("<tr bgcolor=\"".
-                 ($lineno ? "#ffffff" : "#e3e3e3" ).
-                 "\">");
+       return "<tr bgcolor=\"".
+              ($lineno ? "#ffffff" : "#e3e3e3" ).
+              "\">";
     }
 }
 
+sub tr_datarow ($$) {
+    my ($m, $lineno) = @_;
+    $m->print(tr_datarow_s($m, $lineno));
+}
+
 sub escerrq ($) {
     return '"'.CGI::escapeHTML($_[0]).'"';
     # Prettier qotes as below are not in HTML 3.2:
index b2bbf2e..8d8b48b 100644 (file)
@@ -419,6 +419,7 @@ foreach my $f (@flows) {
 </%perl>
 
 % my $optimise= 1;
+% my $opt_how;
 
 % if (!$specific) {
 %      $optimise= 0;
@@ -505,7 +506,7 @@ foreach my $ci (0..($#islandids-1)) {
        }
 #print " RELEVANT $ci COUNT ".scalar(@rel_subflows)."  ";
        if (!@rel_subflows) {
-               foreach my $mv (qw(mass volume)) {
+               foreach my $mv (qw(mass volume capital)) {
                        $sail_total[$ci]{$mv}= 0;
                }
                next;
@@ -581,7 +582,7 @@ if ($qa->{'debug'}) {
 }
 
 my $try_solve= sub {
-       my (@opts) = @_;
+       my ($how, @opts) = @_;
        my $input= pipethrough_prep();
        print $input $cplex or die $!;
        my $output= pipethrough_run_along($input, undef, 'glpsol',
@@ -645,7 +646,7 @@ my $try_solve= sub {
                        $sf->{OptQty}= $qty;
                        $sf->{OptProfit}= $qty * $flow->{'unitprofit'};
                        $sf->{OptCapital}= $qty * $flow->{'org_price'};
-               } elsif ($varname =~ m/^(mass|volume)_(\d+)$/) {
+               } elsif ($varname =~ m/^(mass|volume|capital)_(\d+)$/) {
                        my ($mv,$ix) = ($1,$2);
                        $sail_total[$ix]{$mv}= $qty;
                }
@@ -655,11 +656,16 @@ my $try_solve= sub {
        pipethrough_run_finish($output,$prerr);
        map { defined $_->{OptQty} or die "$prerr $_->{Flow}{Ix}" } @subflows;
        defined $expected_total_profit or die "$prerr ?";
-       return $somemip || !$timelimit;
+       return 0 unless $somemip || !$timelimit;
+       $opt_how= $how;
+       return 1;
 };
 
-unless ($try_solve->(qw( --intopt --cuts --bfs )) or
-       $try_solve->(qw( --nomip ))) {
+unless ($try_solve->('Optimisation successful',
+                    qw( --intopt --cuts --bfs )) or
+       $try_solve->('<strong>Complex problem, downgraded</strong>'.
+                    ' to rounded-down LP.',
+                    qw( --nomip ))) {
 </%perl>
 <h2>Optimisation failed</h2>
 The linear/mixed-integer optimisation failed.
@@ -694,9 +700,9 @@ $addcols->({ Total => 0, DoReverse => 1, TotalSubflows => 1 }, qw(
 <h2>Contents</h2>
 <ul>
 % if ($optimise) {
+ <li><a href="#summary">Summary</a>
  <li><a href="#plan">Voyage trading plan</a>
   <ul>
-   <li><a href="#summary">Summary statistics</a>
    <li>Printable:
          <input type=submit name=printable_pdf value="PDF">
          <input type=submit name=printable_html value="HTML">
@@ -705,7 +711,7 @@ $addcols->({ Total => 0, DoReverse => 1, TotalSubflows => 1 }, qw(
          <input type=submit name=printable_ps2 value="PostScript 2-up">
   </ul>
 % }
- <li><a href="#dataage">Data age summary</a>
+ <li><a href="#dataage">Relevant data ages</a>
  <li><a href="#trades">Relevant trades</a>
 </ul>
 % } else {
@@ -718,51 +724,57 @@ Generated by YARRG at <strong><%
 % }
 
 % if ($optimise) { # ========== TRADING PLAN ==========
-%
-% my $iquery= $dbh->prepare('SELECT islandname FROM islands
-%                              WHERE islandid = ?');
-% my %da_ages;
-% my $total_total= 0;
-% my $total_dist= 0;
-%
-<h2><a name="plan">Voyage trading plan</a></h2>
+<%perl>
+my $iquery= $dbh->prepare('SELECT islandname FROM islands
+                               WHERE islandid = ?');
+my %da_ages;
+my $total_total= 0;
+my $total_dist= 0;
+my @oldest= (-1, 'nowhere');
+my $plan_html= '';
+
+my $plan_table_info= printable($m) ? 'width=100%' : '';
+$plan_html .= <<END;
+<table class="data" rules=groups $plan_table_info >
+END
 
-<table class="data" rules=groups <% printable($m) ? 'width=100%' : '' %> >
-% my $tbody= sub {
-%      if (!printable($m)) { return '<tbody>'; }
-%#  return "<tr><td colspan=7><hr>";
-%      my ($c)= qw(40 00)[$_[0]];
-%      return "<tr><td bgcolor=\"#${c}${c}${c}\" height=1 colspan=7>";
-% };
-%
-% foreach my $i (0..$#islandids) {
-<% $tbody->(1) %>
-<tr>
-%      $iquery->execute($islandids[$i]);
-%      my ($islandname) = $iquery->fetchrow_array();
-%      if (!$i) {
+my $tbody= sub {
+       if (!printable($m)) { return '<tbody>'; }
+       my ($c)= qw(40 00)[$_[0]];
+       return "<tr><td bgcolor=\"#${c}${c}${c}\" height=1 colspan=7>";
+};
+
+foreach my $i (0..$#islandids) {
+     $plan_html .= $tbody->(1);
+     $plan_html .= "<tr>\n";
+     $iquery->execute($islandids[$i]);
+     my ($islandnamepr)= encode_entities( $iquery->fetchrow_array() );
+       
+     if (!$i) {
+               $plan_html .= <<END;
 <td colspan=2>
-<strong>Start at <% $islandname |h %></strong>
+<strong>Start at $islandnamepr</strong>
 <td colspan=2><a href="docs#posinclass">[what are these codes?]</a>
 <td>
-%      } else {
-%              my $this_dist= $distance->($islandids[$i-1],$islandids[$i]);
-%              $total_dist += $this_dist;
+END
+     } else {
+               my $this_dist= $distance->($islandids[$i-1],$islandids[$i]);
+               $total_dist += $this_dist;
+               $plan_html .= <<END;
 <td colspan=5>
-<%perl>
+END
                my $total_value= 0;
                foreach my $sf (@subflows) {
                        next unless $sf->{Org} < $i && $sf->{Dst} >= $i;
                        $total_value +=
                                $sf->{OptQty} * $sf->{Flow}{'dst_price'};
                }
-</%perl>
-<strong>Sail to <% $islandname |h %></strong>
-- <% $this_dist |h %> leagues,
- <% $total_value %>poe at risk
+               $plan_html .= <<END;
+<strong>Sail to $islandnamepr</strong>
+- $this_dist leagues, $total_value poe at risk
  </td>
-%      }
-<%perl>
+END
+     }
      my $age_reported= 0;
      my %flowlists;
      #print "<tr><td colspan=7>" if $qa->{'debug'};
@@ -847,66 +859,72 @@ END
        my ($xinfo) = @_;
        return unless defined $total_to_show;
        my ($totaldesc,$totalwas) = @$total_to_show;
-</%perl>
+       $plan_html .= <<END;
 <tr>
 <td colspan=1>
-<td colspan=3><% $xinfo %>
-<td colspan=2 align=right><% $totaldesc %>
-<td align=right><% $totalwas |h %> total
-<%perl>
+<td colspan=3>$xinfo
+<td colspan=2 align=right>$totaldesc
+<td align=right>$totalwas total
+END
        $total_to_show= undef;
      };
-</%perl>
-%    my $show_flows= sub {
-%      my ($od,$arbitrage,$collectdeliver) = @_;
-%      my $todo= $flowlists{$od};
-%      return unless $todo;
-%      foreach my $tkey (sort keys %$todo) {
-%              my $t= $todo->{$tkey};
-%              next if $t->{"${od}Arbitrage"} != $arbitrage;
-%              $show_total_now->('');
-%              if (!$age_reported++) {
-%                      my $age= $now - $t->{Timestamp};
-%                      my $cellid= "da_${i}";
-%                      $da_ages{$cellid}= $age;
-<td colspan=2>\
-(Data age: <span id="<% $cellid %>"><% prettyprint_age($age) %></span>)
-%              } elsif (!defined $total) {
-%                      $total= 0;
-<% $tbody->(0) %>
-%              }
-%              $total += $t->{Total};
-%              my $span= 0 + keys %{ $t->{Stalls} };
-%              my $td= "td rowspan=$span";
-%              my %linkqf= (%{ $qa->{'baseqf'} }, %{ $qa->{'queryqf'} });
-%              $linkqf{'query'}= 'commod';
-%              $linkqf{'commodstring'}= $t->{'commodname'};
-%              $linkqf{'commodid'}= $t->{'commodid'};
-% tr_datarow($m,$dline);
-<<% $td %>><% $collectdeliver %>
-<<% $td %>><a href="<% $quri->(%linkqf) %>"><% $t->{'commodname'} |h %></a>
-<<% $td %>><% $t->{'posinclass'} %>
-%
-%              my @stalls= sort keys %{ $t->{Stalls} };
-%              my $pstall= sub {
-%                      my $name= $stalls[$_[0]];
-<td><% $name |h %>
-%              };
-%
-%              $pstall->(0);
-<<% $td %> align=right><% $t->{Price} |h %> poe ea.
-<<% $td %> align=right><% $t->{Qty} |h %> unit(s)
-<<% $td %> align=right><% $t->{Total} |h %> total
-%
-%              foreach my $stallix (1..$#stalls) {
-% tr_datarow($m,$dline);
-%                      $pstall->($stallix);
-%              }
-%
-%              $dline ^= 1;
-%      }
-%    };
-<%perl>
+     my $show_flows= sub {
+       my ($od,$arbitrage,$collectdeliver) = @_;
+       my $todo= $flowlists{$od};
+       return unless $todo;
+       foreach my $tkey (sort keys %$todo) {
+               my $t= $todo->{$tkey};
+               next if $t->{"${od}Arbitrage"} != $arbitrage;
+               $show_total_now->('');
+               if (!$age_reported++) {
+                       my $age= $now - $t->{Timestamp};
+                       @oldest= ($age,$islandnamepr) if $oldest[0] < $age;
+                       my $cellid= "da_${i}";
+                       my $agepr= prettyprint_age($age);
+                       $da_ages{$cellid}= $age;
+                       $plan_html .= <<END
+<td colspan=2>(Data age: <span id="$cellid">$agepr</span>)
+END
+               } elsif (!defined $total) {
+                       $total= 0;
+                       $plan_html .= $tbody->(0);
+               }
+               $total += $t->{Total};
+               my $span= 0 + keys %{ $t->{Stalls} };
+               my $td= "td rowspan=$span";
+               my %linkqf= (%{ $qa->{'baseqf'} }, %{ $qa->{'queryqf'} });
+               $linkqf{'query'}= 'commod';
+               $linkqf{'commodstring'}= $t->{'commodname'};
+               $linkqf{'commodid'}= $t->{'commodid'};
+               my $linkqfpr= $quri->(%linkqf);
+               my $commodnamepr= encode_entities($t->{'commodname'});
+               $plan_html .= tr_datarow_s($m,$dline) . <<END;
+<$td>$collectdeliver
+<$td><a href="$linkqfpr">$commodnamepr</a>
+<$td>$t->{'posinclass'}
+END
+               my @stalls= sort keys %{ $t->{Stalls} };
+               my $pstall= sub {
+                       my $namepr= encode_entities( $stalls[$_[0]] );
+                       $plan_html .= <<END;
+<td>$namepr
+END
+               };
+
+               $pstall->(0);
+               $plan_html .= <<END;
+<$td align=right>$t->{Price} poe ea.
+<$td align=right>$t->{Qty} unit(s)
+<$td align=right>$t->{Total} total
+END
+               foreach my $stallix (1..$#stalls) {
+                       tr_datarow_s($m,$dline);
+                       $pstall->($stallix);
+               }
+
+               $dline ^= 1;
+       }
+     };
 
      $show_flows->('dst',0,'Deliver'); $show_total->('Proceeds',1);
      $show_flows->('org',1,'Collect'); $show_total->('(Arbitrage) outlay',-1);
@@ -930,23 +948,65 @@ END
      }
      $show_total_now->($totals);
 }
-</%perl><a name="summary"></a>
-<% $tbody->(1) %><tr>
-<td colspan=3>Total distance: <% $total_dist %> leagues.
+
+my $cashflowpr= $total_total < 0
+               ? -$total_total." loss"
+               : $total_total." gain";
+
+my $max_capital= 0;
+foreach my $cap (map { $_->{capital} } @sail_total) {
+       $max_capital= $cap if $cap > $max_capital;
+}
+
+$da_ages{'oldest'}= $oldest[0];
+
+$plan_html .= $tbody->(1) . <<END;
+<tr>
+<td colspan=3>Total distance: $total_dist leagues.
 <td colspan=3 align=right>Overall net cash flow
-<td align=right><strong><%
-  $total_total < 0 ? -$total_total." loss" : $total_total." gain"
- %></strong>
+<td align=right><strong>$cashflowpr</strong>
 </table>
+END
+
+</%perl>
+% if (!printable($m)) {
+<h2><a name="summary">Summary</a></h2>
+% }
+
+<table>
+<tr>
+ <td>Distance:
+ <td><strong><% $total_dist %></strong> leagues,
+     <strong><% scalar(@islandids) %></strong> island(s)
+<tr>
+ <td>Planned net cash flow:
+ <td><strong><% $cashflowpr %></strong>
+<tr>
+ <td>Expected profit on average: approx.
+ <td>
+  <strong><% sprintf "%d", $expected_total_profit %></strong> poe
+  (considering expected losses, but ignoring rum consumed)
+<tr>
+ <td>Capital required:
+ <td>
+  <strong><% $max_capital %></strong> poe or less
+<tr>
+ <td>Oldest market data used:
+ <td><strong id="oldest"><% prettyprint_age($oldest[0]) %></strong>
+     (<% $oldest[1] %>)
+<tr>
+ <td colspan=2><% $opt_how %>
+</table>
+<p>
+
+<h2><a name="plan">Voyage trading plan</a></h2>
+<% $plan_html %>
 <& query_age:dataages, id2age => \%da_ages &>
-Expected average profit:
- approx. <strong><% sprintf "%d", $expected_total_profit %></strong> poe
- (considering expected losses, but ignoring rum consumed)
 %
 % } # ========== TRADING PLAN ==========
 
 % if (!printable($m)) {
-<h2><a name="dataage">Data age summary</a></h2>
+<h2><a name="dataage">Relevant data ages</a></h2>
 <%perl>
        my $sth_i= $dbh->prepare(<<END);
                SELECT archipelago, islandid, islandname, timestamp