modify crawler implementation
This commit is contained in:
155
core/src/main/java/ru/trader/analysis/graph/AbstractGraph.java
Normal file
155
core/src/main/java/ru/trader/analysis/graph/AbstractGraph.java
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
package ru.trader.analysis.graph;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.trader.analysis.AnalysisCallBack;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ForkJoinPool;
|
||||||
|
import java.util.concurrent.RecursiveAction;
|
||||||
|
|
||||||
|
public abstract class AbstractGraph<T> implements Graph<T> {
|
||||||
|
private final static ForkJoinPool POOL = new ForkJoinPool();
|
||||||
|
private final static int THRESHOLD = 4;
|
||||||
|
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(AbstractGraph.class);
|
||||||
|
|
||||||
|
protected Vertex<T> root;
|
||||||
|
protected final Map<T, Vertex<T>> vertexes;
|
||||||
|
private final GraphCallBack callback;
|
||||||
|
|
||||||
|
protected int minJumps;
|
||||||
|
|
||||||
|
protected AbstractGraph() {
|
||||||
|
this(new AnalysisCallBack());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AbstractGraph(AnalysisCallBack callback) {
|
||||||
|
this.callback = new GraphCallBack(callback);
|
||||||
|
vertexes = new ConcurrentHashMap<>(50, 0.9f, THRESHOLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract GraphBuilder createGraphBuilder(Vertex<T> vertex, Collection<T> set, int deep, double limit);
|
||||||
|
|
||||||
|
public void build(T start, Collection<T> set, int maxDeep, double limit) {
|
||||||
|
callback.startBuild(start);
|
||||||
|
root = getInstance(start, maxDeep);
|
||||||
|
POOL.invoke(createGraphBuilder(root, set, maxDeep - 1, limit));
|
||||||
|
if (set.size() > vertexes.size()){
|
||||||
|
minJumps = maxDeep;
|
||||||
|
} else {
|
||||||
|
minJumps = 1;
|
||||||
|
for (Vertex<T> vertex : vertexes.values()) {
|
||||||
|
int jumps = maxDeep - vertex.getLevel();
|
||||||
|
if (jumps > minJumps) minJumps = jumps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback.endBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vertex<T> getInstance(T entry, int deep){
|
||||||
|
Vertex<T> vertex = vertexes.get(entry);
|
||||||
|
if (vertex == null) {
|
||||||
|
LOG.trace("Is new vertex");
|
||||||
|
vertex = new Vertex<>(entry);
|
||||||
|
vertex.setLevel(deep);
|
||||||
|
vertexes.put(entry, vertex);
|
||||||
|
}
|
||||||
|
return vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAccessible(T entry){
|
||||||
|
return vertexes.containsKey(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vertex<T> getVertex(T entry){
|
||||||
|
return vertexes.get(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vertex<T> getRoot() {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinJumps() {
|
||||||
|
return minJumps;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract class GraphBuilder extends RecursiveAction {
|
||||||
|
protected final Vertex<T> vertex;
|
||||||
|
protected final Collection<T> set;
|
||||||
|
protected final int deep;
|
||||||
|
protected final double limit;
|
||||||
|
|
||||||
|
protected GraphBuilder(Vertex<T> vertex, Collection<T> set, int deep, double limit) {
|
||||||
|
this.vertex = vertex;
|
||||||
|
this.set = set;
|
||||||
|
this.deep = deep;
|
||||||
|
this.limit = limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract double onConnect(T entry);
|
||||||
|
protected abstract Edge<T> createEdge(Vertex<T> target);
|
||||||
|
protected GraphBuilder createSubTask(Vertex<T> vertex, Collection<T> set, int deep, double limit){
|
||||||
|
return createGraphBuilder(vertex, set, deep, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void compute() {
|
||||||
|
LOG.trace("Build graph from {}, limit {}, deep {}", vertex, limit, deep);
|
||||||
|
ArrayList<GraphBuilder> subTasks = new ArrayList<>(THRESHOLD);
|
||||||
|
Iterator<T> iterator = set.iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
if (callback.isCancel()) break;
|
||||||
|
T entry = iterator.next();
|
||||||
|
if (entry == vertex.getEntry()) continue;
|
||||||
|
double nextLimit = onConnect(entry);
|
||||||
|
if (nextLimit >= 0) {
|
||||||
|
LOG.trace("Connect {} to {}", vertex, entry);
|
||||||
|
Vertex<T> next = getInstance(entry, 0);
|
||||||
|
vertex.connect(createEdge(next));
|
||||||
|
// If level > deep when vertex already added on upper deep
|
||||||
|
if (next.getLevel() < deep) {
|
||||||
|
next.setLevel(vertex.getLevel() - 1);
|
||||||
|
if (deep > 0) {
|
||||||
|
//Recursive build
|
||||||
|
GraphBuilder task = createSubTask(next, set, deep - 1, nextLimit);
|
||||||
|
task.fork();
|
||||||
|
subTasks.add(task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG.trace("Vertex {} is far away", entry);
|
||||||
|
}
|
||||||
|
if (subTasks.size() == THRESHOLD || !iterator.hasNext()){
|
||||||
|
for (GraphBuilder subTask : subTasks) {
|
||||||
|
if (callback.isCancel()){
|
||||||
|
subTask.cancel(true);
|
||||||
|
} else {
|
||||||
|
subTask.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subTasks.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!subTasks.isEmpty()){
|
||||||
|
for (GraphBuilder subTask : subTasks) {
|
||||||
|
if (callback.isCancel()){
|
||||||
|
subTask.cancel(true);
|
||||||
|
} else {
|
||||||
|
subTask.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subTasks.clear();
|
||||||
|
}
|
||||||
|
LOG.trace("End build graph from {} on deep {}", vertex, deep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
112
core/src/main/java/ru/trader/analysis/graph/CCrawler.java
Normal file
112
core/src/main/java/ru/trader/analysis/graph/CCrawler.java
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package ru.trader.analysis.graph;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.trader.core.Profile;
|
||||||
|
import ru.trader.core.Ship;
|
||||||
|
import ru.trader.graph.Connectable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class CCrawler<T extends Connectable<T>> extends Crawler<T> {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(CCrawler.class);
|
||||||
|
|
||||||
|
public CCrawler(ConnectibleGraph<T> graph, Consumer<List<Edge<T>>> onFoundFunc) {
|
||||||
|
super(graph, onFoundFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Ship getShip(){
|
||||||
|
return ((ConnectibleGraph<T>)graph).getProfile().getShip();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Profile getProfile(){
|
||||||
|
return ((ConnectibleGraph<T>)graph).getProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Crawler<T>.TraversalEntry start(Vertex<T> vertex) {
|
||||||
|
double fuel = getShip().getTank();
|
||||||
|
return new CTraversalEntry(new ArrayList<>(), vertex, fuel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Crawler<T>.CostTraversalEntry costStart(Vertex<T> vertex) {
|
||||||
|
double fuel = getShip().getTank();
|
||||||
|
return new CCostTraversalEntry(new ArrayList<>(), vertex, fuel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Crawler<T>.TraversalEntry travers(TraversalEntry entry, Edge<T> edge) {
|
||||||
|
T source = entry.vertex.getEntry();
|
||||||
|
double distance = source.getDistance(edge.target.getEntry());
|
||||||
|
double fuelCost = getShip().getFuelCost(((CTraversalEntry)entry).fuel, distance);
|
||||||
|
double nextLimit = getProfile().withRefill() ? ((CTraversalEntry)entry).fuel - fuelCost : getShip().getTank();
|
||||||
|
boolean refill = nextLimit < 0 && source.canRefill();
|
||||||
|
if (refill) {
|
||||||
|
LOG.trace("Refill");
|
||||||
|
refill = true;
|
||||||
|
nextLimit = getShip().getTank() - getShip().getFuelCost(distance);
|
||||||
|
}
|
||||||
|
edge = new ConnectibleEdge<>(edge.getSource(), edge.getTarget(), refill, fuelCost);
|
||||||
|
return new CTraversalEntry(getCopyList(entry.head, edge), edge.getTarget(), nextLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Crawler<T>.CostTraversalEntry costTravers(Crawler<T>.CostTraversalEntry entry, List<Edge<T>> head, Edge<T> edge) {
|
||||||
|
T source = entry.vertex.getEntry();
|
||||||
|
double distance = source.getDistance(edge.target.getEntry());
|
||||||
|
double fuelCost = getShip().getFuelCost(((CCostTraversalEntry)entry).fuel, distance);
|
||||||
|
double nextLimit = getProfile().withRefill() ? ((CCostTraversalEntry)entry).fuel - fuelCost : getShip().getTank();
|
||||||
|
boolean refill = nextLimit < 0 && source.canRefill();
|
||||||
|
if (refill) {
|
||||||
|
LOG.trace("Refill");
|
||||||
|
refill = true;
|
||||||
|
fuelCost = getShip().getFuelCost(distance);
|
||||||
|
nextLimit = getShip().getTank() - fuelCost;
|
||||||
|
}
|
||||||
|
edge = new ConnectibleEdge<>(edge.getSource(), edge.getTarget(), refill, fuelCost);
|
||||||
|
return new CCostTraversalEntry(head, edge, entry.getWeight(), nextLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class CTraversalEntry extends TraversalEntry {
|
||||||
|
private final double fuel;
|
||||||
|
|
||||||
|
protected CTraversalEntry(List<Edge<T>> head, Vertex<T> vertex, double fuel) {
|
||||||
|
super(head, vertex);
|
||||||
|
this.fuel = fuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Iterator<Edge<T>> getIteratorInstance() {
|
||||||
|
return vertex.getEdges().stream().filter(e -> {
|
||||||
|
ConnectibleEdge<T> edge = (ConnectibleEdge<T>) e;
|
||||||
|
return edge.getFuel() <= fuel || e.getSource().getEntry().canRefill();
|
||||||
|
}).iterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class CCostTraversalEntry extends CostTraversalEntry {
|
||||||
|
private final double fuel;
|
||||||
|
|
||||||
|
protected CCostTraversalEntry(List<Edge<T>> head, Vertex<T> vertex, double fuel) {
|
||||||
|
super(head, vertex);
|
||||||
|
this.fuel = fuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CCostTraversalEntry(List<Edge<T>> head, Edge<T> edge, double cost, double fuel) {
|
||||||
|
super(head, edge, cost);
|
||||||
|
this.fuel = fuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Iterator<Edge<T>> getIteratorInstance() {
|
||||||
|
return vertex.getEdges().stream().filter(e -> {
|
||||||
|
ConnectibleEdge<T> edge = (ConnectibleEdge<T>) e;
|
||||||
|
return edge.getFuel() <= fuel || e.getSource().getEntry().canRefill();
|
||||||
|
}).iterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package ru.trader.analysis.graph;
|
||||||
|
|
||||||
|
import ru.trader.graph.Connectable;
|
||||||
|
|
||||||
|
public class ConnectibleEdge<T extends Connectable<T>> extends Edge<T> {
|
||||||
|
protected final boolean refill;
|
||||||
|
protected final double fuel;
|
||||||
|
|
||||||
|
public ConnectibleEdge(Vertex<T> source, Vertex<T> target, boolean refill, double fuel) {
|
||||||
|
super(source, target);
|
||||||
|
this.refill = refill;
|
||||||
|
this.fuel = fuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRefill() {
|
||||||
|
return refill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getFuel() {
|
||||||
|
return fuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double computeWeight() {
|
||||||
|
T s = source.getEntry();
|
||||||
|
T t = target.getEntry();
|
||||||
|
return s.getDistance(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return source.getEntry().toString() + " - "+ weight
|
||||||
|
+ (refill ? "R" : "")
|
||||||
|
+" -> " + target.getEntry().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,10 +9,10 @@ import ru.trader.graph.Connectable;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class ConnectibleGraph<T extends Connectable<T>> extends Graph<T> {
|
public class ConnectibleGraph<T extends Connectable<T>> extends AbstractGraph<T> {
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(ConnectibleGraph.class);
|
private final static Logger LOG = LoggerFactory.getLogger(ConnectibleGraph.class);
|
||||||
|
|
||||||
private final Profile profile;
|
protected final Profile profile;
|
||||||
|
|
||||||
public ConnectibleGraph(Profile profile) {
|
public ConnectibleGraph(Profile profile) {
|
||||||
super();
|
super();
|
||||||
@@ -24,6 +24,10 @@ public class ConnectibleGraph<T extends Connectable<T>> extends Graph<T> {
|
|||||||
this.profile = profile;
|
this.profile = profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Profile getProfile() {
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected GraphBuilder createGraphBuilder(Vertex<T> vertex, Collection<T> set, int deep, double limit) {
|
protected GraphBuilder createGraphBuilder(Vertex<T> vertex, Collection<T> set, int deep, double limit) {
|
||||||
return new ConnectibleGraphBuilder(vertex, set, deep, limit);
|
return new ConnectibleGraphBuilder(vertex, set, deep, limit);
|
||||||
@@ -48,11 +52,12 @@ public class ConnectibleGraph<T extends Connectable<T>> extends Graph<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ConnectibleGraphBuilder extends GraphBuilder {
|
protected class ConnectibleGraphBuilder extends GraphBuilder {
|
||||||
private final DistanceFilter distanceFilter;
|
private final DistanceFilter distanceFilter;
|
||||||
protected boolean refill;
|
protected boolean refill;
|
||||||
|
protected double fuelCost;
|
||||||
|
|
||||||
private ConnectibleGraphBuilder(Vertex<T> vertex, Collection<T> set, int deep, double limit) {
|
protected ConnectibleGraphBuilder(Vertex<T> vertex, Collection<T> set, int deep, double limit) {
|
||||||
super(vertex, set, deep, limit);
|
super(vertex, set, deep, limit);
|
||||||
distanceFilter = new DistanceFilter(limit, vertex.getEntry());
|
distanceFilter = new DistanceFilter(limit, vertex.getEntry());
|
||||||
}
|
}
|
||||||
@@ -64,12 +69,13 @@ public class ConnectibleGraph<T extends Connectable<T>> extends Graph<T> {
|
|||||||
LOG.trace("Vertex {} is far away, {}", entry, distance);
|
LOG.trace("Vertex {} is far away, {}", entry, distance);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
double costFuel = profile.getShip().getFuelCost(limit, distance);
|
fuelCost = profile.getShip().getFuelCost(limit, distance);
|
||||||
double nextLimit = profile.withRefill() ? limit - costFuel : profile.getShip().getTank();
|
double nextLimit = profile.withRefill() ? limit - fuelCost : profile.getShip().getTank();
|
||||||
if (nextLimit < 0) {
|
if (nextLimit < 0) {
|
||||||
LOG.trace("Refill");
|
LOG.trace("Refill");
|
||||||
refill = true;
|
refill = true;
|
||||||
nextLimit = profile.getShip().getTank() - profile.getShip().getFuelCost(distance);
|
fuelCost = profile.getShip().getFuelCost(distance);
|
||||||
|
nextLimit = profile.getShip().getTank() - fuelCost;
|
||||||
} else {
|
} else {
|
||||||
refill = false;
|
refill = false;
|
||||||
}
|
}
|
||||||
@@ -77,35 +83,9 @@ public class ConnectibleGraph<T extends Connectable<T>> extends Graph<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ConnectibleEdge createEdge(Vertex<T> target) {
|
protected ConnectibleEdge<T> createEdge(Vertex<T> target) {
|
||||||
return new ConnectibleEdge(vertex, target, refill);
|
return new ConnectibleEdge<>(vertex, target, refill, fuelCost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected class ConnectibleEdge extends Edge<T> {
|
|
||||||
private final boolean refill;
|
|
||||||
|
|
||||||
protected ConnectibleEdge(Vertex<T> source, Vertex<T> target, boolean refill) {
|
|
||||||
super(source, target);
|
|
||||||
this.refill = refill;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRefill() {
|
|
||||||
return refill;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected double computeWeight() {
|
|
||||||
T s = source.getEntry();
|
|
||||||
T t = target.getEntry();
|
|
||||||
return s.getDistance(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return source.getEntry().toString() + " - "+ weight
|
|
||||||
+ (refill ? "R" : "")
|
|
||||||
+" -> " + target.getEntry().toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,21 +13,27 @@ public class Crawler<T> {
|
|||||||
private final static int THRESHOLD = 4;
|
private final static int THRESHOLD = 4;
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(Crawler.class);
|
private final static Logger LOG = LoggerFactory.getLogger(Crawler.class);
|
||||||
|
|
||||||
private final Graph<T> graph;
|
protected final Graph<T> graph;
|
||||||
private final Consumer<List<Edge<T>>> onFoundFunc;
|
private final Consumer<List<Edge<T>>> onFoundFunc;
|
||||||
|
private int maxSize;
|
||||||
|
|
||||||
public Crawler(Graph<T> graph, Consumer<List<Edge<T>>> onFoundFunc) {
|
public Crawler(Graph<T> graph, Consumer<List<Edge<T>>> onFoundFunc) {
|
||||||
this.graph = graph;
|
this.graph = graph;
|
||||||
|
maxSize = graph.getRoot().getLevel();
|
||||||
this.onFoundFunc = onFoundFunc;
|
this.onFoundFunc = onFoundFunc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Edge<T>> getCopyList(List<Edge<T>> head, Edge<T> tail){
|
protected List<Edge<T>> getCopyList(List<Edge<T>> head, Edge<T> tail){
|
||||||
List<Edge<T>> res = new ArrayList<>(20);
|
List<Edge<T>> res = new ArrayList<>(20);
|
||||||
res.addAll(head);
|
res.addAll(head);
|
||||||
res.add(tail);
|
res.add(tail);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaxSize(int maxSize) {
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
public void findFast(T target){
|
public void findFast(T target){
|
||||||
findFast(target, 1);
|
findFast(target, 1);
|
||||||
}
|
}
|
||||||
@@ -37,9 +43,11 @@ public class Crawler<T> {
|
|||||||
int found = 0;
|
int found = 0;
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
found = bfs(new ArrayList<>(), graph.root, target, 0, count);
|
Vertex<T> s = graph.getRoot();
|
||||||
|
s.sortEdges();
|
||||||
|
found = bfs(start(s), target, 0, count);
|
||||||
} else {
|
} else {
|
||||||
found = dfs(new ArrayList<>(), graph.root, target, t.getLevel() + 1, count);
|
found = dfs(start(graph.getRoot()), target, t.getLevel() + 1, count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG.debug("Found {} paths", found);
|
LOG.debug("Found {} paths", found);
|
||||||
@@ -53,31 +61,53 @@ public class Crawler<T> {
|
|||||||
Vertex<T> t = graph.getVertex(target);
|
Vertex<T> t = graph.getVertex(target);
|
||||||
int found = 0;
|
int found = 0;
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
found = ucs(new ArrayList<>(), graph.root, target, 0, count);
|
found = ucs(costStart(graph.getRoot()), target, 0, count);
|
||||||
}
|
}
|
||||||
LOG.debug("Found {} paths", found);
|
LOG.debug("Found {} paths", found);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int dfs(List<Edge<T>> head, Vertex<T> source, T target, int deep, int count) {
|
protected TraversalEntry start(Vertex<T> vertex){
|
||||||
LOG.trace("DFS from {} to {}, deep {}, count {}, head {}", source, target, deep, count, head);
|
return new TraversalEntry(new ArrayList<>(), vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CostTraversalEntry costStart(Vertex<T> vertex){
|
||||||
|
return new CostTraversalEntry(new ArrayList<>(), vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TraversalEntry travers(TraversalEntry entry, Edge<T> edge){
|
||||||
|
return new TraversalEntry(getCopyList(entry.head, edge), edge.getTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
private CostTraversalEntry costTravers(CostTraversalEntry entry, Edge<T> edge){
|
||||||
|
return costTravers(entry, getCopyList(entry.head, edge), edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CostTraversalEntry costTravers(CostTraversalEntry entry, List<Edge<T>> head, Edge<T> edge){
|
||||||
|
return new CostTraversalEntry(head, edge, entry.getWeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
private int dfs(TraversalEntry entry, T target, int deep, int count) {
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
List<Edge<T>> head = entry.head;
|
||||||
|
Vertex<T> source = entry.vertex;
|
||||||
|
LOG.trace("DFS from {} to {}, deep {}, count {}, head {}", source, target, deep, count, head);
|
||||||
if (deep == source.getLevel()){
|
if (deep == source.getLevel()){
|
||||||
Optional<Edge<T>> last = source.getEdges().parallelStream()
|
for (Edge<T> next : entry.getEdges()) {
|
||||||
.filter(next -> next.isConnect(target))
|
if (next.isConnect(target)){
|
||||||
.findFirst();
|
List<Edge<T>> res = getCopyList(head, next);
|
||||||
if (last.isPresent()){
|
LOG.debug("Last edge find, path {}", res);
|
||||||
List<Edge<T>> res = getCopyList(head, last.get());
|
onFoundFunc.accept(res);
|
||||||
LOG.debug("Last edge find, path {}", res);
|
found++;
|
||||||
onFoundFunc.accept(res);
|
break;
|
||||||
found++;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found < count){
|
if (found < count){
|
||||||
if (deep < source.getLevel()) {
|
if (deep < source.getLevel() && head.size() < maxSize-1) {
|
||||||
LOG.trace("Search around");
|
LOG.trace("Search around");
|
||||||
for (Edge<T> edge : source.getEdges()) {
|
for (Edge<T> edge : entry.getEdges()) {
|
||||||
if (edge.getTarget().isSingle()) continue;
|
if (edge.getTarget().isSingle()) continue;
|
||||||
found += dfs(getCopyList(head, edge), edge.getTarget(), target, deep, count-found);
|
found += dfs(travers(entry, edge), target, deep, count-found);
|
||||||
if (found >= count) break;
|
if (found >= count) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,18 +115,23 @@ public class Crawler<T> {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int bfs(List<Edge<T>> head, Vertex<T> source, T target, int deep, int count) {
|
private int bfs(TraversalEntry root, T target, int deep, int count) {
|
||||||
LOG.trace("BFS from {} to {}, deep {}, count {}", source, target, deep, count);
|
LOG.trace("BFS from {} to {}, deep {}, count {}", root.vertex, target, deep, count);
|
||||||
int found = 0;
|
int found = 0;
|
||||||
LinkedList<TraversalEntry> queue = new LinkedList<>();
|
LinkedList<TraversalEntry> queue = new LinkedList<>();
|
||||||
queue.add(new TraversalEntry(head, source));
|
queue.add(root);
|
||||||
while (!queue.isEmpty() && count > found){
|
while (!queue.isEmpty() && count > found){
|
||||||
TraversalEntry entry = queue.poll();
|
TraversalEntry entry = queue.poll();
|
||||||
head = entry.head;
|
List<Edge<T>> head = entry.head;
|
||||||
source = entry.vertex;
|
Vertex<T> source = entry.vertex;
|
||||||
|
if (head.size() >= maxSize){
|
||||||
|
LOG.trace("Is limit deep");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
LOG.trace("Search from {} to {}, head {}", source, target, head);
|
LOG.trace("Search from {} to {}, head {}", source, target, head);
|
||||||
source.sortEdges();
|
Iterator<Edge<T>> iterator = entry.iterator();
|
||||||
for (Edge<T> edge : source.getEdges()) {
|
while (iterator.hasNext()){
|
||||||
|
Edge<T> edge = iterator.next();
|
||||||
if (edge.isConnect(target)){
|
if (edge.isConnect(target)){
|
||||||
List<Edge<T>> res = getCopyList(head, edge);
|
List<Edge<T>> res = getCopyList(head, edge);
|
||||||
LOG.debug("Last edge find, path {}", res);
|
LOG.debug("Last edge find, path {}", res);
|
||||||
@@ -106,25 +141,26 @@ public class Crawler<T> {
|
|||||||
if (found >= count) break;
|
if (found >= count) break;
|
||||||
if (edge.getTarget().isSingle()) continue;
|
if (edge.getTarget().isSingle()) continue;
|
||||||
if (deep < source.getLevel()) {
|
if (deep < source.getLevel()) {
|
||||||
queue.add(new TraversalEntry(getCopyList(head, edge), edge.getTarget()));
|
edge.getTarget().sortEdges();
|
||||||
|
queue.add(travers(entry, edge));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int ucs(List<Edge<T>> head, Vertex<T> source, T target, int deep, int count) {
|
private int ucs(CostTraversalEntry root, T target, int deep, int count) {
|
||||||
LOG.trace("UCS from {} to {}, deep {}, count {}", source, target, deep, count);
|
LOG.trace("UCS from {} to {}, deep {}, count {}", root.vertex, target, deep, count);
|
||||||
int found = 0;
|
int found = 0;
|
||||||
PriorityQueue<CostTraversalEntry> queue = new PriorityQueue<>();
|
PriorityQueue<CostTraversalEntry> queue = new PriorityQueue<>();
|
||||||
queue.add(new CostTraversalEntry(head, source));
|
queue.add(root);
|
||||||
while (!queue.isEmpty() && count > found){
|
while (!queue.isEmpty() && count > found){
|
||||||
CostTraversalEntry entry = queue.poll();
|
CostTraversalEntry entry = queue.poll();
|
||||||
LOG.trace("Check path head {}, edge {}, cost {}", entry.head, entry.edge, entry.cost);
|
LOG.trace("Check path head {}, edge {}, weight {}", entry.head, entry.edge, entry.weight);
|
||||||
head = entry.head;
|
List<Edge<T>> head = entry.head;
|
||||||
|
Vertex<T> source = entry.vertex;
|
||||||
Edge<T> edge = entry.edge;
|
Edge<T> edge = entry.edge;
|
||||||
if (edge != null) {
|
if (edge != null) {
|
||||||
source = edge.getSource();
|
|
||||||
if (edge.isConnect(target)) {
|
if (edge.isConnect(target)) {
|
||||||
List<Edge<T>> res = getCopyList(head, edge);
|
List<Edge<T>> res = getCopyList(head, edge);
|
||||||
LOG.debug("Path found {}", res);
|
LOG.debug("Path found {}", res);
|
||||||
@@ -137,13 +173,17 @@ public class Crawler<T> {
|
|||||||
}
|
}
|
||||||
head = getCopyList(entry.head, edge);
|
head = getCopyList(entry.head, edge);
|
||||||
}
|
}
|
||||||
Iterator<Edge<T>> iterator = entry.iterator;
|
if (head.size() >= maxSize){
|
||||||
|
LOG.trace("Is limit deep");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Iterator<Edge<T>> iterator = entry.iterator();
|
||||||
//put only 2 entry for iterate
|
//put only 2 entry for iterate
|
||||||
while (iterator.hasNext()){
|
while (iterator.hasNext()){
|
||||||
edge = iterator.next();
|
edge = iterator.next();
|
||||||
if (deep < source.getLevel() && !edge.getTarget().isSingle() || edge.isConnect(target)) {
|
if (deep < source.getLevel() && !edge.getTarget().isSingle() || edge.isConnect(target)) {
|
||||||
LOG.trace("Add edge {} to queue", edge);
|
LOG.trace("Add edge {} to queue", edge);
|
||||||
queue.add(new CostTraversalEntry(head, edge, entry.cost));
|
queue.add(costTravers(entry, head, edge));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,17 +191,17 @@ public class Crawler<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//last edge don't compare
|
//last edge don't compare
|
||||||
private int ucs2(List<Edge<T>> head, Vertex<T> source, T target, int deep, int count) {
|
private int ucs2(CostTraversalEntry root, T target, int deep, int count) {
|
||||||
LOG.trace("UCS2 from {} to {}, deep {}, count {}", source, target, deep, count);
|
LOG.trace("UCS2 from {} to {}, deep {}, count {}", root.vertex, target, deep, count);
|
||||||
int found = 0;
|
int found = 0;
|
||||||
PriorityQueue<CostTraversalEntry> queue = new PriorityQueue<>();
|
PriorityQueue<CostTraversalEntry> queue = new PriorityQueue<>();
|
||||||
source.sortEdges();
|
queue.add(root);
|
||||||
queue.add(new CostTraversalEntry(head, source));
|
|
||||||
while (!queue.isEmpty() && count > found){
|
while (!queue.isEmpty() && count > found){
|
||||||
CostTraversalEntry entry = queue.peek();
|
CostTraversalEntry entry = queue.peek();
|
||||||
head = entry.edge != null ? getCopyList(entry.head, entry.edge) : entry.head;
|
List<Edge<T>> head = entry.edge != null ? getCopyList(entry.head, entry.edge) : entry.head;
|
||||||
Iterator<Edge<T>> iterator = entry.iterator;
|
Vertex<T> source = entry.vertex;
|
||||||
LOG.trace("Check path head {}, cost {}", head, entry.cost);
|
Iterator<Edge<T>> iterator = entry.iterator();
|
||||||
|
LOG.trace("Check path head {}, weight {}", head, entry.weight);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
//put only 2 entry for iterate
|
//put only 2 entry for iterate
|
||||||
while (iterator.hasNext() && i < 2){
|
while (iterator.hasNext() && i < 2){
|
||||||
@@ -175,9 +215,9 @@ public class Crawler<T> {
|
|||||||
}
|
}
|
||||||
if (found >= count) break;
|
if (found >= count) break;
|
||||||
if (edge.getTarget().isSingle()) continue;
|
if (edge.getTarget().isSingle()) continue;
|
||||||
if (deep < source.getLevel()) {
|
if (deep < source.getLevel() && head.size() < maxSize-1) {
|
||||||
edge.getTarget().sortEdges();
|
edge.getTarget().sortEdges();
|
||||||
queue.add(new CostTraversalEntry(head, edge, entry.cost));
|
queue.add(costTravers(entry, head, edge));
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,39 +226,59 @@ public class Crawler<T> {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TraversalEntry {
|
protected class TraversalEntry {
|
||||||
private final List<Edge<T>> head;
|
protected final List<Edge<T>> head;
|
||||||
private final Vertex<T> vertex;
|
protected final Vertex<T> vertex;
|
||||||
|
private Iterator<Edge<T>> iterator;
|
||||||
|
|
||||||
private TraversalEntry(List<Edge<T>> head, Vertex<T> vertex) {
|
protected TraversalEntry(List<Edge<T>> head, Vertex<T> vertex) {
|
||||||
this.head = head;
|
this.head = head;
|
||||||
this.vertex = vertex;
|
this.vertex = vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Iterator<Edge<T>> iterator(){
|
||||||
|
if (iterator == null){
|
||||||
|
iterator = getIteratorInstance();
|
||||||
|
}
|
||||||
|
return iterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Iterator<Edge<T>> getIteratorInstance(){
|
||||||
|
return vertex.getEdges().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterable<Edge<T>> getEdges(){
|
||||||
|
return this::iterator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CostTraversalEntry implements Comparable<CostTraversalEntry>{
|
protected class CostTraversalEntry extends TraversalEntry implements Comparable<CostTraversalEntry>{
|
||||||
private final List<Edge<T>> head;
|
|
||||||
private final Edge<T> edge;
|
private final Edge<T> edge;
|
||||||
private final Iterator<Edge<T>> iterator;
|
|
||||||
private final double cost;
|
private final double cost;
|
||||||
|
private Double weight;
|
||||||
|
|
||||||
private CostTraversalEntry(List<Edge<T>> head, Vertex<T> vertex) {
|
protected CostTraversalEntry(List<Edge<T>> head, Vertex<T> vertex) {
|
||||||
this.head = head;
|
super(head, vertex);
|
||||||
this.iterator = vertex.getEdges().iterator();
|
|
||||||
this.edge = null;
|
this.edge = null;
|
||||||
this.cost = 0;
|
this.cost = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CostTraversalEntry(List<Edge<T>> head, Edge<T> edge, double cost) {
|
protected CostTraversalEntry(List<Edge<T>> head, Edge<T> edge, double cost) {
|
||||||
this.head = head;
|
super(head, edge.getTarget());
|
||||||
this.edge = edge;
|
this.edge = edge;
|
||||||
this.iterator = edge.getTarget().getEdges().iterator();
|
this.cost = cost;
|
||||||
this.cost = cost + edge.getWeight();
|
}
|
||||||
|
|
||||||
|
protected double getWeight(){
|
||||||
|
if (weight == null){
|
||||||
|
weight = cost + (edge !=null ? edge.getWeight() : 0);
|
||||||
|
}
|
||||||
|
return weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(@NotNull CostTraversalEntry other) {
|
public int compareTo(@NotNull CostTraversalEntry other) {
|
||||||
int cmp = Double.compare(cost, other.cost);
|
int cmp = Double.compare(getWeight(), other.getWeight());
|
||||||
if (cmp != 0) return cmp;
|
if (cmp != 0) return cmp;
|
||||||
return Integer.compare(head.size(), other.head.size());
|
return Integer.compare(head.size(), other.head.size());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,144 +1,11 @@
|
|||||||
package ru.trader.analysis.graph;
|
package ru.trader.analysis.graph;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
public interface Graph<T> {
|
||||||
import org.slf4j.LoggerFactory;
|
boolean isAccessible(T entry);
|
||||||
import ru.trader.analysis.AnalysisCallBack;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
Vertex<T> getVertex(T entry);
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ForkJoinPool;
|
|
||||||
import java.util.concurrent.RecursiveAction;
|
|
||||||
|
|
||||||
public abstract class Graph<T> {
|
Vertex<T> getRoot();
|
||||||
private final static ForkJoinPool POOL = new ForkJoinPool();
|
|
||||||
private final static int THRESHOLD = 4;
|
|
||||||
|
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(Graph.class);
|
int getMinJumps();
|
||||||
|
|
||||||
protected Vertex<T> root;
|
|
||||||
protected final Map<T, Vertex<T>> vertexes;
|
|
||||||
private final GraphCallBack callback;
|
|
||||||
|
|
||||||
protected int minJumps;
|
|
||||||
|
|
||||||
protected Graph() {
|
|
||||||
this(new AnalysisCallBack());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Graph(AnalysisCallBack callback) {
|
|
||||||
this.callback = new GraphCallBack(callback);
|
|
||||||
vertexes = new ConcurrentHashMap<>(50, 0.9f, THRESHOLD);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract GraphBuilder createGraphBuilder(Vertex<T> vertex, Collection<T> set, int deep, double limit);
|
|
||||||
|
|
||||||
public void build(T start, Collection<T> set, int maxDeep, double limit) {
|
|
||||||
callback.startBuild(start);
|
|
||||||
root = getInstance(start, maxDeep);
|
|
||||||
POOL.invoke(createGraphBuilder(root, set, maxDeep - 1, limit));
|
|
||||||
if (set.size() > vertexes.size()){
|
|
||||||
minJumps = maxDeep;
|
|
||||||
} else {
|
|
||||||
minJumps = 1;
|
|
||||||
for (Vertex<T> vertex : vertexes.values()) {
|
|
||||||
int jumps = maxDeep - vertex.getLevel();
|
|
||||||
if (jumps > minJumps) minJumps = jumps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callback.endBuild();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Vertex<T> getInstance(T entry, int deep){
|
|
||||||
Vertex<T> vertex = new Vertex<>(entry);
|
|
||||||
vertex.setLevel(deep);
|
|
||||||
Vertex<T> old = vertexes.get(entry);
|
|
||||||
if (old == null || old.getLevel() < deep) {
|
|
||||||
LOG.trace("Is top vertex");
|
|
||||||
vertexes.put(entry, vertex);
|
|
||||||
}
|
|
||||||
return vertex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAccessible(T entry){
|
|
||||||
return vertexes.containsKey(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vertex<T> getVertex(T entry){
|
|
||||||
return vertexes.get(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getRoot() {
|
|
||||||
return root.getEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMinJumps() {
|
|
||||||
return minJumps;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract class GraphBuilder extends RecursiveAction {
|
|
||||||
protected final Vertex<T> vertex;
|
|
||||||
protected final Collection<T> set;
|
|
||||||
protected final int deep;
|
|
||||||
protected final double limit;
|
|
||||||
|
|
||||||
protected GraphBuilder(Vertex<T> vertex, Collection<T> set, int deep, double limit) {
|
|
||||||
this.vertex = vertex;
|
|
||||||
this.set = set;
|
|
||||||
this.deep = deep;
|
|
||||||
this.limit = limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract double onConnect(T entry);
|
|
||||||
protected abstract Edge<T> createEdge(Vertex<T> target);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void compute() {
|
|
||||||
LOG.trace("Build graph from {}, limit {}, deep {}", vertex, limit, deep);
|
|
||||||
ArrayList<GraphBuilder> subTasks = new ArrayList<>(THRESHOLD);
|
|
||||||
Iterator<T> iterator = set.iterator();
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
if (callback.isCancel()) break;
|
|
||||||
T entry = iterator.next();
|
|
||||||
if (entry == vertex.getEntry()) continue;
|
|
||||||
double nextLimit = onConnect(entry);
|
|
||||||
if (nextLimit >= 0) {
|
|
||||||
LOG.trace("Connect {} to {}", vertex, entry);
|
|
||||||
Vertex<T> next = getInstance(entry, vertex.getLevel() - 1);
|
|
||||||
vertex.connect(createEdge(next));
|
|
||||||
if (deep > 0) {
|
|
||||||
//Recursive build
|
|
||||||
GraphBuilder task = createGraphBuilder(next, set, deep - 1, nextLimit);
|
|
||||||
task.fork();
|
|
||||||
subTasks.add(task);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG.trace("Vertex {} is far away", entry);
|
|
||||||
}
|
|
||||||
if (subTasks.size() == THRESHOLD || !iterator.hasNext()){
|
|
||||||
for (GraphBuilder subTask : subTasks) {
|
|
||||||
if (callback.isCancel()){
|
|
||||||
subTask.cancel(true);
|
|
||||||
} else {
|
|
||||||
subTask.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
subTasks.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!subTasks.isEmpty()){
|
|
||||||
for (GraphBuilder subTask : subTasks) {
|
|
||||||
if (callback.isCancel()){
|
|
||||||
subTask.cancel(true);
|
|
||||||
} else {
|
|
||||||
subTask.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
subTasks.clear();
|
|
||||||
}
|
|
||||||
LOG.trace("End build graph from {} on deep {}", vertex, deep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public class Vertex<T> {
|
|||||||
return this.entry.equals(entry);
|
return this.entry.equals(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLevel(int level) {
|
public void setLevel(int level) {
|
||||||
this.level = level;
|
this.level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,21 @@ public class Profile {
|
|||||||
private int jumps;
|
private int jumps;
|
||||||
private Ship ship;
|
private Ship ship;
|
||||||
private boolean refill;
|
private boolean refill;
|
||||||
|
//Scorer multipliers
|
||||||
|
private int scoreOrdersCount;
|
||||||
|
private double distanceMult;
|
||||||
|
private double jumpMult;
|
||||||
|
private double landMult;
|
||||||
|
private double fuelPrice;
|
||||||
|
|
||||||
public Profile(Ship ship) {
|
public Profile(Ship ship) {
|
||||||
this.ship = ship;
|
this.ship = ship;
|
||||||
refill = true;
|
refill = true;
|
||||||
|
scoreOrdersCount = 5;
|
||||||
|
distanceMult = 1;
|
||||||
|
landMult = 1;
|
||||||
|
fuelPrice = 1;
|
||||||
|
jumpMult = 0.01;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getBalance() {
|
public double getBalance() {
|
||||||
@@ -43,4 +54,44 @@ public class Profile {
|
|||||||
public void setRefill(boolean refill) {
|
public void setRefill(boolean refill) {
|
||||||
this.refill = refill;
|
this.refill = refill;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getScoreOrdersCount() {
|
||||||
|
return scoreOrdersCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScoreOrdersCount(int scoreOrdersCount) {
|
||||||
|
this.scoreOrdersCount = scoreOrdersCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDistanceMult() {
|
||||||
|
return distanceMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDistanceMult(double distanceMult) {
|
||||||
|
this.distanceMult = distanceMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getJumpMult() {
|
||||||
|
return jumpMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJumpMult(double jumpMult) {
|
||||||
|
this.jumpMult = jumpMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLandMult() {
|
||||||
|
return landMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLandMult(double landMult) {
|
||||||
|
this.landMult = landMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getFuelPrice() {
|
||||||
|
return fuelPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFuelPrice(double fuelPrice) {
|
||||||
|
this.fuelPrice = fuelPrice;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class CrawlerTest extends Assert {
|
public class CrawlerTest extends Assert {
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(CrawlerTest.class);
|
private final static Logger LOG = LoggerFactory.getLogger(CrawlerTest.class);
|
||||||
@@ -89,7 +90,7 @@ public class CrawlerTest extends Assert {
|
|||||||
// x5 <-> x4, x5 <-> x6
|
// x5 <-> x4, x5 <-> x6
|
||||||
|
|
||||||
SimpleCollector paths = new SimpleCollector();
|
SimpleCollector paths = new SimpleCollector();
|
||||||
Crawler<Point> crawler = new Crawler<>(graph, paths::add);
|
Crawler<Point> crawler = new CCrawler<>(graph, paths::add);
|
||||||
crawler.findMin(x4, 10);
|
crawler.findMin(x4, 10);
|
||||||
assertPaths(paths.get(), PPath.of(x5, x4));
|
assertPaths(paths.get(), PPath.of(x5, x4));
|
||||||
paths.clear();
|
paths.clear();
|
||||||
@@ -118,7 +119,7 @@ public class CrawlerTest extends Assert {
|
|||||||
// x5 <-> x4 <-> x3 <-> x2, x5 <-> x6 <-> x7 <-> x8
|
// x5 <-> x4 <-> x3 <-> x2, x5 <-> x6 <-> x7 <-> x8
|
||||||
// x5 <-> x3, x4 <-> x2, x3 <-> x6, x4 <-> x6
|
// x5 <-> x3, x4 <-> x2, x3 <-> x6, x4 <-> x6
|
||||||
SimpleCollector paths = new SimpleCollector();
|
SimpleCollector paths = new SimpleCollector();
|
||||||
Crawler<Point> crawler = new Crawler<>(graph, paths::add);
|
Crawler<Point> crawler = new CCrawler<>(graph, paths::add);
|
||||||
|
|
||||||
crawler.findMin(x8, 10);
|
crawler.findMin(x8, 10);
|
||||||
assertPaths(paths.get(), PPath.of(x5, x6, x7, x8));
|
assertPaths(paths.get(), PPath.of(x5, x6, x7, x8));
|
||||||
@@ -135,11 +136,16 @@ public class CrawlerTest extends Assert {
|
|||||||
|
|
||||||
crawler.findMin(x4, 20);
|
crawler.findMin(x4, 20);
|
||||||
assertPaths(true, paths.get(), PPath.of(x5, x4), PPath.of(x5, x3, x4), PPath.of(x5, x6, x4),
|
assertPaths(true, paths.get(), PPath.of(x5, x4), PPath.of(x5, x3, x4), PPath.of(x5, x6, x4),
|
||||||
PPath.of(x5, x6, x5, x4), PPath.of(x5, x4, x3, x4), PPath.of(x5, x4, x5, x4),
|
PPath.of(x5, x6, x5, x4), PPath.of(x5, x4, x5, x4), PPath.of(x5, x4, x3, x4),
|
||||||
PPath.of(x5, x6, x3, x4), PPath.of(x5, x4, x6, x4),
|
PPath.of(x5, x4, x6, x4), PPath.of(x5, x6, x3, x4),
|
||||||
PPath.of(x5, x3, x5, x4), PPath.of(x5, x3, x2, x4),
|
PPath.of(x5, x3, x5, x4), PPath.of(x5, x4, x2, x4),
|
||||||
PPath.of(x5, x4, x2, x4), PPath.of(x5, x3, x6, x4)
|
PPath.of(x5, x3, x2, x4), PPath.of(x5, x3, x6, x4)
|
||||||
);
|
);
|
||||||
|
TestUtil.assertCollectionEquals(paths.getWeights(), 5.0, 15.0, 15.0,
|
||||||
|
15.0, 15.0, 15.0,
|
||||||
|
25.0, 25.0,
|
||||||
|
25.0, 35.0,
|
||||||
|
35.0, 35.0);
|
||||||
paths.clear();
|
paths.clear();
|
||||||
|
|
||||||
crawler.findMin(x5, 20);
|
crawler.findMin(x5, 20);
|
||||||
@@ -177,7 +183,7 @@ public class CrawlerTest extends Assert {
|
|||||||
// x5 <-> x4 <- refill -> x3 <- refill -> x2, x5 <-> x6
|
// x5 <-> x4 <- refill -> x3 <- refill -> x2, x5 <-> x6
|
||||||
// x5 <-> x3 <- refill -> x2, x5 <-> x4 <- refill -> x6
|
// x5 <-> x3 <- refill -> x2, x5 <-> x4 <- refill -> x6
|
||||||
SimpleCollector paths = new SimpleCollector();
|
SimpleCollector paths = new SimpleCollector();
|
||||||
Crawler<Point> crawler = new Crawler<>(graph, paths::add);
|
Crawler<Point> crawler = new CCrawler<>(graph, paths::add);
|
||||||
|
|
||||||
crawler.findMin(x1, 10);
|
crawler.findMin(x1, 10);
|
||||||
assertTrue(paths.get().isEmpty());
|
assertTrue(paths.get().isEmpty());
|
||||||
@@ -188,10 +194,14 @@ public class CrawlerTest extends Assert {
|
|||||||
paths.clear();
|
paths.clear();
|
||||||
|
|
||||||
crawler.findMin(x6, 10);
|
crawler.findMin(x6, 10);
|
||||||
assertPaths(true, paths.get(), PPath.of(x5, x6), PPath.of(x5, x4, x6),
|
assertPaths(paths.get(), PPath.of(x5, x6), PPath.of(x5, x4, x6),
|
||||||
PPath.of(x5, x6, x5, x6), PPath.of(x5, x4, x5, x6),
|
PPath.of(x5, x4, x5, x6), PPath.of(x5, x6, x5, x6),
|
||||||
PPath.of(x5, x3, x5, x6), PPath.of(x5, x3, x4, x6),
|
PPath.of(x5, x3, x4, x6), PPath.of(x5, x3, x5, x6),
|
||||||
PPath.of(x5, x6, x4, x6));
|
PPath.of(x5, x6, x4, x6));
|
||||||
|
TestUtil.assertCollectionEquals(paths.getWeights(), 5.0, 15.0,
|
||||||
|
15.0, 15.0,
|
||||||
|
25.0, 25.0,
|
||||||
|
25.0);
|
||||||
paths.clear();
|
paths.clear();
|
||||||
|
|
||||||
crawler.findFast(x2);
|
crawler.findFast(x2);
|
||||||
@@ -216,7 +226,7 @@ public class CrawlerTest extends Assert {
|
|||||||
// x5 <-> x3 <- refill -> x2
|
// x5 <-> x3 <- refill -> x2
|
||||||
// x5 <-> x4 <- refill -> x6
|
// x5 <-> x4 <- refill -> x6
|
||||||
SimpleCollector paths = new SimpleCollector();
|
SimpleCollector paths = new SimpleCollector();
|
||||||
Crawler<Point> crawler = new Crawler<>(graph, paths::add);
|
Crawler<Point> crawler = new CCrawler<>(graph, paths::add);
|
||||||
|
|
||||||
crawler.findMin(x1, 10);
|
crawler.findMin(x1, 10);
|
||||||
assertTrue(paths.get().isEmpty());
|
assertTrue(paths.get().isEmpty());
|
||||||
@@ -227,7 +237,7 @@ public class CrawlerTest extends Assert {
|
|||||||
PPath.of(x5, x4, x3, x2), PPath.of(x5, x4, x2), PPath.of(x5, x3, x5, x4, x2),
|
PPath.of(x5, x4, x3, x2), PPath.of(x5, x4, x2), PPath.of(x5, x3, x5, x4, x2),
|
||||||
PPath.of(x5, x6, x4, x2), PPath.of(x5, x6, x4, x3, x2), PPath.of(x5, x4, x3, x4, x2),
|
PPath.of(x5, x6, x4, x2), PPath.of(x5, x6, x4, x3, x2), PPath.of(x5, x4, x3, x4, x2),
|
||||||
PPath.of(x5, x4, x5, x4, x2), PPath.of(x5, x6, x5, x4, x2), PPath.of(x5, x3, x4, x3, x2),
|
PPath.of(x5, x4, x5, x4, x2), PPath.of(x5, x6, x5, x4, x2), PPath.of(x5, x3, x4, x3, x2),
|
||||||
PPath.of(x5, x3, x4, x3, x2), PPath.of(x5, x3, x4, x3, x2), PPath.of(x5, x3, x4, x3, x2));
|
PPath.of(x5, x3, x4, x3, x2), PPath.of(x5, x3, x4, x3, x2), PPath.of(x5, x3, x4, x3, x2));
|
||||||
paths.clear();
|
paths.clear();
|
||||||
|
|
||||||
crawler.findMin(x6, 30);
|
crawler.findMin(x6, 30);
|
||||||
@@ -269,13 +279,22 @@ public class CrawlerTest extends Assert {
|
|||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Edge<Point>> get(int indx) {
|
public List<Edge<Point>> get(int index) {
|
||||||
if (indx >= paths.size()) return Collections.emptyList();
|
if (index >= paths.size()) return Collections.emptyList();
|
||||||
return paths.get(indx);
|
return paths.get(index);
|
||||||
}
|
}
|
||||||
public void clear(){
|
public void clear(){
|
||||||
paths.clear();
|
paths.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getWeight(int index){
|
||||||
|
if (index >= paths.size()) return 0;
|
||||||
|
return paths.get(index).stream().mapToDouble(Edge::getWeight).sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Double> getWeights(){
|
||||||
|
return paths.stream().map(p -> p.stream().mapToDouble(Edge::getWeight).sum()).collect(Collectors.toList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user