From b0ef280c8fbde95b4016049bc6c59280f7945f31 Mon Sep 17 00:00:00 2001 From: iMoHax Date: Fri, 20 Nov 2015 16:10:59 +0300 Subject: [PATCH] implement limit by time for crawler specification --- .../trader/analysis/CrawlerSpecificator.java | 208 ++++++++++++++---- .../ru/trader/analysis/RouteSearcher.java | 17 +- .../trader/analysis/RouteSpecification.java | 2 +- .../analysis/RouteSpecificationByPair.java | 75 ++++--- .../analysis/RouteSpecificationByTarget.java | 22 +- .../analysis/RouteSpecificationByTargets.java | 107 +++++---- .../analysis/RouteSpecificationMixer.java | 131 +++++++++++ .../ru/trader/analysis/VendorsCrawler.java | 9 + .../java/ru/trader/analysis/graph/Edge.java | 4 + .../ru/trader/analysis/graph/Traversal.java | 25 +++ .../analysis/CrawlerSpecificatorTest.java | 2 +- 11 files changed, 479 insertions(+), 123 deletions(-) create mode 100644 core/src/main/java/ru/trader/analysis/RouteSpecificationMixer.java diff --git a/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java b/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java index 91ba8c2..ed339c6 100644 --- a/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java +++ b/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java @@ -6,26 +6,76 @@ import ru.trader.core.Vendor; import java.util.*; import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Collectors; public class CrawlerSpecificator { - private final Set any; - private final Set containsAny; - private final Set all; - private final Collection offers; + private final Collection> any; + private final Collection> containsAny; + private final Collection> all; + private final Collection> offers; private int groupCount; private boolean byTime; private boolean fullScan; public CrawlerSpecificator() { - any = new HashSet<>(); - all = new HashSet<>(); - containsAny = new HashSet<>(); + any = new ArrayList<>(); + all = new ArrayList<>(); + containsAny = new ArrayList<>(); offers = new ArrayList<>(); byTime = false; fullScan = true; } + private void add(Collection> set, T obj){ + add(set, INFINITY_TIME, obj); + } + + private void add(Collection> set, Long time, T obj){ + TimeEntry entry = new TimeEntry<>(obj, time); + boolean add = true; + for (Iterator> iterator = set.iterator(); iterator.hasNext(); ) { + TimeEntry e = iterator.next(); + if (entry.obj.equals(e.obj)){ + if (entry.compareTo(e) >= 0){ + add = false; + } else { + iterator.remove(); + } + break; + } + } + if (add){ + set.add(entry); + } + } + + private void addAll(Collection> set, Collection objs){ + addAll(set, INFINITY_TIME, objs); + } + + private void addAll(Collection> set, Long time, Collection objs){ + for (T obj : objs) { + add(set, time, obj); + } + } + + private boolean contains(Collection> set, T obj){ + for (TimeEntry entry : set) { + if (entry.obj.equals(obj)){ + return true; + } + } + return false; + } + + private Map> groupByTime(Collection> set){ + return set.stream().collect( + Collectors.groupingBy(TimeEntry::getTime, + Collectors.mapping((Function, T>)TimeEntry::getObj, Collectors.toList()))); + } + + public void setByTime(boolean byTime){ this.byTime = byTime; } @@ -39,43 +89,67 @@ public class CrawlerSpecificator { } public void all(Collection vendors){ - all.addAll(vendors); + addAll(all, vendors); + } + + public void all(Collection vendors, long time){ + addAll(all, time, vendors); } public void any(Collection vendors){ - containsAny.addAll(vendors); + addAll(containsAny, vendors); + } + + public void any(Collection vendors, long time){ + addAll(containsAny, time, vendors); } public void target(Vendor vendor){ - any.add(vendor); + add(any, vendor); + } + + public void target(Vendor vendor, long time){ + add(any, time, vendor); } public void targetAny(Collection vendors){ - any.addAll(vendors); + addAll(any, vendors); + } + + public void targetAny(Collection vendors, long time){ + addAll(any, time, vendors); } public void add(Vendor vendor, boolean required){ if (required){ - all.add(vendor); + add(all, vendor); } else { - any.add(vendor); + add(any, vendor); } } - public void remove(Vendor vendor, boolean required){ + public void add(Vendor vendor, long time, boolean required){ if (required){ - all.remove(vendor); + add(all, time, vendor); } else { - any.remove(vendor); + add(any, time, vendor); } } public void buy(Offer offer){ - offers.add(offer); + add(offers, offer); + } + + public void buy(Offer offer, long time){ + add(offers, time, offer); } public void buy(Collection offers){ - this.offers.addAll(offers); + addAll(this.offers, offers); + } + + public void buy(Collection offers, long time){ + addAll(this.offers, time, offers); } public void setGroupCount(int groupCount) { @@ -83,13 +157,14 @@ public class CrawlerSpecificator { } public int getMinHop(){ - return all.size() + (any.isEmpty() ? 0 : 1) + (containsAny.isEmpty() ? 0 : 1) + offers.size()/4 ; + return all.size() + (any.isEmpty() ? 0 : 1) + (containsAny.isEmpty() ? 0 : 1) + offers.size(); } public boolean contains(Vendor vendor){ - boolean res = all.contains(vendor) || any.contains(vendor) || containsAny.contains(vendor); + boolean res = contains(all, vendor) || contains(any, vendor) || contains(containsAny, vendor); if (res) return true; - for (Offer offer : offers) { + for (TimeEntry entry : offers){ + Offer offer = entry.obj; Offer sell = vendor.getSell(offer.getItem()); res = sell != null && sell.getCount() >= offer.getCount(); if (res) return true; @@ -98,24 +173,29 @@ public class CrawlerSpecificator { } public Collection getVendors(Collection vendors){ - Set v = new HashSet<>(containsAny); - v.addAll(any); - v.addAll(all); + Set v = containsAny.stream().map(e -> e.obj).collect(Collectors.toSet()); + any.stream().map(e -> e.obj).forEach(v::add); + all.stream().map(e -> e.obj).forEach(v::add); + offers.stream().map(e -> e.obj.getVendor()).forEach(v::add); v.addAll(vendors); return v; } private RouteSpecification buildOffersSpec(Collection vendors){ RouteSpecification res = null; - for (Offer offer : offers) { + for (TimeEntry entry : offers) { + Offer offer = entry.obj; List sellers = vendors.stream().filter(v -> { Offer sell = v.getSell(offer.getItem()); return sell != null && sell.getCount() >= offer.getCount(); }).collect(Collectors.toList()); + RouteSpecificationByPair spec = entry.time.equals(INFINITY_TIME) ? + new RouteSpecificationByPair<>(sellers, offer.getVendor()) : + new RouteSpecificationByPair<>(sellers, offer.getVendor(), entry.time); if (res != null){ - res = res.and(new RouteSpecificationByPair<>(sellers, offer.getVendor())); + res = res.and(spec); } else { - res = new RouteSpecificationByPair<>(sellers, offer.getVendor()); + res = spec; } } return res; @@ -125,23 +205,51 @@ public class CrawlerSpecificator { RouteSpecification spec; RouteSpecification res = null; if (!all.isEmpty()){ - spec = RouteSpecificationByTargets.all(all); - res = spec; + for (Map.Entry> entry : groupByTime(all).entrySet()) { + spec = entry.getKey().equals(INFINITY_TIME) ? + RouteSpecificationByTargets.all(entry.getValue()) : + RouteSpecificationByTargets.all(entry.getValue(), entry.getKey()); + if (res != null){ + res = res.and(spec); + } else { + res = spec; + } + } } if (!any.isEmpty()){ - spec = any.size() > 1 ? RouteSpecificationByTargets.any(any) : new RouteSpecificationByTarget<>(any.iterator().next()); - if (res != null){ - res = res.and(spec); + if (any.size() == 1){ + TimeEntry entry = any.iterator().next(); + spec = entry.time.equals(INFINITY_TIME) ? + new RouteSpecificationByTarget<>(entry.obj) : + new RouteSpecificationByTarget<>(entry.obj, entry.time); + if (res != null){ + res = res.and(spec); + } else { + res = spec; + } } else { - res = spec; + for (Map.Entry> entry : groupByTime(any).entrySet()) { + spec = entry.getKey().equals(INFINITY_TIME) ? + RouteSpecificationByTargets.any(entry.getValue()) : + RouteSpecificationByTargets.any(entry.getValue(), entry.getKey()); + if (res != null){ + res = res.and(spec); + } else { + res = spec; + } + } } } if (!containsAny.isEmpty()){ - spec = RouteSpecificationByTargets.containAny(containsAny); - if (res != null){ - res = res.and(spec); - } else { - res = spec; + for (Map.Entry> entry : groupByTime(containsAny).entrySet()) { + spec = entry.getKey().equals(INFINITY_TIME) ? + RouteSpecificationByTargets.containAny(entry.getValue()) : + RouteSpecificationByTargets.containAny(entry.getValue(), entry.getKey()); + if (res != null){ + res = res.and(spec); + } else { + res = spec; + } } } if (!offers.isEmpty()){ @@ -173,4 +281,28 @@ public class CrawlerSpecificator { return build(vendors, onFoundFunc, null, false); } + private final static Long INFINITY_TIME = Long.MAX_VALUE; + + private class TimeEntry implements Comparable> { + private final T obj; + private final Long time; + + private TimeEntry(T obj, Long time) { + this.obj = obj; + this.time = time; + } + + private T getObj() { + return obj; + } + + private Long getTime() { + return time; + } + + @Override + public int compareTo(TimeEntry o) { + return this.time.compareTo(o.time); + } + } } diff --git a/core/src/main/java/ru/trader/analysis/RouteSearcher.java b/core/src/main/java/ru/trader/analysis/RouteSearcher.java index 814d0af..ce18253 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSearcher.java +++ b/core/src/main/java/ru/trader/analysis/RouteSearcher.java @@ -85,8 +85,10 @@ public class RouteSearcher { RouteCollector collector = new RouteCollector(); VendorsCrawlerSpecification specification = specificator.build(vendors, collector::add); Crawler crawler = vGraph.crawler(specification, callback); - int lands = Math.max(scorer.getProfile().getLands(), specification.getMinLands()); - if (!specificator.isFullScan()) lands = specificator.getMinHop(); + int lands = specification.getMinLands(); + if (specificator.isFullScan()){ + lands = Math.max(scorer.getProfile().getLands(), lands); + } crawler.setMaxSize(lands); crawler.findMin(target, count); return collector.get(); @@ -103,13 +105,18 @@ public class RouteSearcher { specificator.setGroupCount(vendors.size()); VendorsCrawlerSpecification specification = specificator.build(vendors, collector::add, new LoopRouteSpecification<>(true), true); - int lands = Math.max(scorer.getProfile().getLands(), specification.getMinLands()); + int lands = specification.getMinLands(); + if (specificator.isFullScan()){ + lands = Math.max(scorer.getProfile().getLands(), lands); + } Crawler crawler = vGraph.crawler(specification, callback); crawler.setMaxSize(lands); crawler.findMin(source, vendors.size()); specification = specificator.build(vendors, collector::add, new RouteSpecificationByTarget<>(source), false); - lands = Math.max(scorer.getProfile().getLands(), specification.getMinLands()); - if (!specificator.isFullScan()) lands = specificator.getMinHop(); + lands = specification.getMinLands(); + if (specificator.isFullScan()){ + lands = Math.max(scorer.getProfile().getLands(), lands); + } crawler = vGraph.crawler(specification, callback); crawler.setMaxSize(lands); crawler.findMin(source, 1); diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecification.java b/core/src/main/java/ru/trader/analysis/RouteSpecification.java index 20457a0..e5f3e94 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSpecification.java +++ b/core/src/main/java/ru/trader/analysis/RouteSpecification.java @@ -14,7 +14,7 @@ public interface RouteSpecification { public default boolean updateMutated(){return false;} public default boolean mutable(){return false;} public default void update(Traversal entry){} - public default void onAnd(RouteSpecification other){} + public default void onAnd(RouteSpecification other){RouteSpecificationMixer.andMix(this, other);} public default void onOr(RouteSpecification other){} default RouteSpecification and(final RouteSpecification other){ diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecificationByPair.java b/core/src/main/java/ru/trader/analysis/RouteSpecificationByPair.java index 3cc9ecf..2f9e81c 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSpecificationByPair.java +++ b/core/src/main/java/ru/trader/analysis/RouteSpecificationByPair.java @@ -6,25 +6,45 @@ import ru.trader.analysis.graph.Traversal; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; +import java.util.List; public class RouteSpecificationByPair implements RouteSpecification { protected final Collection first; protected final T second; + protected final long time; private boolean checkSecond; public RouteSpecificationByPair(T first, T second) { + this(first, second, Long.MAX_VALUE); + } + + public RouteSpecificationByPair(T first, T second, long time) { this.first = new ArrayList<>(); this.first.add(first); this.second = second; + this.time = time; checkSecond = true; } public RouteSpecificationByPair(Collection first, T second) { + this(first, second, Long.MAX_VALUE); + } + + public RouteSpecificationByPair(Collection first, T second, long time) { this.first = new ArrayList<>(first); this.second = second; + this.time = time; checkSecond = true; } + private boolean checkTime(){ + return time < Long.MAX_VALUE; + } + + protected void remove(){ + checkSecond = false; + } + @Override public boolean specified(Edge edge, Traversal entry) { return searchPair(edge, entry) == 0; @@ -32,6 +52,7 @@ public class RouteSpecificationByPair implements RouteSpecification { @Override public boolean content(Edge edge, Traversal entry) { + if (checkTime() && edge.getTime() + entry.getTime() > time) return false; T obj = edge.getTarget().getEntry(); return second.equals(obj) || first.contains(obj); } @@ -47,51 +68,35 @@ public class RouteSpecificationByPair implements RouteSpecification { } private int searchPair(Edge edge, Traversal entry){ - T obj = edge.getTarget().getEntry(); int fIndex = -1; int sIndex = -1; - if (first.contains(obj)){ - fIndex = 0; - } - if (second.equals(obj)){ - sIndex = 0; - } - if (sIndex != -1 && fIndex >= sIndex) return 0; - - Iterator> iterator = entry.routeIterator(); - int i = 1; - while (iterator.hasNext()){ - obj = iterator.next().getTarget().getEntry(); - if (sIndex == -1 && second.equals(obj)){ + List> entries = entry.toList(); + int max = entries.size(); + for (int i = 0; i < max; i++) { + Traversal e = entries.get(i); + T target = e.getTarget().getEntry(); + if (second.equals(target)){ + if (checkTime() && e.getTime() > time) return checkSecond ? 2 : 1; sIndex = i; } - if (sIndex != -1 && fIndex >= sIndex){ + if (sIndex != -1 && fIndex != -1 && fIndex <= sIndex){ return 0; } - if (first.contains(obj)){ + if (fIndex == -1 && first.contains(target)){ fIndex = i; } - i++; + } + T obj = edge.getTarget().getEntry(); + if (fIndex == -1 && first.contains(obj)){ + fIndex = max; + } + if (second.equals(obj)){ + if (checkTime() && edge.getTime() + entry.getTime() > time) return checkSecond ? 2 : 1; + sIndex = max; } if (fIndex == -1) return checkSecond ? 2 : 1; - if (sIndex == -1) return 1; - return fIndex >= sIndex ? 0 : 1; + if (sIndex == -1) return checkSecond ? 1 : 0; + return fIndex <= sIndex ? 0 : 1; } - - @Override - public void onAnd(RouteSpecification other) { - if (other instanceof RouteSpecificationByTarget){ - if (checkSecond){ - T otherTarget = ((RouteSpecificationByTarget)other).target; - checkSecond = !second.equals(otherTarget); - } - } else - if (other instanceof RouteSpecificationByPair){ - RouteSpecificationByPair os = (RouteSpecificationByPair)other; - if (checkSecond && os.checkSecond){ - checkSecond = !second.equals(os.second); - } - } - } } diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecificationByTarget.java b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTarget.java index ceb3370..7f29b05 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSpecificationByTarget.java +++ b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTarget.java @@ -4,14 +4,34 @@ import ru.trader.analysis.graph.Edge; import ru.trader.analysis.graph.Traversal; public class RouteSpecificationByTarget implements RouteSpecification { - protected final T target; + private T target; + protected final long time; public RouteSpecificationByTarget(T target) { + this(target, Long.MAX_VALUE); + } + + public RouteSpecificationByTarget(T target, long time) { this.target = target; + this.time = time; + } + + private boolean checkTime(){ + return time < Long.MAX_VALUE; + } + + protected T getTarget(){ + return target; + } + + protected void remove(){ + target = null; } @Override public boolean specified(Edge edge, Traversal entry) { + if (target == null) return true; + if (checkTime() && edge.getTime() + entry.getTime() > time) return false; return edge.isConnect(target); } } diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java index 0671f95..e725184 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java +++ b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java @@ -3,35 +3,42 @@ package ru.trader.analysis; import ru.trader.analysis.graph.Edge; import ru.trader.analysis.graph.Traversal; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; +import java.util.*; public class RouteSpecificationByTargets implements RouteSpecification { protected final Collection targets; protected final boolean all; protected final boolean targetOnly; + protected final long time; - private RouteSpecificationByTargets(Collection targets, boolean all, boolean targetOnly) { + protected RouteSpecificationByTargets(Collection targets, long time, boolean all, boolean targetOnly) { this.all = all; this.targetOnly = targetOnly; this.targets = new HashSet<>(targets); + this.time = time; + } + + private boolean checkTime(){ + return time < Long.MAX_VALUE; } @Override public boolean specified(Edge edge, Traversal entry) { - return targets.isEmpty() || (all ? containsAll(edge, entry) == 0 : containsAny(edge, entry) == 0); + if (targets.isEmpty()) return true; + if (checkTime() && targetOnly && edge.getTime() + entry.getTime() > time) return false; + return all ? containsAll(edge, entry) == 0 : containsAny(edge, entry) == 0; } @Override public boolean content(Edge edge, Traversal entry) { + if (checkTime() && edge.getTime() + entry.getTime() > time) return false; return targets.contains(edge.getTarget().getEntry()); } @Override public int lastFound(Edge edge, Traversal entry) { if (targets.isEmpty()) return 0; + if (checkTime() && targetOnly && edge.getTime() + entry.getTime() > time) return matchCount(); return all ? containsAll(edge, entry) : containsAny(edge, entry); } @@ -41,63 +48,79 @@ public class RouteSpecificationByTargets implements RouteSpecification { return all ? targets.size() : 1; } - @Override - public void onAnd(RouteSpecification other) { - if (other instanceof RouteSpecificationByTarget){ - T otherTarget = ((RouteSpecificationByTarget)other).target; - targets.remove(otherTarget); - } else - if (other instanceof RouteSpecificationByTargets){ - RouteSpecificationByTargets os = ((RouteSpecificationByTargets)other); - if (os.all){ - Collection otherTargets = ((RouteSpecificationByTargets)other).targets; - targets.removeAll(otherTargets); - } - } else - if (other instanceof RouteSpecificationByPair){ - T otherTarget = ((RouteSpecificationByPair)other).second; - targets.remove(otherTarget); - } - } - private int containsAll(Edge edge, Traversal entry) { - T obj = edge.getTarget().getEntry(); - Collection set = new ArrayList<>(targets.size()); - set.add(obj); - entry.routeIterator().forEachRemaining(e -> set.add(e.getTarget().getEntry())); - int last = targets.size(); - for (T target : targets) { - if (set.contains(target)){ - last--; + Collection founds = new HashSet<>(); + List> entries = entry.toList(); + for (Traversal e : entries) { + T target = e.getTarget().getEntry(); + if (targets.contains(target)){ + if (checkTime() && e.getTime() > time){ + return targets.size() - founds.size(); + } else { + founds.add(target); + } + } + if (targets.size() == founds.size()) return 0; + } + T target = edge.getTarget().getEntry(); + if (targets.contains(target)){ + if (checkTime() && edge.getTime() + entry.getTime() > time){ + return targets.size() - founds.size(); + } else { + founds.add(target); } } - return last; + return targets.size() - founds.size(); } private int containsAny(Edge edge, Traversal entry) { T obj = edge.getTarget().getEntry(); - if (targets.contains(obj)) return 0; + if (targets.contains(obj)){ + if (targetOnly){ + if (checkTime() && edge.getTime() + entry.getTime() > time) return 1; + else return 0; + } else { + return 0; + } + } if (targetOnly){ return 1; } - Iterator> iterator = entry.routeIterator(); - while (iterator.hasNext()){ - if (targets.contains(iterator.next().getTarget().getEntry())){ - return 0; + List> entries = entry.toList(); + for (Traversal e : entries) { + T target = e.getTarget().getEntry(); + if (targets.contains(target)){ + if (checkTime() && e.getTime() > time){ + return 1; + } else { + return 0; + } } } return 1; } public static RouteSpecificationByTargets all(Collection targets){ - return new RouteSpecificationByTargets<>(targets, true, false); + return all(targets, Long.MAX_VALUE); + } + + public static RouteSpecificationByTargets all(Collection targets, long time){ + return new RouteSpecificationByTargets<>(targets, time, true, false); } public static RouteSpecificationByTargets any(Collection targets){ - return new RouteSpecificationByTargets<>(targets, false, true); + return any(targets, Long.MAX_VALUE); + } + + public static RouteSpecificationByTargets any(Collection targets, long time){ + return new RouteSpecificationByTargets<>(targets, time, false, true); } public static RouteSpecificationByTargets containAny(Collection targets){ - return new RouteSpecificationByTargets<>(targets, false, false); + return containAny(targets, Long.MAX_VALUE); + } + + public static RouteSpecificationByTargets containAny(Collection targets, long time){ + return new RouteSpecificationByTargets<>(targets, time, false, false); } } diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecificationMixer.java b/core/src/main/java/ru/trader/analysis/RouteSpecificationMixer.java new file mode 100644 index 0000000..8fccb2c --- /dev/null +++ b/core/src/main/java/ru/trader/analysis/RouteSpecificationMixer.java @@ -0,0 +1,131 @@ +package ru.trader.analysis; + +import java.util.Collection; + +public class RouteSpecificationMixer { + public static void andMix(RouteSpecificationByTargets spec, RouteSpecification other) { + if (other instanceof RouteSpecificationByTarget){ + RouteSpecificationByTarget os = (RouteSpecificationByTarget)other; + T otherTarget = os.getTarget(); + if (os.time < spec.time){ + spec.targets.remove(otherTarget); + } else { + if (spec.targetOnly && spec.targets.contains(otherTarget)){ + os.remove(); + } + } + } else + if (other instanceof RouteSpecificationByTargets){ + RouteSpecificationByTargets os = ((RouteSpecificationByTargets)other); + if (os.all){ + Collection otherTargets = os.targets; + if (os.time < spec.time){ + spec.targets.removeAll(otherTargets); + } else { + if (spec.all){ + os.targets.removeAll(spec.targets); + } + } + } + } else + if (other instanceof RouteSpecificationByPair){ + RouteSpecificationByPair os = (RouteSpecificationByPair)other; + T otherTarget = os.second; + if (os.time < spec.time){ + spec.targets.remove(otherTarget); + } else { + if (spec.targetOnly && spec.targets.contains(otherTarget)){ + os.remove(); + } + } + } + } + + public static void andMix(RouteSpecificationByTarget spec, RouteSpecification other) { + if (other instanceof RouteSpecificationByTarget){ + RouteSpecificationByTarget os = (RouteSpecificationByTarget)other; + T otherTarget = os.getTarget(); + if (spec.getTarget() == otherTarget){ + if (os.time < spec.time){ + spec.remove(); + } else { + os.remove(); + } + } + } else + if (other instanceof RouteSpecificationByTargets){ + RouteSpecificationByTargets os = ((RouteSpecificationByTargets)other); + if (os.all){ + Collection otherTargets = os.targets; + if (otherTargets.contains(spec.getTarget())){ + if (os.time < spec.time){ + spec.remove(); + } else { + os.targets.remove(spec.getTarget()); + } + } + } + } else + if (other instanceof RouteSpecificationByPair){ + RouteSpecificationByPair os = (RouteSpecificationByPair)other; + T otherTarget = os.second; + if (spec.getTarget() == otherTarget){ + if (os.time < spec.time){ + spec.remove(); + } else { + os.remove(); + } + } + } + } + + public static void andMix(RouteSpecificationByPair spec, RouteSpecification other) { + if (other instanceof RouteSpecificationByTarget){ + RouteSpecificationByTarget os = (RouteSpecificationByTarget)other; + T otherTarget = os.getTarget(); + if (spec.second == otherTarget){ + if (os.time >= spec.time) { + os.remove(); + } + } + } else + if (other instanceof RouteSpecificationByTargets){ + RouteSpecificationByTargets os = ((RouteSpecificationByTargets)other); + if (os.targetOnly){ + Collection otherTargets = os.targets; + if (otherTargets.contains(spec.second)){ + if (os.time >= spec.time) { + os.targets.remove(spec.second); + } + } + } + } else + if (other instanceof RouteSpecificationByPair){ + RouteSpecificationByPair os = (RouteSpecificationByPair)other; + boolean eqFirst = spec.first.containsAll(os.first); + T otherTarget = os.second; + if (eqFirst && spec.second == otherTarget){ + if (os.time < spec.time){ + spec.remove(); + } else { + os.remove(); + } + } + } + } + + public static void andMix(RouteSpecification spec, RouteSpecification other) { + if (spec instanceof RouteSpecificationByTarget){ + andMix((RouteSpecificationByTarget)spec, other); + } else + if (spec instanceof RouteSpecificationByTargets){ + andMix((RouteSpecificationByTargets)spec, other); + } else + if (spec instanceof RouteSpecificationByPair){ + andMix((RouteSpecificationByPair)spec, other); + } + + } + + +} \ No newline at end of file diff --git a/core/src/main/java/ru/trader/analysis/VendorsCrawler.java b/core/src/main/java/ru/trader/analysis/VendorsCrawler.java index e32e16c..102d7b8 100644 --- a/core/src/main/java/ru/trader/analysis/VendorsCrawler.java +++ b/core/src/main/java/ru/trader/analysis/VendorsCrawler.java @@ -51,6 +51,7 @@ public class VendorsCrawler extends Crawler { protected class VendorsTraversalEntry extends CostTraversalEntry { private final double fuel; private final double balance; + private Long time; protected VendorsTraversalEntry(CostTraversalEntry entry, double fuel, double balance) { super(entry.getTarget()); @@ -101,6 +102,13 @@ public class VendorsCrawler extends Crawler { return weight; } + @Override + public long getTime() { + if (time == null){ + time = super.getTime(); + } + return time; + } private Vendor findMarket(){ Optional> head = getHead(); @@ -171,6 +179,7 @@ public class VendorsCrawler extends Crawler { return profitByTonne; } + @Override public long getTime() { if (time == null){ time = computeTime(); diff --git a/core/src/main/java/ru/trader/analysis/graph/Edge.java b/core/src/main/java/ru/trader/analysis/graph/Edge.java index ca1030d..f031905 100644 --- a/core/src/main/java/ru/trader/analysis/graph/Edge.java +++ b/core/src/main/java/ru/trader/analysis/graph/Edge.java @@ -33,6 +33,10 @@ public abstract class Edge implements Comparable{ return target.getEntry().equals(other); } + public long getTime(){ + return 1; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/core/src/main/java/ru/trader/analysis/graph/Traversal.java b/core/src/main/java/ru/trader/analysis/graph/Traversal.java index 519b030..f1f8b8f 100644 --- a/core/src/main/java/ru/trader/analysis/graph/Traversal.java +++ b/core/src/main/java/ru/trader/analysis/graph/Traversal.java @@ -32,6 +32,15 @@ public interface Traversal { return s; } + default long getTime(){ + Edge edge = this.getEdge(); + long t = edge != null ? edge.getTime() : 0; + if (this.getHead().isPresent()){ + t += getHead().get().getTime(); + } + return t; + } + @SuppressWarnings("unchecked") default List> toEdges(){ int s = size(); @@ -48,6 +57,22 @@ public interface Traversal { return Arrays.asList(res); } + @SuppressWarnings("unchecked") + default List> toList(){ + int s = size(); + Traversal[] res = new Traversal[s]; + int i = s - 1; + Traversal entry = this; + while (i >= 0){ + res[i]=entry; + if (i > 0) + entry = entry.getHead().get(); + i--; + } + return Arrays.asList(res); + + } + default Iterator> routeIterator(){ return new Iterator>() { private Edge next = getEdge(); diff --git a/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java b/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java index c980a83..dc35d8b 100644 --- a/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java +++ b/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java @@ -199,7 +199,7 @@ public class CrawlerSpecificatorTest extends Assert{ VendorsCrawlerSpecification spec = specificator.build(vendors, edges -> {paths.add(RouteSearcher.toRoute(edges, vGraph.getScorer()));}); Crawler crawler = vGraph.crawler(spec, new AnalysisCallBack()); - crawler.setMaxSize(7); + crawler.setMaxSize(spec.getMinLands()); crawler.findMin(ithaca_st, 10); assertEquals(10, paths.size()); for (Route path : paths) {