diff options
Diffstat (limited to 'src/history.cc')
-rw-r--r-- | src/history.cc | 218 |
1 files changed, 147 insertions, 71 deletions
diff --git a/src/history.cc b/src/history.cc index c4f6b3fc..22ac4494 100644 --- a/src/history.cc +++ b/src/history.cc @@ -42,13 +42,89 @@ struct f_max : public std::binary_function<T, T, bool> { namespace ledger { +template <typename EdgeWeightMap, + typename PricePointMap, + typename PriceRatioMap> +class recent_edge_weight +{ +public: + EdgeWeightMap weight; + PricePointMap price_point; + PriceRatioMap ratios; + + datetime_t reftime; + datetime_t oldest; + + recent_edge_weight() { } + recent_edge_weight(EdgeWeightMap _weight, + PricePointMap _price_point, + PriceRatioMap _ratios, + const datetime_t& _reftime, + const datetime_t& _oldest = datetime_t()) + : weight(_weight), price_point(_price_point), ratios(_ratios), + reftime(_reftime), oldest(_oldest) { } + + template <typename Edge> + bool operator()(const Edge& e) const + { +#if defined(DEBUG_ON) + DEBUG("history.find", " reftime = " << reftime); + if (! oldest.is_not_a_date_time()) { + DEBUG("history.find", " oldest = " << oldest); + } +#endif + + const price_map_t& prices(get(ratios, e)); + if (prices.empty()) { + DEBUG("history.find", " prices map is empty for this edge"); + return false; + } + + price_map_t::const_iterator low = prices.upper_bound(reftime); + if (low != prices.end() && low == prices.begin()) { + DEBUG("history.find", " don't use this edge"); + return false; + } else { + --low; + assert(((*low).first <= reftime)); + + if (! oldest.is_not_a_date_time() && (*low).first < oldest) { + DEBUG("history.find", " edge is out of range"); + return false; + } + + long secs = (reftime - (*low).first).total_seconds(); + assert(secs >= 0); + + put(weight, e, secs); + put(price_point, e, price_point_t((*low).first, (*low).second)); + + DEBUG("history.find", " using edge at price point " + << (*low).first << " " << (*low).second); + return true; + } + } +}; + +typedef filtered_graph + <commodity_history_t::Graph, + recent_edge_weight<commodity_history_t::EdgeWeightMap, + commodity_history_t::PricePointMap, + commodity_history_t::PriceRatioMap> > FGraph; + +typedef property_map<FGraph, vertex_name_t>::type FNameMap; +typedef property_map<FGraph, vertex_index_t>::type FIndexMap; +typedef iterator_property_map + <commodity_history_t::vertex_descriptor*, FIndexMap, + commodity_history_t::vertex_descriptor, + commodity_history_t::vertex_descriptor&> FPredecessorMap; +typedef iterator_property_map<long*, FIndexMap, long, long&> FDistanceMap; + void commodity_history_t::add_commodity(commodity_t& comm) { if (! comm.graph_index()) { - std::size_t index = num_vertices(price_graph); - comm.set_graph_index(index); - const vertex_descriptor vert = add_vertex(&comm, price_graph); - put(indexmap, vert, index); + comm.set_graph_index(num_vertices(price_graph)); + add_vertex(/* vertex_name= */ &comm, price_graph); } } @@ -59,7 +135,10 @@ void commodity_history_t::add_price(const commodity_t& source, vertex_descriptor sv = vertex(*source.graph_index(), price_graph); vertex_descriptor tv = vertex(*price.commodity().graph_index(), price_graph); - std::pair<edge_descriptor, bool> e1 = add_edge(sv, tv, 0, price_graph); + std::pair<edge_descriptor, bool> e1 = edge(sv, tv, price_graph); + if (! e1.second) + e1 = add_edge(sv, tv, price_graph); + price_map_t& prices(get(ratiomap, e1.first)); std::pair<price_map_t::iterator, bool> result = @@ -67,9 +146,6 @@ void commodity_history_t::add_price(const commodity_t& source, if (! result.second) { // There is already an entry for this moment, so update it (*result.first).second = price; - } else { - last_reftime = none; // invalidate the FGraph cache - last_oldest = none; } } @@ -80,31 +156,30 @@ void commodity_history_t::remove_price(const commodity_t& source, vertex_descriptor sv = vertex(*source.graph_index(), price_graph); vertex_descriptor tv = vertex(*target.graph_index(), price_graph); - std::pair<edge_descriptor, bool> e1 = add_edge(sv, tv, 0, price_graph); - price_map_t& prices(get(ratiomap, e1.first)); + std::pair<Graph::edge_descriptor, bool> e1 = edge(sv, tv, price_graph); + if (e1.second) { + price_map_t& prices(get(ratiomap, e1.first)); - // jww (2012-03-04): If it fails, should we give a warning? - prices.erase(date); + // jww (2012-03-04): If it fails, should we give a warning? + prices.erase(date); - last_reftime = none; // invalidate the FGraph cache - last_oldest = none; + if (prices.empty()) + remove_edge(e1.first, price_graph); + } } void commodity_history_t::map_prices(function<void(datetime_t, const amount_t&)> fn, - const commodity_t& source, - const datetime_t& moment, - const optional<datetime_t>& _oldest) + const commodity_t& source, + const datetime_t& moment, + const datetime_t& oldest) { vertex_descriptor sv = vertex(*source.graph_index(), price_graph); - reftime = moment; - oldest = _oldest; - FGraph fg(price_graph, recent_edge_weight<EdgeWeightMap, PricePointMap, PriceRatioMap> (get(edge_weight, price_graph), pricemap, ratiomap, - &reftime, &last_reftime, &oldest, &last_oldest)); + moment, oldest)); FNameMap namemap(get(vertex_name, fg)); @@ -118,7 +193,7 @@ void commodity_history_t::map_prices(function<void(datetime_t, foreach (const price_map_t::value_type& pair, prices) { const datetime_t& when(pair.first); - if ((! _oldest || when >= *_oldest) && when <= moment) { + if ((oldest.is_not_a_date_time() || when >= oldest) && when <= moment) { if (pair.second.commodity() == source) { amount_t price(pair.second); price.in_place_invert(); @@ -134,19 +209,16 @@ void commodity_history_t::map_prices(function<void(datetime_t, } optional<price_point_t> -commodity_history_t::find_price(const commodity_t& source, - const datetime_t& moment, - const optional<datetime_t>& _oldest) +commodity_history_t::find_price(const commodity_t& source, + const datetime_t& moment, + const datetime_t& oldest) { vertex_descriptor sv = vertex(*source.graph_index(), price_graph); - reftime = moment; - oldest = _oldest; - FGraph fg(price_graph, recent_edge_weight<EdgeWeightMap, PricePointMap, PriceRatioMap> (get(edge_weight, price_graph), pricemap, ratiomap, - &reftime, &last_reftime, &oldest, &last_oldest)); + moment, oldest)); FNameMap namemap(get(vertex_name, fg)); @@ -188,9 +260,6 @@ commodity_history_t::find_price(const commodity_t& source, DEBUG("history.find", "price is = " << price.unrounded()); } - last_reftime = reftime; // invalidate the FGraph cache - last_oldest = oldest; - if (price.is_null()) { DEBUG("history.find", "there is no final price"); return none; @@ -201,32 +270,30 @@ commodity_history_t::find_price(const commodity_t& source, } optional<price_point_t> -commodity_history_t::find_price(const commodity_t& source, - const commodity_t& target, - const datetime_t& moment, - const optional<datetime_t>& _oldest) +commodity_history_t::find_price(const commodity_t& source, + const commodity_t& target, + const datetime_t& moment, + const datetime_t& oldest) { vertex_descriptor sv = vertex(*source.graph_index(), price_graph); vertex_descriptor tv = vertex(*target.graph_index(), price_graph); - reftime = moment; - oldest = _oldest; - FGraph fg(price_graph, recent_edge_weight<EdgeWeightMap, PricePointMap, PriceRatioMap> (get(edge_weight, price_graph), pricemap, ratiomap, - &reftime, &last_reftime, &oldest, &last_oldest)); + moment, oldest)); FNameMap namemap(get(vertex_name, fg)); DEBUG("history.find", "sv commodity = " << get(namemap, sv)->symbol()); DEBUG("history.find", "tv commodity = " << get(namemap, tv)->symbol()); - std::vector<vertex_descriptor> predecessors(num_vertices(fg)); - std::vector<long> distances(num_vertices(fg)); - - PredecessorMap predecessorMap(&predecessors[0]); - DistanceMap distanceMap(&distances[0]); + std::size_t vector_len(num_vertices(fg)); + std::vector<vertex_descriptor> predecessors(vector_len); + std::vector<long> distances(vector_len); + + FPredecessorMap predecessorMap(&predecessors[0]); + FDistanceMap distanceMap(&distances[0]); dijkstra_shortest_paths(fg, /* start= */ sv, predecessor_map(predecessorMap) @@ -235,10 +302,15 @@ commodity_history_t::find_price(const commodity_t& source, // Extract the shortest path and performance the calculations datetime_t least_recent = moment; - amount_t price; + amount_t price; const commodity_t * last_target = ⌖ + typedef tuple<const commodity_t *, const commodity_t *, + const price_point_t *> results_tuple; + std::vector<results_tuple> results; + bool results_reversed = false; + vertex_descriptor v = tv; for (vertex_descriptor u = predecessorMap[v]; u != v; @@ -247,8 +319,24 @@ commodity_history_t::find_price(const commodity_t& source, std::pair<Graph::edge_descriptor, bool> edgePair = edge(u, v, fg); Graph::edge_descriptor edge = edgePair.first; + const commodity_t * u_comm = get(namemap, u); + const commodity_t * v_comm = get(namemap, v); const price_point_t& point(get(pricemap, edge)); + if (v == tv && u_comm != last_target && v_comm != last_target) + results_reversed = true; + + results.push_back(results_tuple(u_comm, v_comm, &point)); + } + + if (results_reversed) + std::reverse(results.begin(), results.end()); + + foreach (const results_tuple& edge, results) { + const commodity_t * u_comm = edge.get<0>(); + const commodity_t * v_comm = edge.get<1>(); + const price_point_t& point(*edge.get<2>()); + bool first_run = false; if (price.is_null()) { least_recent = point.when; @@ -258,8 +346,8 @@ commodity_history_t::find_price(const commodity_t& source, least_recent = point.when; } - DEBUG("history.find", "u commodity = " << get(namemap, u)->symbol()); - DEBUG("history.find", "v commodity = " << get(namemap, v)->symbol()); + DEBUG("history.find", "u commodity = " << u_comm->symbol()); + DEBUG("history.find", "v commodity = " << v_comm->symbol()); DEBUG("history.find", "last target = " << last_target->symbol()); // Determine which direction we are converting in @@ -268,12 +356,12 @@ commodity_history_t::find_price(const commodity_t& source, if (! first_run) { DEBUG("history.find", "price was = " << price.unrounded()); - if (pprice.commodity() != *last_target) + if (pprice.commodity_ptr() != last_target) price *= pprice.inverted(); else price *= pprice; } - else if (pprice.commodity() != *last_target) { + else if (pprice.commodity_ptr() != last_target) { price = pprice.inverted(); } else { @@ -281,17 +369,14 @@ commodity_history_t::find_price(const commodity_t& source, } DEBUG("history.find", "price is = " << price.unrounded()); - if (*last_target == *get(namemap, v)) - last_target = get(namemap, u); + if (last_target == v_comm) + last_target = u_comm; else - last_target = get(namemap, v); + last_target = v_comm; DEBUG("history.find", "last target now = " << last_target->symbol()); } - last_reftime = reftime; // invalidate the FGraph cache - last_oldest = oldest; - if (price.is_null()) { DEBUG("history.find", "there is no final price"); return none; @@ -317,25 +402,16 @@ private: Name name; }; -void commodity_history_t::print_map(std::ostream& out, - const optional<datetime_t>& moment) +void commodity_history_t::print_map(std::ostream& out, const datetime_t& moment) { - if (moment) { - reftime = *moment; - oldest = none; - + if (moment.is_not_a_date_time()) { + write_graphviz(out, price_graph, + label_writer<NameMap>(get(vertex_name, price_graph))); + } else { FGraph fg(price_graph, recent_edge_weight<EdgeWeightMap, PricePointMap, PriceRatioMap> - (get(edge_weight, price_graph), pricemap, ratiomap, - &reftime, &last_reftime, &oldest, &last_oldest)); - + (get(edge_weight, price_graph), pricemap, ratiomap, moment)); write_graphviz(out, fg, label_writer<FNameMap>(get(vertex_name, fg))); - - last_reftime = reftime; - last_oldest = none; - } else { - write_graphviz(out, price_graph, - label_writer<NameMap>(get(vertex_name, price_graph))); } } |