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

View file

@ -13,6 +13,7 @@ pub fn compute_flow(
edges: &EdgeDB, edges: &EdgeDB,
requested_flow: U256, requested_flow: U256,
max_distance: Option<u64>, max_distance: Option<u64>,
max_transfers: Option<u64>,
) -> (U256, Vec<Edge>) { ) -> (U256, Vec<Edge>) {
let mut adjacencies = Adjacencies::new(edges); let mut adjacencies = Adjacencies::new(edges);
let mut used_edges: HashMap<Node, HashMap<Node, U256>> = HashMap::new(); 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; 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) { let transfers = if flow == U256::from(0) {
vec![] vec![]
} else { } else {
@ -219,6 +229,25 @@ fn prune_flow(
flow_to_prune 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. /// Returns a map from the negative shortest path length to the edge.
/// The shortest path length is negative so that it is sorted by /// The shortest path length is negative so that it is sorted by
/// longest paths first - those are the ones we want to eliminate first. /// longest paths first - those are the ones we want to eliminate first.
@ -531,7 +560,7 @@ mod test {
token: t, token: t,
capacity: U256::from(10), 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!( assert_eq!(
flow, flow,
( (
@ -563,7 +592,7 @@ mod test {
capacity: U256::from(8), 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!( assert_eq!(
flow, flow,
( (
@ -615,7 +644,7 @@ mod test {
capacity: U256::from(8), 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(); flow.1.sort();
assert_eq!( assert_eq!(
flow, 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(); pruned_flow.1.sort();
assert_eq!( assert_eq!(
pruned_flow, pruned_flow,
@ -707,7 +736,7 @@ mod test {
capacity: U256::from(8), 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(); flow.1.sort();
println!("{:?}", &flow.1); println!("{:?}", &flow.1);
assert_eq!(flow.0, U256::from(9)); assert_eq!(flow.0, U256::from(9));

View file

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

View file

@ -61,7 +61,7 @@ fn test_flow(
requested_flow: U256, requested_flow: U256,
max_distance: Option<u64>, 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:?}"); println!("{transfers:?}");
let token_owners = transfers let token_owners = transfers