Ich versuche, ein Programm zu implementieren, das arbitrage trading Möglichkeiten mit einem minimalen Kostenfluss Algorithmus erkennt. Dieser Algorithmus ist in Boost.Graph in Form von boost::push_relabel_max_flow()
gefolgt von einem Aufruf an boost::cycle_canceling()
implementiert.Boost.Graph - algo.is_optimal() assertion
Das folgende ist der Code, den ich bereits habe, den boost::cycle_canceling
-Teil auslassend, weil mein Programm stirbt, bevor es die Funktion erreicht.
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/push_relabel_max_flow.hpp>
#include <boost/graph/cycle_canceling.hpp>
#include <boost/graph/directed_graph.hpp>
#include <boost/config.hpp>
#include <iostream>
#include <string>
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> Traits;
struct st_order {
double price;
double amount;
std::string type;
};
struct VertexProps {
unsigned int id;
};
struct EdgeProps {
double capacity;
double residual_capacity;
double weight;
Traits::edge_descriptor reverse;
};
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexProps, EdgeProps > DirectedGraph;
int main() {
DirectedGraph g;
// ETH/BTC
std::vector<st_order> trades{
st_order{0.0101,10.0,"SELL"},
st_order{0.01,3.0,"BUY"},
st_order{0.0102,5.0,"SELL"},
st_order{0.2,42.0,"BUY"},
};
std::vector<boost::graph_traits<DirectedGraph>::vertex_descriptor> vertices;
for(unsigned int vertex_index = 0; vertex_index < trades.size(); vertex_index++)
{
vertices.push_back(boost::add_vertex({vertex_index}, g));
}
std::map<DirectedGraph::vertex_descriptor, std::map<DirectedGraph::vertex_descriptor, Traits::edge_descriptor>> edges;
int ifirst = 0;
for(auto& first : vertices)
{
int isecond = 0;
for(auto& second : vertices)
{
if(first == second || trades[ifirst].type.compare(trades[isecond].type) == 0)
{
isecond++;
continue;
}
double amount = trades[isecond].amount;
if(trades[isecond].type.compare("SELL") == 0)
amount = amount * trades[isecond].price;
edges[first][second] = boost::add_edge(first, second, {amount, amount, (trades[isecond].price/trades[ifirst].price)} , g).first;
std::cout << "Add Edge: From " << first << " to " << second << std::endl;
isecond++;
}
ifirst++;
}
for(auto& i : vertices)
{
for(auto& j : vertices)
{
if(i == j)
continue;
if(edges.find(i) != edges.end() && edges[i].find(j) != edges[i].end())
{
if(edges.find(j) == edges.end() || edges[j].find(i) == edges[j].end())
{
throw std::runtime_error("No return edge found: "+std::to_string(i)+" "+std::to_string(j));
}
auto edge = boost::edge(i,j,g).first;
g[edge].reverse = edges[i][j];
}
}
}
double flow = boost::push_relabel_max_flow(g, vertices[0], vertices[1],
boost::get(&EdgeProps::capacity, g),
boost::get(&EdgeProps::residual_capacity, g),
boost::get(&EdgeProps::reverse, g),
boost::get(boost::vertex_index, g)
);
// Now boost::cycle_canceling() would follow
std::cout << "END << std::endl;
return 0;
};
Die "normale" Ausgabe meines Programms ist:
Add Edge: From 0 to 1
Add Edge: From 0 to 3
Add Edge: From 1 to 0
Add Edge: From 1 to 2
Add Edge: From 2 to 1
Add Edge: From 2 to 3
Add Edge: From 3 to 0
Add Edge: From 3 to 2
Als Flussdiagramm:
Mein Programm behauptet im push_relabel_max_flow
-function. Im Folgenden ist der vollständige Fehlercode (die bei Laufzeit gedruckt wird):
/usr/local/include/boost/graph/push_relabel_max_flow.hpp:707: typename
boost::property_traits<IndexMap>::value_type
boost::push_relabel_max_flow(Graph&, typename
boost::graph_traits<Graph>::vertex_descriptor, typename
boost::graph_traits<Graph>::vertex_descriptor, CapacityEdgeMap,
ResidualCapacityEdgeMap, ReverseEdgeMap, VertexIndexMap) [with Graph =
boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
VertexProps, EdgeProps>; CapacityEdgeMap =
boost::adj_list_edge_property_map<boost::directed_tag, double, double&, long
unsigned int, EdgeProps, double EdgeProps::*>; ResidualCapacityEdgeMap =
boost::adj_list_edge_property_map<boost::directed_tag, double, double&, long
unsigned int, EdgeProps, double EdgeProps::*>; ReverseEdgeMap =
boost::adj_list_edge_property_map<boost::directed_tag,
boost::detail::edge_desc_impl<boost::directed_tag, long unsigned int>,
boost::detail::edge_desc_impl<boost::directed_tag, long unsigned int>&, long
unsigned int, EdgeProps, boost::detail::edge_desc_impl<boost::directed_tag,
long unsigned int> EdgeProps::*>; VertexIndexMap =
boost::vec_adj_list_vertex_id_map<VertexProps, long unsigned int>; typename
boost::property_traits<IndexMap>::value_type = double; typename
boost::graph_traits<Graph>::vertex_descriptor = long unsigned int]: Assertion
`algo.is_optimal()' failed.
Ganz am Ende der Nachricht, die Sie Assertion sehen: algo.is_optimal() fehlgeschlagen. Ich habe absolut keine Ahnung, was das bedeutet.
in der Quelldatei (boost/Graph/push_relabel_max_flow.hpp) wird wie folgt definiert:
bool is_optimal() {
// check if mincut is saturated...
global_distance_update();
return get(distance, src) >= n;
}
ich habe gegoogelt und nichts gefunden. Habe ich meine Parameter falsch übergeben? Liegt es daran, dass ich double
als Kapazität verwende (obwohl, wenn ich mich richtig erinnere, beschrieben "documentation" es als möglich, ein double
für die Kapazität zu verwenden)? Auch habe ich diesen Satz in den documentation entdeckt:
Die CapacityEdgeMap Argumente Kappe jede Kante in E auf eine positive Zahl, und jede Kante in E^T auf 0 Karte muss.
Was bedeutet der fettgedruckte Teil? Bedeutet das, dass ich die Kapazität aller ausgehenden Kanten vom Senken-Vertex auf 0 setzen muss?
Ich bin nicht mit diesem bestimmten Algorithmus vertraut. Ich habe Sie Code ausgeführt und es sieht aus wie 'is_optimal' ist Teil des Push-Relabel-Algorithmus nicht Boost, wie ich ursprünglich dachte. Meine Vermutung ist, dass es mit der Topologie Ihres Graphen zu tun haben könnte. Ich hatte keine Zeit, den Code für die Erstellung von Grafiken durchzugehen. Sind Sie sicher, dass diese Topologie für diese Art von Problem richtig ist? Sie könnten in Betracht ziehen, mit einem minimalen Arbeitsbeispiel des Algorithmus zu beginnen. – pbible
Ich habe meinen Beitrag mit weiteren Informationen und einem Diagramm bearbeitet. Ich bin mir ziemlich sicher, dass ich diesen Algorithmus für mein Diagramm verwenden kann. – Bobface