Option to limit amount of transfers.

This commit is contained in:
chriseth 2022-12-21 16:56:37 +01:00
parent e36f1558ef
commit 404ceb39b9
4 changed files with 46 additions and 7 deletions

View file

@ -41,7 +41,7 @@ fn main() {
return;
}
if args.len() < 4 {
if args.len() < 5 {
println!("Usage: cli [--csv] [--safes] <from> <to> <edges.dat> [--dot <dotfile>]");
println!(
"Usage: cli [--csv] [--safes] <from> <to> <edges.dat> <max_hops> [--dot <dotfile>]"
@ -49,12 +49,16 @@ fn main() {
println!(
"Usage: cli [--csv] [--safes] <from> <to> <edges.dat> <max_hops> <max_flow> [--dot <dotfile>]"
);
println!(
"Usage: cli [--csv] [--safes] <from> <to> <edges.dat> <max_hops> <max_flow> <max_transfers> [--dot <dotfile>]"
);
println!("Option --csv reads edges.dat in csv format instead of binary.");
println!("Option --safes reads a safes.dat file instead of an edges.dat file.");
return;
}
let mut max_hops = None;
let mut max_flow = U256::MAX;
let mut max_transfers: Option<u64> = None;
let (from_str, to_str, edges_file) = (&args[1], &args[2], &args[3]);
if args.len() >= 5 {
max_hops = Some(
@ -64,6 +68,9 @@ fn main() {
);
if args.len() >= 6 {
max_flow = args[5].as_str().into();
if args.len() >= 7 {
max_transfers = Some(args[6].as_str().parse::<i64>().unwrap() as u64);
}
}
}
@ -83,6 +90,7 @@ fn main() {
&edges,
max_flow,
max_hops,
max_transfers,
);
println!("Found flow: {}", flow.to_decimal());
//println!("{:?}", transfers);

View file

@ -13,6 +13,7 @@ pub fn compute_flow(
edges: &EdgeDB,
requested_flow: U256,
max_distance: Option<u64>,
max_transfers: Option<u64>,
) -> (U256, Vec<Edge>) {
let mut adjacencies = Adjacencies::new(edges);
let mut used_edges: HashMap<Node, HashMap<Node, U256>> = HashMap::new();
@ -59,6 +60,15 @@ pub fn compute_flow(
flow = requested_flow + still_to_prune;
}
if let Some(max_transfers) = max_transfers {
let lost = reduce_transfers(max_transfers * 3, &mut used_edges);
println!(
"Capacity lost by transfer count reduction: {}",
lost.to_decimal_fraction()
);
flow -= lost;
}
let transfers = if flow == U256::from(0) {
vec![]
} else {
@ -219,6 +229,25 @@ fn prune_flow(
flow_to_prune
}
fn reduce_transfers(
max_transfers: u64,
used_edges: &mut HashMap<Node, HashMap<Node, U256>>,
) -> U256 {
let mut reduced_flow = U256::from(0);
while used_edges.len() > max_transfers as usize {
let all_edges = used_edges
.iter()
.flat_map(|(f, e)| e.iter().map(|(t, c)| ((f.clone(), t.clone()), c)));
if all_edges.clone().count() <= max_transfers as usize {
return reduced_flow;
}
let ((f, t), c) = all_edges.min_by_key(|(_, c)| *c).unwrap();
reduced_flow += *c;
prune_edge(used_edges, (&f, &t), *c);
}
reduced_flow
}
/// Returns a map from the negative shortest path length to the edge.
/// The shortest path length is negative so that it is sorted by
/// longest paths first - those are the ones we want to eliminate first.
@ -531,7 +560,7 @@ mod test {
token: t,
capacity: U256::from(10),
}]);
let flow = compute_flow(&a, &b, &edges, U256::MAX, None);
let flow = compute_flow(&a, &b, &edges, U256::MAX, None, None);
assert_eq!(
flow,
(
@ -563,7 +592,7 @@ mod test {
capacity: U256::from(8),
},
]);
let flow = compute_flow(&a, &c, &edges, U256::MAX, None);
let flow = compute_flow(&a, &c, &edges, U256::MAX, None, None);
assert_eq!(
flow,
(
@ -615,7 +644,7 @@ mod test {
capacity: U256::from(8),
},
]);
let mut flow = compute_flow(&a, &d, &edges, U256::MAX, None);
let mut flow = compute_flow(&a, &d, &edges, U256::MAX, None, None);
flow.1.sort();
assert_eq!(
flow,
@ -649,7 +678,7 @@ mod test {
]
)
);
let mut pruned_flow = compute_flow(&a, &d, &edges, U256::from(6), None);
let mut pruned_flow = compute_flow(&a, &d, &edges, U256::from(6), None, None);
pruned_flow.1.sort();
assert_eq!(
pruned_flow,
@ -707,7 +736,7 @@ mod test {
capacity: U256::from(8),
},
]);
let mut flow = compute_flow(&a, &d, &edges, U256::MAX, None);
let mut flow = compute_flow(&a, &d, &edges, U256::MAX, None, None);
flow.1.sort();
println!("{:?}", &flow.1);
assert_eq!(flow.0, U256::from(9));

View file

@ -143,6 +143,7 @@ fn compute_transfer(
} else {
vec![None]
};
let max_transfers = request.params["max_transfers"].as_u64();
for max_distance in max_distances {
let (flow, transfers) = graph::compute_flow(
&Address::from(request.params["from"].to_string().as_str()),
@ -154,6 +155,7 @@ fn compute_transfer(
U256::MAX
},
max_distance,
max_transfers,
);
println!("Computed flow with max distance {max_distance:?}: {flow}");
socket.write_all(

View file

@ -61,7 +61,7 @@ fn test_flow(
requested_flow: U256,
max_distance: Option<u64>,
) {
let transfers = compute_flow(source, sink, edges, requested_flow, max_distance);
let transfers = compute_flow(source, sink, edges, requested_flow, max_distance, None);
println!("{transfers:?}");
let token_owners = transfers