Option to limit amount of transfers.
This commit is contained in:
parent
e36f1558ef
commit
404ceb39b9
4 changed files with 46 additions and 7 deletions
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue