improve search with complex specification
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package ru.trader.analysis;
|
||||
|
||||
|
||||
import ru.trader.analysis.graph.Edge;
|
||||
import ru.trader.analysis.graph.Traversal;
|
||||
|
||||
public class NullRouteSpecification<T> implements RouteSpecification<T> {
|
||||
@Override
|
||||
public boolean specified(Edge<T> edge, Traversal<T> entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean content(Edge<T> edge, Traversal<T> entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastFound(Edge<T> edge, Traversal<T> entry) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int matchCount() {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -14,162 +14,23 @@ public interface RouteSpecification<T> {
|
||||
public default boolean updateMutated(){return false;}
|
||||
public default boolean mutable(){return false;}
|
||||
public default void update(Traversal<T> entry){}
|
||||
public default void onAnd(RouteSpecification<T> other){RouteSpecificationMixer.andMix(this, other);}
|
||||
public default void onOr(RouteSpecification<T> other){}
|
||||
public default long getStart(){return 0;}
|
||||
public default long getEnd(){return Long.MAX_VALUE;}
|
||||
|
||||
default RouteSpecification<T> and(final RouteSpecification<T> other){
|
||||
this.onAnd(other);
|
||||
other.onAnd(this);
|
||||
return new RouteSpecification<T>() {
|
||||
@Override
|
||||
public boolean specified(Edge<T> edge, Traversal<T> entry) {
|
||||
return RouteSpecification.this.specified(edge, entry) && other.specified(edge, entry);
|
||||
if (other instanceof RouteSpecificationAndMixer){
|
||||
((RouteSpecificationAndMixer<T>) other).mix(this);
|
||||
return other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean content(Edge<T> edge, Traversal<T> entry) {
|
||||
return RouteSpecification.this.content(edge, entry) || other.content(edge, entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastFound(Edge<T> edge, Traversal<T> entry) {
|
||||
return RouteSpecification.this.lastFound(edge, entry) + other.lastFound(edge, entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int matchCount() {
|
||||
return RouteSpecification.this.matchCount() + other.matchCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateMutated() {
|
||||
return RouteSpecification.this.updateMutated() || other.updateMutated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mutable() {
|
||||
return RouteSpecification.this.mutable() || other.mutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Traversal<T> entry) {
|
||||
RouteSpecification.this.update(entry);
|
||||
other.update(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnd(RouteSpecification<T> specification) {
|
||||
RouteSpecification.this.onAnd(specification);
|
||||
other.onAnd(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOr(RouteSpecification<T> specification) {
|
||||
RouteSpecification.this.onOr(specification);
|
||||
other.onOr(specification);
|
||||
}
|
||||
};
|
||||
return RouteSpecificationAndMixer.mix(this, other);
|
||||
}
|
||||
|
||||
default RouteSpecification<T> or(final RouteSpecification<T> other){
|
||||
this.onOr(other);
|
||||
return new RouteSpecification<T>() {
|
||||
@Override
|
||||
public boolean specified(Edge<T> edge, Traversal<T> entry) {
|
||||
return RouteSpecification.this.specified(edge, entry) || other.specified(edge, entry);
|
||||
if (other instanceof RouteSpecificationOrMixer){
|
||||
((RouteSpecificationOrMixer<T>) other).mix(this);
|
||||
return other;
|
||||
}
|
||||
return RouteSpecificationOrMixer.mix(this, other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean content(Edge<T> edge, Traversal<T> entry) {
|
||||
return RouteSpecification.this.content(edge, entry) || other.content(edge, entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastFound(Edge<T> edge, Traversal<T> entry) {
|
||||
return Math.min(RouteSpecification.this.lastFound(edge, entry), other.lastFound(edge, entry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int matchCount() {
|
||||
return Math.min(RouteSpecification.this.matchCount(), other.matchCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateMutated() {
|
||||
return RouteSpecification.this.updateMutated() || other.updateMutated();
|
||||
}
|
||||
@Override
|
||||
public boolean mutable() {
|
||||
return RouteSpecification.this.mutable() || other.mutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Traversal<T> entry) {
|
||||
RouteSpecification.this.update(entry);
|
||||
other.update(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnd(RouteSpecification<T> specification) {
|
||||
RouteSpecification.this.onAnd(specification);
|
||||
other.onAnd(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOr(RouteSpecification<T> specification) {
|
||||
RouteSpecification.this.onOr(specification);
|
||||
other.onOr(specification);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
default RouteSpecification<T> negate(){
|
||||
return new RouteSpecification<T>() {
|
||||
@Override
|
||||
public boolean specified(Edge<T> edge, Traversal<T> entry) {
|
||||
return !RouteSpecification.this.specified(edge, entry);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean content(Edge<T> edge, Traversal<T> entry) {
|
||||
return !RouteSpecification.this.content(edge, entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastFound(Edge<T> edge, Traversal<T> entry) {
|
||||
return RouteSpecification.this.lastFound(edge, entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int matchCount() {
|
||||
return RouteSpecification.this.matchCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateMutated() {
|
||||
return RouteSpecification.this.updateMutated();
|
||||
}
|
||||
@Override
|
||||
public boolean mutable() {
|
||||
return RouteSpecification.this.mutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Traversal<T> entry) {
|
||||
RouteSpecification.this.update(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnd(RouteSpecification<T> specification) {
|
||||
RouteSpecification.this.onAnd(specification);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOr(RouteSpecification<T> specification) {
|
||||
RouteSpecification.this.onOr(specification);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,787 @@
|
||||
package ru.trader.analysis;
|
||||
|
||||
import ru.trader.analysis.graph.Edge;
|
||||
import ru.trader.analysis.graph.Traversal;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
||||
public class RouteSpecificationAndMixer<T> implements RouteSpecificationMixer<T>, RouteSpecification<T> {
|
||||
private final List<RouteSpecification<T>> specifications;
|
||||
|
||||
public RouteSpecificationAndMixer() {
|
||||
this.specifications = new ArrayList<>();
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private RouteSpecificationAndMixer(RouteSpecification<T> ... specification) {
|
||||
this();
|
||||
Collections.addAll(specifications, specification);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<RouteSpecification<T>> getMixed() {
|
||||
return specifications;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specified(Edge<T> edge, Traversal<T> entry) {
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
if (!specification.specified(edge, entry)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean content(Edge<T> edge, Traversal<T> entry) {
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
if (specification.content(edge, entry)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastFound(Edge<T> edge, Traversal<T> entry) {
|
||||
int res = 0;
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
res += specification.lastFound(edge, entry);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int matchCount() {
|
||||
int res = 0;
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
res += specification.matchCount();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateMutated() {
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
if (specification.updateMutated()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mutable() {
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
if (specification.mutable()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Traversal<T> entry) {
|
||||
specifications.forEach(s -> s.update(entry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouteSpecification<T> and(RouteSpecification<T> other) {
|
||||
return this.mix(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouteSpecification<T> mix(RouteSpecification<T> specification) {
|
||||
if (specification instanceof RouteSpecificationOrMixer){
|
||||
RouteSpecificationOrMixer<T> other = (RouteSpecificationOrMixer<T>)specification;
|
||||
for (RouteSpecification<T> s : specifications) {
|
||||
other.and(s);
|
||||
}
|
||||
return other;
|
||||
}
|
||||
if (specification instanceof RouteSpecificationAndMixer){
|
||||
Collection<RouteSpecification<T>> other = ((RouteSpecificationAndMixer<T>)specification).getMixed();
|
||||
other.forEach(this::collapse);
|
||||
} else {
|
||||
collapse(specification);
|
||||
}
|
||||
specifications.sort(RouteSpecificationOrMixer.ROUTE_SPECIFICATION_COMPARATOR);
|
||||
return this;
|
||||
}
|
||||
|
||||
private int getMinHope(Collection<RouteSpecification<T>> specifications){
|
||||
if (specifications.isEmpty()) return -1;
|
||||
return specifications.stream().mapToInt(RouteSpecification::matchCount).sum();
|
||||
}
|
||||
|
||||
private void collapse(RouteSpecification<T> specification){
|
||||
if (specifications.isEmpty()){
|
||||
specifications.add(specification);
|
||||
return;
|
||||
}
|
||||
Collection<RouteSpecification<T>> res = new ArrayList<>(specifications.size());
|
||||
RouteSpecification<T> minSpec = null;
|
||||
Collection<RouteSpecification<T>> minCollapsed = null;
|
||||
int min = -1;
|
||||
for (RouteSpecification<T> s : specifications) {
|
||||
Collection<RouteSpecification<T>> collapsed = andMix(s, specification);
|
||||
int hopes = getMinHope(collapsed);
|
||||
if (hopes != -1 && (minCollapsed == null || hopes < min || (hopes == min && minCollapsed.size()<collapsed.size()))){
|
||||
minCollapsed = collapsed;
|
||||
min = hopes;
|
||||
if (minSpec != null){
|
||||
res.add(minSpec);
|
||||
}
|
||||
minSpec = s;
|
||||
} else {
|
||||
res.add(s);
|
||||
}
|
||||
}
|
||||
if (minCollapsed != null){
|
||||
res.addAll(minCollapsed);
|
||||
} else {
|
||||
res.add(specification);
|
||||
}
|
||||
specifications.clear();
|
||||
specifications.addAll(res);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> RouteSpecification<T> mix(RouteSpecification<T> ... specification){
|
||||
RouteSpecificationAndMixer<T> res = new RouteSpecificationAndMixer<>();
|
||||
for (RouteSpecification<T> s : specification) {
|
||||
res.mix(s);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// target fot time t1 A = At1
|
||||
// contains A and B and C fot time t1 = [A&B&C]t1
|
||||
// target A or B or C fot time t1 = [A|B|C]t1
|
||||
// contains A or B or C fot time t1 = [A,B,C]t1
|
||||
// pair A or B or C to D fot time t1 = [A,B,C - D]t1
|
||||
// contains A from t1 to t2 time = A[t1-t2]
|
||||
|
||||
public static <T> Collection<RouteSpecification<T>> andMix(RouteSpecificationByTarget<T> spec, RouteSpecification<T> other) {
|
||||
Collection<RouteSpecification<T>> res = new ArrayList<>();
|
||||
T target = spec.getTarget();
|
||||
if (other instanceof RouteSpecificationByTarget){
|
||||
RouteSpecificationByTarget<T> os = (RouteSpecificationByTarget<T>)other;
|
||||
T otherTarget = os.getTarget();
|
||||
if (Objects.equals(target, otherTarget)){
|
||||
//At1 & At2 -> At1
|
||||
long time = Math.min(spec.getEnd(), os.getEnd());
|
||||
RouteSpecification<T> newSpec = new RouteSpecificationByTarget<>(target, time);
|
||||
res.add(newSpec);
|
||||
} else {
|
||||
//At1 & Bt2 -> empty
|
||||
res.add(new NullRouteSpecification<>());
|
||||
}
|
||||
} else
|
||||
if (other instanceof RouteSpecificationByTargets){
|
||||
RouteSpecificationByTargets<T> os = ((RouteSpecificationByTargets<T>)other);
|
||||
Collection<T> otherTargets = os.getTargets();
|
||||
if (otherTargets.contains(target)){
|
||||
if (os.isAll()){
|
||||
//At1 & [A&B&C]t2 -> At1 & [B&C]t1
|
||||
//[A&B&C]t1 & At2 -> At1 & [B&C]t1
|
||||
Collection<T> remainTargets = new ArrayList<>(otherTargets);
|
||||
long time = Math.min(spec.getEnd(), os.getEnd());
|
||||
RouteSpecification<T> s1 = new RouteSpecificationByTarget<>(target, time);
|
||||
res.add(s1);
|
||||
if (!remainTargets.isEmpty()){
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.all(remainTargets, time);
|
||||
res.add(s2);
|
||||
}
|
||||
} else
|
||||
if (os.isAny()){
|
||||
//At1 & [A|B|C]t2 -> At1
|
||||
//[A|B|C]t1 & At2 -> At1
|
||||
long time = Math.min(spec.getEnd(), os.getEnd());
|
||||
RouteSpecification<T> newSpec = new RouteSpecificationByTarget<>(target, time);
|
||||
res.add(newSpec);
|
||||
} else {
|
||||
Collection<T> remainTargets = new ArrayList<>(otherTargets);
|
||||
remainTargets.remove(target);
|
||||
if (spec.getEnd() <= os.getEnd()) {
|
||||
//At1 & [A,B,C]t2 -> At1
|
||||
RouteSpecification<T> newSpec = new RouteSpecificationByTarget<>(target, spec.getEnd());
|
||||
res.add(newSpec);
|
||||
} else {
|
||||
//[A,B,C]t1 & At2 -> At1 | (A[t1-t2] & [B,C]t1)
|
||||
RouteSpecification<T> s1 = new RouteSpecificationByTarget<>(target, os.getEnd());
|
||||
if (!remainTargets.isEmpty()){
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.containAny(remainTargets, spec.getEnd(), os.getEnd());
|
||||
RouteSpecification<T> s3 = new RouteSpecificationByTarget<>(target, spec.getEnd());
|
||||
RouteSpecification<T> newSpec = RouteSpecificationOrMixer.mix(s1, new RouteSpecificationAndMixer<>(s2, s3));
|
||||
res.add(newSpec);
|
||||
} else {
|
||||
res.add(s1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//A & [B,C] -> A & [B,C]
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else
|
||||
if (other instanceof RouteSpecificationByPair){
|
||||
RouteSpecificationByPair<T> os = (RouteSpecificationByPair<T>)other;
|
||||
Collection<T> otherTargets = os.getTargets();
|
||||
T otherTarget = os.getTarget();
|
||||
if (Objects.equals(target, otherTarget)){
|
||||
//At1 & [B,C - A]t2 -> At1 & [B,C]t1
|
||||
//[A,B,C - D]t1 & Dt2 -> [A,B,C]t1 & Dt1
|
||||
long time = Math.min(spec.getEnd(), os.getEnd());
|
||||
RouteSpecification<T> s1 = new RouteSpecificationByTarget<>(target, time);
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.containAny(otherTargets, time);
|
||||
res.add(s1);
|
||||
res.add(s2);
|
||||
} else
|
||||
if (otherTargets.contains(target) && spec.getEnd() < os.getEnd()){
|
||||
//At1 & [A,B,C - D]t2 -> At1 & [A,B,C - D]t1
|
||||
RouteSpecification<T> s2 = new RouteSpecificationByPair<>(otherTargets, otherTarget, spec.getEnd());
|
||||
res.add(spec);
|
||||
res.add(s2);
|
||||
} else {
|
||||
//[A,B,C - D]t1 & At2 -> [A,B,C - D]t1 & At2
|
||||
//At1 & [B,C - D]t2 -> At1 & [B,C - D]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static <E> void split(Collection<E> source, Collection<E> collection, Collection<E> intersect, Collection<E> retain, Collection<E> retainCollection){
|
||||
Collection<E> c = new ArrayList<>(collection);
|
||||
for (E s : source) {
|
||||
if (c.remove(s)){
|
||||
intersect.add(s);
|
||||
} else {
|
||||
retain.add(s);
|
||||
}
|
||||
}
|
||||
retainCollection.addAll(c);
|
||||
}
|
||||
|
||||
public static <T> Collection<RouteSpecification<T>> andMix(RouteSpecificationByTargets<T> spec, RouteSpecification<T> other) {
|
||||
Collection<RouteSpecification<T>> res = new ArrayList<>();
|
||||
Collection<T> targets = spec.getTargets();
|
||||
if (other instanceof RouteSpecificationByTarget){
|
||||
// already implement in other methods
|
||||
return andMix((RouteSpecificationByTarget<T>)other, spec);
|
||||
} else
|
||||
if (other instanceof RouteSpecificationByTargets){
|
||||
RouteSpecificationByTargets<T> os = ((RouteSpecificationByTargets<T>)other);
|
||||
if (os.getEnd() < spec.getEnd()){
|
||||
//swap
|
||||
return andMix(os, spec);
|
||||
}
|
||||
Collection<T> otherTargets = os.getTargets();
|
||||
if (spec.isAll()){
|
||||
if (os.isAll()){
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(otherTargets);
|
||||
if (retainOtherTargets.removeAll(targets)){
|
||||
//[A&B&C]t1 & [B&C&D]t2 -> [A&B&C]t1 & [&D]t2
|
||||
RouteSpecification<T> s1 = RouteSpecificationByTargets.all(targets, spec.getEnd());
|
||||
res.add(s1);
|
||||
if (!retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.all(retainOtherTargets, os.getEnd());
|
||||
res.add(s2);
|
||||
}
|
||||
} else {
|
||||
//[A&B&C]t1 & [D&E&F]t2 -> [A&B&C]t1 & [D&E&F]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else
|
||||
if (os.isAny()){
|
||||
//[A&B&C]t1 & [B|C|D]t2 -> [&A]t1 & (([&C]t1 & Bt1) | ([&B]t1 & Ct1) | ([&B&C]t1 & [B|C|D][t1-t2]))
|
||||
Collection<T> intersectTargets = new ArrayList<>();
|
||||
Collection<T> retainTargets = new ArrayList<>();
|
||||
Collection<T> retainOtherTargets = new ArrayList<>();
|
||||
split(targets, otherTargets, intersectTargets, retainTargets, retainOtherTargets);
|
||||
if (!intersectTargets.isEmpty()){
|
||||
if (!retainTargets.isEmpty()){
|
||||
RouteSpecification<T> s1 = RouteSpecificationByTargets.all(retainTargets, spec.getEnd());
|
||||
res.add(s1);
|
||||
}
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
for (T intersectTarget : intersectTargets) {
|
||||
Collection<T> its = new ArrayList<>(intersectTargets);
|
||||
its.remove(intersectTarget);
|
||||
RouteSpecification<T> s3 = new RouteSpecificationByTarget<>(intersectTarget, spec.getEnd());
|
||||
if (!its.isEmpty()){
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.all(its, spec.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
} else {
|
||||
orSpec.mix(s3);
|
||||
}
|
||||
}
|
||||
if (!retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s4 = RouteSpecificationByTargets.all(intersectTargets, spec.getEnd());
|
||||
RouteSpecification<T> s5 = RouteSpecificationByTargets.any(otherTargets, spec.getEnd(), os.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s4,s5));
|
||||
}
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
//[A&B&C]t1 & [D|E|F]t2 -> [A&B&C]t1 & [D|E|F]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
if (otherTargets.stream().filter(targets::contains).findAny().isPresent()){
|
||||
//[A&B&C]t1 & [B,C,D]t2 -> [A&B&C]t1
|
||||
res.add(spec);
|
||||
} else {
|
||||
//[A&B&C]t1 & [D,E,F]t2 -> [A&B&C]t1 & [D,E,F]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (spec.isAny()){
|
||||
if (os.isAll()){
|
||||
//[A|B|C]t1 & [B&C&D]t2
|
||||
Collection<T> intersectTargets = new ArrayList<>(); //B,C
|
||||
Collection<T> retainTargets = new ArrayList<>(); //A
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(); //D
|
||||
split(targets, otherTargets, intersectTargets, retainTargets, retainOtherTargets);
|
||||
if (!intersectTargets.isEmpty()){
|
||||
//[A|B|C]t1 & [B&C&D]t2 -> [&D]t1 & ((Bt1 & [&C]t1) | (Ct1 & [&B]t1) | [|A]t1 & [B&C]t1))
|
||||
if (!retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s1 = RouteSpecificationByTargets.all(retainOtherTargets, spec.getEnd());
|
||||
res.add(s1);
|
||||
}
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
for (T intersectTarget : intersectTargets) {
|
||||
Collection<T> its = new ArrayList<>(intersectTargets);
|
||||
its.remove(intersectTarget);
|
||||
RouteSpecification<T> s2 = new RouteSpecificationByTarget<>(intersectTarget, spec.getEnd());
|
||||
if (!its.isEmpty()){
|
||||
RouteSpecification<T> s3 = RouteSpecificationByTargets.all(its, spec.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
} else {
|
||||
orSpec.mix(s2);
|
||||
}
|
||||
}
|
||||
if (!retainTargets.isEmpty()){
|
||||
RouteSpecification<T> s4 = RouteSpecificationByTargets.any(retainTargets, spec.getEnd());
|
||||
RouteSpecification<T> s5 = RouteSpecificationByTargets.all(intersectTargets, spec.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s4,s5));
|
||||
}
|
||||
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
//[A|B|C]t1 & [D&E&F]t2 -> [A|B|C]t1 & [D&E&F]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
} else
|
||||
if (os.isAny()){
|
||||
Collection<T> intersectTarget = new ArrayList<>(otherTargets);
|
||||
intersectTarget.retainAll(targets);
|
||||
if (!intersectTarget.isEmpty()){
|
||||
//[A|B|C]t1 & [B|C|D]t2 -> [B|C]t1
|
||||
RouteSpecification<T> newSpec = RouteSpecificationByTargets.any(intersectTarget, spec.getEnd());
|
||||
res.add(newSpec);
|
||||
} else {
|
||||
//[A|B|C]t1 & [D|E|F]t2 -> empty
|
||||
res.add(new NullRouteSpecification<>());
|
||||
}
|
||||
} else {
|
||||
Collection<T> intersectTargets = new ArrayList<>(); //B,C
|
||||
Collection<T> retainTargets = new ArrayList<>(); //A
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(); //D
|
||||
split(targets, otherTargets, intersectTargets, retainTargets, retainOtherTargets);
|
||||
if (!intersectTargets.isEmpty()){
|
||||
//[A|B|C]t1 & [B,C,D]t2 -> ([B|C]t1) | ([,D]t1 & [|A]t1)
|
||||
RouteSpecification<T> s1 = RouteSpecificationByTargets.any(intersectTargets, spec.getEnd());
|
||||
if (!retainTargets.isEmpty() && !retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.containAny(retainOtherTargets, spec.getEnd());
|
||||
RouteSpecification<T> s3 = RouteSpecificationByTargets.any(retainTargets, spec.getEnd());
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
orSpec.mix(s1);
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
res.add(s1);
|
||||
}
|
||||
} else {
|
||||
//[A|B|C]t1 & [D,E,F]t2 -> [A|B|C]t1 & [D,E,F]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (os.isAll()){
|
||||
//[A,B,C]t1 & [B&C&D]t2
|
||||
Collection<T> intersectTargets = new ArrayList<>(); //B,C
|
||||
Collection<T> retainTargets = new ArrayList<>(); //A
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(); //D
|
||||
split(targets, otherTargets, intersectTargets, retainTargets, retainOtherTargets);
|
||||
if (!intersectTargets.isEmpty()){
|
||||
//[A,B,C]t1 & [B&C&D]t2 -> [&D]t2 & (([B]t1 & [&C]t2) | ([C]t1 & [&B]t2) | ([A]t1 & [B&C][t1-t2]))
|
||||
if (!retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s1 = RouteSpecificationByTargets.all(retainOtherTargets, os.getEnd());
|
||||
res.add(s1);
|
||||
}
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
for (T intersectTarget : intersectTargets) {
|
||||
Collection<T> its = new ArrayList<>(intersectTargets);
|
||||
its.remove(intersectTarget);
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.containAny(Collections.singleton(intersectTarget), spec.getEnd());
|
||||
if (!its.isEmpty()){
|
||||
RouteSpecification<T> s3 = RouteSpecificationByTargets.all(its, os.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
} else {
|
||||
orSpec.mix(s2);
|
||||
}
|
||||
}
|
||||
if (!retainTargets.isEmpty()){
|
||||
RouteSpecification<T> s4 = RouteSpecificationByTargets.containAny(retainTargets, spec.getEnd());
|
||||
RouteSpecification<T> s5 = RouteSpecificationByTargets.all(intersectTargets, spec.getEnd(), os.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s4,s5));
|
||||
}
|
||||
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
//[A,B,C]t1 & [B&C&D]t2 -> [A,B,C]t1 & [D&E&F]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
} else
|
||||
if (os.isAny()){
|
||||
//[A,B,C]t1 & [B|C|D]t2
|
||||
Collection<T> intersectTargets = new ArrayList<>(); //B,C
|
||||
Collection<T> retainTargets = new ArrayList<>(); //A
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(); //D
|
||||
split(targets, otherTargets, intersectTargets, retainTargets, retainOtherTargets);
|
||||
if (!intersectTargets.isEmpty()){
|
||||
//[A,B,C]t1 & [B|C|D]t2 -> [B|C]t1 | ([A]t1 & ([B|C][t1-t2] | [|D]t2))
|
||||
RouteSpecification<T> s1 = RouteSpecificationByTargets.any(intersectTargets, spec.getEnd());
|
||||
if (!retainTargets.isEmpty()){
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
orSpec.mix(s1);
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.containAny(retainTargets, spec.getEnd());
|
||||
RouteSpecification<T> s3 = RouteSpecificationByTargets.any(intersectTargets, spec.getEnd(), os.getEnd());
|
||||
RouteSpecificationAndMixer<T> andSpec;
|
||||
if (!retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s4 = RouteSpecificationByTargets.any(retainOtherTargets, os.getEnd());
|
||||
andSpec = new RouteSpecificationAndMixer<>(s2, RouteSpecificationOrMixer.mix(s3, s4));
|
||||
} else {
|
||||
andSpec = new RouteSpecificationAndMixer<>(s2, s3);
|
||||
}
|
||||
orSpec.mix(andSpec);
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
res.add(s1);
|
||||
}
|
||||
} else {
|
||||
//[A,B,C]t1 & [D|E|F]t2 -> [A,B,C]t1 & [D|E|F]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
//[A,B,C]t1 & [B,C,D]t2
|
||||
Collection<T> intersectTargets = new ArrayList<>(); //B,C
|
||||
Collection<T> retainTargets = new ArrayList<>(); //A
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(); //D
|
||||
split(targets, otherTargets, intersectTargets, retainTargets, retainOtherTargets);
|
||||
if (!intersectTargets.isEmpty()){
|
||||
//[A,B,C]t1 & [B,C,D]t2 -> [B,C]t1 | ([A]t1 & [D]t2)
|
||||
RouteSpecification<T> s1 = RouteSpecificationByTargets.containAny(intersectTargets, spec.getEnd());
|
||||
if (!retainTargets.isEmpty() && !retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.containAny(retainTargets, spec.getEnd());
|
||||
RouteSpecification<T> s3 = RouteSpecificationByTargets.containAny(retainOtherTargets, os.getEnd());
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
orSpec.mix(s1);
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
res.add(s1);
|
||||
}
|
||||
} else {
|
||||
//[A,B,C]t1 & [D,E,F]t2 -> [A,B,C]t1 & [D,E,F]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (other instanceof RouteSpecificationByPair){
|
||||
// already implement in other methods
|
||||
return andMix((RouteSpecificationByPair<T>)other, spec);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static <T> Collection<RouteSpecification<T>> andMix(RouteSpecificationByPair<T> spec, RouteSpecification<T> other) {
|
||||
Collection<RouteSpecification<T>> res = new ArrayList<>();
|
||||
Collection<T> targets = spec.getTargets();
|
||||
T target = spec.getTarget();
|
||||
if (other instanceof RouteSpecificationByTarget){
|
||||
// already implement in other methods
|
||||
return andMix((RouteSpecificationByTarget<T>)other, spec);
|
||||
} else
|
||||
if (other instanceof RouteSpecificationByTargets){
|
||||
RouteSpecificationByTargets<T> os = ((RouteSpecificationByTargets<T>)other);
|
||||
Collection<T> otherTargets = os.getTargets();
|
||||
|
||||
if (os.isAll()){
|
||||
//[A,B,C - D]t1 & [B&C&D&E]t2
|
||||
Collection<T> intersectTargets = new ArrayList<>(); //B,C
|
||||
Collection<T> retainTargets = new ArrayList<>(); //A
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(); //D
|
||||
split(targets, otherTargets, intersectTargets, retainTargets, retainOtherTargets);
|
||||
if (!intersectTargets.isEmpty() || otherTargets.contains(target)){
|
||||
if (spec.getEnd() <= os.getEnd()){
|
||||
//[A,B,C - D]t1 & [B&C&D&E]t2 -> [&E]t2 & (([B - D]t1 & [&C]t2) | ([C - D]t1 & [&B]t2) | ([A - D]t1 & [B&C]t2))
|
||||
//[A,B,C - F]t1 & [B&C&D&E]t2 -> [D&E]t2 & (([B - F]t1 & [&C]t2) | ([C - F]t1 & [&B]t2) | ([A - F]t1 & [B&C]t2)
|
||||
retainOtherTargets.remove(target);
|
||||
if (!retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s1 = RouteSpecificationByTargets.all(retainOtherTargets, os.getEnd());
|
||||
res.add(s1);
|
||||
}
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
for (T intersectTarget : intersectTargets) {
|
||||
Collection<T> its = new ArrayList<>(intersectTargets);
|
||||
its.remove(intersectTarget);
|
||||
RouteSpecification<T> s2 = new RouteSpecificationByPair<>(Collections.singleton(intersectTarget), target, spec.getEnd());
|
||||
if (!its.isEmpty()){
|
||||
RouteSpecification<T> s3 = RouteSpecificationByTargets.all(its, os.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
} else {
|
||||
orSpec.mix(s2);
|
||||
}
|
||||
}
|
||||
if (!retainTargets.isEmpty()){
|
||||
RouteSpecification<T> s4 = new RouteSpecificationByPair<>(retainTargets, target, spec.getEnd());
|
||||
if (!intersectTargets.isEmpty()){
|
||||
RouteSpecification<T> s5 = RouteSpecificationByTargets.all(intersectTargets, os.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s4,s5));
|
||||
} else {
|
||||
orSpec.mix(s4);
|
||||
}
|
||||
}
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
//[B,C,D,E - A]t2 & [A&B&C]t1 -> ([&B]t1 & [C - A]t1) | ([&C]t1 & [B - A]t1) | ([B&C]t1 & [D,E - A]t1) | ([A&B&C]t1 & [A][t1-t2])
|
||||
//[B,C,D - E]t2 & [A&B&C]t1 -> [&A]t1 & (([&B]t1 & [C - E]t1) | ([&C]t1 & [B - E]t1) | ([B&C]t1 & [D - E]t1) | ([B&C]t1 & [E][t1-t2]))
|
||||
retainOtherTargets.remove(target);
|
||||
if (!retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s1 = RouteSpecificationByTargets.all(retainOtherTargets, os.getEnd());
|
||||
res.add(s1);
|
||||
}
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
for (T intersectTarget : intersectTargets) {
|
||||
Collection<T> its = new ArrayList<>(intersectTargets);
|
||||
its.remove(intersectTarget);
|
||||
RouteSpecification<T> s2 = new RouteSpecificationByPair<>(Collections.singleton(intersectTarget), target, os.getEnd());
|
||||
if (!its.isEmpty()){
|
||||
RouteSpecification<T> s3 = RouteSpecificationByTargets.all(its, os.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
} else {
|
||||
orSpec.mix(s2);
|
||||
}
|
||||
}
|
||||
if (!retainTargets.isEmpty()){
|
||||
RouteSpecification<T> s4 = new RouteSpecificationByPair<>(retainTargets, target, os.getEnd());
|
||||
RouteSpecification<T> s5 = RouteSpecificationByTargets.all(intersectTargets, os.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s4,s5));
|
||||
}
|
||||
if (!intersectTargets.isEmpty()){
|
||||
Collection<T> targets6 = new ArrayList<>(intersectTargets);
|
||||
if (otherTargets.contains(target)) targets6.add(target);
|
||||
RouteSpecification<T> s6 = RouteSpecificationByTargets.all(targets6, os.getEnd());
|
||||
RouteSpecification<T> s7 = RouteSpecificationByTargets.containAny(Collections.singleton(target), os.getEnd(), spec.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s6,s7));
|
||||
}
|
||||
res.add(orSpec);
|
||||
}
|
||||
} else {
|
||||
//[A,B,C - D]t1 & [E&F]t2 -> [A,B,C - D]t1 & [E&F]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else
|
||||
if (os.isAny()){
|
||||
long time = Math.min(spec.getEnd(), os.getEnd());
|
||||
if (otherTargets.contains(target)){
|
||||
//[A,B,C,F - D]t1 & [B|C|D|E]t2 -> ([A,B,C,F]t1 & Dt1) | ([A,B,C,F - D]t1 & [B|C|E]t2)
|
||||
//[A,B,C,F - D]t2 & [B|C|D|E]t1 -> ([A,B,C,F]t1 & Dt1) | ([A,B,C,F - D]t1 & [B|C|E]t1)
|
||||
RouteSpecification<T> s1 = RouteSpecificationByTargets.containAny(targets, time);
|
||||
RouteSpecification<T> s2 = new RouteSpecificationByTarget<>(target, time);
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(otherTargets); // B,C,E
|
||||
retainOtherTargets.remove(target);
|
||||
if (!retainOtherTargets.isEmpty()){
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s1,s2));
|
||||
RouteSpecification<T> s3 = new RouteSpecificationByPair<>(targets, target, time);
|
||||
RouteSpecification<T> s4 = RouteSpecificationByTargets.any(retainOtherTargets, os.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s3,s4));
|
||||
} else {
|
||||
res.add(s1);
|
||||
res.add(s2);
|
||||
}
|
||||
} else {
|
||||
//[A,B,C,D - F]t1 & [B|C|E]t2 -> [A,B,C,D - F]t1 & [B|C|E]t2
|
||||
//[A,B,C,D - F]t2 & [B|C|E]t1 -> [A,B,C,D - F]t1 & [B|C|E]t1
|
||||
//[A,B,C - D] & [E|F] -> [A,B,C - D] & [E|F]
|
||||
RouteSpecification<T> s1 = new RouteSpecificationByPair<>(targets, target, time);
|
||||
res.add(s1);
|
||||
res.add(os);
|
||||
}
|
||||
} else {
|
||||
if (otherTargets.contains(target)){
|
||||
//[A,B,C - D]t1 & [B,C,D,E]t2 -> [A,B,C - D]t1
|
||||
if (spec.getEnd() <= os.getEnd()){
|
||||
res.add(spec);
|
||||
} else {
|
||||
Collection<T> intersectTargets = new ArrayList<>(targets); //B,C
|
||||
intersectTargets.retainAll(otherTargets);
|
||||
if (!intersectTargets.isEmpty()){
|
||||
//[B,C,D - A]t2 & [A,B,C]t1 -> [B,C,D - A]t1 | ([B,C]t1 & [A][t1-t2])
|
||||
RouteSpecification<T> s1 = new RouteSpecificationByPair<>(targets, target, os.getEnd());
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
orSpec.mix(s1);
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.containAny(intersectTargets, os.getEnd());
|
||||
RouteSpecification<T> s3 = RouteSpecificationByTargets.containAny(Collections.singleton(target), os.getEnd(), spec.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
//[B,C,D - A]t2 & [A,E,F]t1 -> [B,C,D - A]t1 | ([E,F]t1 & [B,C,D - A][t1-t2])
|
||||
RouteSpecification<T> s1 = new RouteSpecificationByPair<>(targets, target, os.getEnd());
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(otherTargets);
|
||||
retainOtherTargets.remove(target);
|
||||
if (!retainOtherTargets.isEmpty()){
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
orSpec.mix(s1);
|
||||
RouteSpecification<T> s2 = RouteSpecificationByTargets.containAny(otherTargets, os.getEnd());
|
||||
RouteSpecification<T> s3 = new RouteSpecificationByPair<>(targets, target, os.getEnd(), spec.getEnd());
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
res.add(s1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Collection<T> intersectTargets = new ArrayList<>(); //B,C
|
||||
Collection<T> retainTargets = new ArrayList<>(); //A
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(); //D,E
|
||||
split(targets, otherTargets, intersectTargets, retainTargets, retainOtherTargets);
|
||||
if (!intersectTargets.isEmpty()){
|
||||
//[A,B,C - F]t1 & [B,C,D,E]t2 -> [B,C - F]t1 | ([A - F]t1 & [D,E]t2)
|
||||
//[B,C,D - E]t2 & [A,B,C]t1 -> [B,C - E]t1 | ([D - E]t2 & [,A]t1 )
|
||||
long time = Math.min(spec.getEnd(), os.getEnd());
|
||||
RouteSpecification<T> s1 = new RouteSpecificationByPair<>(intersectTargets, target, time);
|
||||
if (!retainTargets.isEmpty() && !retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s2 = new RouteSpecificationByPair<>(retainTargets, target, spec.getEnd());
|
||||
RouteSpecification<T> s3 = RouteSpecificationByTargets.containAny(retainOtherTargets, os.getEnd());
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
orSpec.mix(s1);
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
res.add(s1);
|
||||
}
|
||||
} else {
|
||||
//[A,B,C - F]t1 & [G,H,I]t2 -> [A,B,C - F]t1 & [G,H,I]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (other instanceof RouteSpecificationByPair){
|
||||
RouteSpecificationByPair<T> os = ((RouteSpecificationByPair<T>)other);
|
||||
Collection<T> otherTargets = os.getTargets();
|
||||
T otherTarget = os.getTarget();
|
||||
if (os.getEnd() < spec.getEnd()){
|
||||
return andMix(os, spec);
|
||||
}
|
||||
if (target.equals(otherTarget)){
|
||||
//[A,B,C - F]t1 & [B,C,D - F]t2 -> [B,C - F]t1 | ([A - F]t1 & [D - F]t2)
|
||||
Collection<T> intersectTargets = new ArrayList<>(); //B,C
|
||||
Collection<T> retainTargets = new ArrayList<>(); //A
|
||||
Collection<T> retainOtherTargets = new ArrayList<>(); //D
|
||||
split(targets, otherTargets, intersectTargets, retainTargets, retainOtherTargets);
|
||||
if (!intersectTargets.isEmpty()){
|
||||
RouteSpecification<T> s1 = new RouteSpecificationByPair<>(intersectTargets, target, spec.getEnd());
|
||||
if (!retainTargets.isEmpty() && !retainOtherTargets.isEmpty()){
|
||||
RouteSpecification<T> s2 = new RouteSpecificationByPair<>(retainTargets, target, spec.getEnd());
|
||||
RouteSpecification<T> s3 = new RouteSpecificationByPair<>(retainOtherTargets, target, os.getEnd());
|
||||
RouteSpecificationOrMixer<T> orSpec = new RouteSpecificationOrMixer<>();
|
||||
orSpec.mix(s1);
|
||||
orSpec.mix(new RouteSpecificationAndMixer<>(s2,s3));
|
||||
res.add(orSpec);
|
||||
} else {
|
||||
res.add(s1);
|
||||
}
|
||||
} else {
|
||||
//[A,B,C - F]t1 & [D,E - F]t2 -> [A,B,C - F]t1 & [D,E - F]t2
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
//[A,B,C - D]t1 & [B,C,D - E]t2 -> [B,C - D]t1 & [- E]) | ([A - D] & [B,C - E])
|
||||
//[A,B,C - E]t1 & [B,C,D - A]t2 -> ([B,C - D - E]) | ([A - D] & [B,C - E])
|
||||
//[A,B,C - D]t1 & [B,C,E - G]t2 -> ([B,C - D - E]) | ([A - D] & [B,C - E])
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public static <T> Collection<RouteSpecification<T>> andMix(RouteSpecification<T> spec, RouteSpecification<T> other) {
|
||||
if (spec instanceof NullRouteSpecification || other instanceof NullRouteSpecification){
|
||||
RouteSpecification<T> res = new NullRouteSpecification<>();
|
||||
return Collections.singleton(res);
|
||||
}
|
||||
Collection<RouteSpecification<T>> res = Collections.emptyList();
|
||||
RouteSpecification<T> first = spec;
|
||||
RouteSpecification<T> second = other;
|
||||
RouteSpecification<T> adding = null;
|
||||
if (spec.getStart() != other.getStart()){
|
||||
if (spec.getStart() > other.getStart()){
|
||||
first = other;
|
||||
second = spec;
|
||||
}
|
||||
if (first.getEnd() > second.getStart()){
|
||||
adding = clone(first, first.getStart(), second.getStart());
|
||||
if (adding != null){
|
||||
first = clone(first, second.getStart(), first.getEnd());
|
||||
}
|
||||
}
|
||||
else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
if (first instanceof RouteSpecificationByTarget){
|
||||
res = andMix((RouteSpecificationByTarget<T>)first, second);
|
||||
}
|
||||
if (first instanceof RouteSpecificationByTargets){
|
||||
res = andMix((RouteSpecificationByTargets<T>)first, second);
|
||||
}
|
||||
if (first instanceof RouteSpecificationByPair){
|
||||
res = andMix((RouteSpecificationByPair<T>)first, second);
|
||||
}
|
||||
if (!res.isEmpty() && adding != null){
|
||||
res.add(new RouteSpecificationAndMixer<>(adding, second));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static <T> RouteSpecification<T> clone(RouteSpecification<T> specification, long startTime, long endTime){
|
||||
if (specification instanceof RouteSpecificationByTarget){
|
||||
RouteSpecificationByTarget<T> spec = (RouteSpecificationByTarget<T>) specification;
|
||||
return new RouteSpecificationByTarget<>(spec.getTarget(), startTime, endTime);
|
||||
}
|
||||
if (specification instanceof RouteSpecificationByTargets){
|
||||
RouteSpecificationByTargets<T> spec = (RouteSpecificationByTargets<T>) specification;
|
||||
if (spec.isAll()) return RouteSpecificationByTargets.all(spec.getTargets(), startTime, endTime);
|
||||
if (spec.isAny()) return RouteSpecificationByTargets.any(spec.getTargets(), startTime, endTime);
|
||||
return RouteSpecificationByTargets.containAny(spec.getTargets(), startTime, endTime);
|
||||
}
|
||||
if (specification instanceof RouteSpecificationByPair){
|
||||
RouteSpecificationByPair<T> spec = (RouteSpecificationByPair<T>) specification;
|
||||
return new RouteSpecificationByPair<>(spec.getTargets(), spec.getTarget(), startTime, endTime);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -3,100 +3,131 @@ 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.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public class RouteSpecificationByPair<T> implements RouteSpecification<T> {
|
||||
protected final Collection<T> first;
|
||||
protected final T second;
|
||||
protected final long time;
|
||||
private boolean checkSecond;
|
||||
private final Collection<T> first;
|
||||
private final T second;
|
||||
private final long start;
|
||||
private final long end;
|
||||
|
||||
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;
|
||||
this(Collections.singleton(first), second, 0, time);
|
||||
}
|
||||
|
||||
public RouteSpecificationByPair(Collection<T> first, T second) {
|
||||
this(first, second, Long.MAX_VALUE);
|
||||
this(first, second, 0, Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
public RouteSpecificationByPair(Collection<T> first, T second, long time) {
|
||||
this.first = new ArrayList<>(first);
|
||||
this(first, second, 0, time);
|
||||
}
|
||||
|
||||
public RouteSpecificationByPair(Collection<T> first, T second, long startTime, long endTime) {
|
||||
this.first = new HashSet<>(first);
|
||||
this.second = second;
|
||||
this.time = time;
|
||||
checkSecond = true;
|
||||
this.start = startTime;
|
||||
this.end = endTime;
|
||||
|
||||
}
|
||||
|
||||
public T getTarget(){
|
||||
return second;
|
||||
}
|
||||
|
||||
public Collection<T> getTargets(){
|
||||
return first;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
private boolean checkTime(){
|
||||
return time < Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
protected void remove(){
|
||||
checkSecond = false;
|
||||
return end < Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specified(Edge<T> edge, Traversal<T> entry) {
|
||||
return searchPair(edge, entry) == 0;
|
||||
return searchPair(edge, entry, false) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean content(Edge<T> edge, Traversal<T> entry) {
|
||||
if (checkTime() && edge.getTime() + entry.getTime() > time) return false;
|
||||
if (checkTime()){
|
||||
long time = edge.getTime();
|
||||
if (time < start || time > end) return false;
|
||||
}
|
||||
T obj = edge.getTarget().getEntry();
|
||||
return second.equals(obj) || first.contains(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastFound(Edge<T> edge, Traversal<T> entry) {
|
||||
return searchPair(edge, entry);
|
||||
return searchPair(edge, entry, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int matchCount() {
|
||||
return checkSecond ? 2 : 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
private int searchPair(Edge<T> edge, Traversal<T> entry){
|
||||
private int searchPair(Edge<T> edge, Traversal<T> entry, boolean full){
|
||||
int fIndex = -1;
|
||||
int sIndex = -1;
|
||||
List<Traversal<T>> entries = entry.toList();
|
||||
int max = entries.size();
|
||||
for (int i = 0; i < max; i++) {
|
||||
Traversal<T> e = entries.get(i);
|
||||
|
||||
T obj = edge.getTarget().getEntry();
|
||||
boolean check = true;
|
||||
if (checkTime()){
|
||||
long time = edge.getTime();
|
||||
if (time < start || time > end) check = false;
|
||||
}
|
||||
if (check){
|
||||
if (second.equals(obj)){
|
||||
sIndex = 0;
|
||||
} else
|
||||
if (first.contains(obj)){
|
||||
fIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
Optional<Traversal<T>> t = Optional.of(entry);
|
||||
while (t.isPresent()){
|
||||
i++;
|
||||
Traversal<T> e = t.get();
|
||||
t = e.getHead();
|
||||
if (checkTime()){
|
||||
long time = e.getTime();
|
||||
if (time > end) continue;
|
||||
if (time < start) break;
|
||||
}
|
||||
T target = e.getTarget().getEntry();
|
||||
if (second.equals(target)){
|
||||
if (checkTime() && e.getTime() > time) return checkSecond ? 2 : 1;
|
||||
if (sIndex == -1 && second.equals(target)){
|
||||
sIndex = i;
|
||||
}
|
||||
if (sIndex != -1 && fIndex != -1 && fIndex <= sIndex){
|
||||
//low index last
|
||||
if (sIndex != -1 && fIndex != -1 && fIndex >= sIndex){
|
||||
return 0;
|
||||
}
|
||||
if (fIndex == -1 && first.contains(target)){
|
||||
if ((full || sIndex != -1) && fIndex == -1 && first.contains(target)){
|
||||
fIndex = 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 checkSecond ? 1 : 0;
|
||||
return fIndex <= sIndex ? 0 : 1;
|
||||
|
||||
if (sIndex == -1 && fIndex != -1) return 1;
|
||||
if (fIndex == -1) return 2;
|
||||
return fIndex >= sIndex ? 0 : 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,34 +4,49 @@ import ru.trader.analysis.graph.Edge;
|
||||
import ru.trader.analysis.graph.Traversal;
|
||||
|
||||
public class RouteSpecificationByTarget<T> implements RouteSpecification<T> {
|
||||
private T target;
|
||||
protected final long time;
|
||||
private final T target;
|
||||
private final long start;
|
||||
private final long end;
|
||||
|
||||
public RouteSpecificationByTarget(T target) {
|
||||
this(target, Long.MAX_VALUE);
|
||||
this(target, 0, Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
public RouteSpecificationByTarget(T target, long time) {
|
||||
this(target, 0, time);
|
||||
}
|
||||
|
||||
public RouteSpecificationByTarget(T target, long startTime, long endTime) {
|
||||
this.target = target;
|
||||
this.time = time;
|
||||
this.start = startTime;
|
||||
this.end = endTime;
|
||||
}
|
||||
|
||||
private boolean checkTime(){
|
||||
return time < Long.MAX_VALUE;
|
||||
return end < Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
protected T getTarget(){
|
||||
public T getTarget(){
|
||||
return target;
|
||||
}
|
||||
|
||||
protected void remove(){
|
||||
target = null;
|
||||
@Override
|
||||
public long getStart(){
|
||||
return start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEnd(){
|
||||
return end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specified(Edge<T> edge, Traversal<T> entry) {
|
||||
if (target == null) return true;
|
||||
if (checkTime() && edge.getTime() + entry.getTime() > time) return false;
|
||||
if (checkTime()){
|
||||
long time = edge.getTime();
|
||||
if (time < start || time > end) return false;
|
||||
}
|
||||
return edge.isConnect(target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,39 +6,76 @@ import ru.trader.analysis.graph.Traversal;
|
||||
import java.util.*;
|
||||
|
||||
public class RouteSpecificationByTargets<T> implements RouteSpecification<T> {
|
||||
protected final Collection<T> targets;
|
||||
protected final boolean all;
|
||||
protected final boolean targetOnly;
|
||||
protected final long time;
|
||||
private final Collection<T> targets;
|
||||
private final boolean all;
|
||||
private final boolean targetOnly;
|
||||
private final long start;
|
||||
private final long end;
|
||||
|
||||
protected RouteSpecificationByTargets(Collection<T> targets, long time, boolean all, boolean targetOnly) {
|
||||
private RouteSpecificationByTargets(Collection<T> targets, long startTime, long endTime, boolean all, boolean targetOnly) {
|
||||
this.all = all;
|
||||
this.targetOnly = targetOnly;
|
||||
this.targets = new HashSet<>(targets);
|
||||
this.time = time;
|
||||
this.start = startTime;
|
||||
this.end = endTime;
|
||||
}
|
||||
|
||||
private boolean checkTime(){
|
||||
return time < Long.MAX_VALUE;
|
||||
return end < Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
public Collection<T> getTargets(){
|
||||
return targets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public boolean isAny(){
|
||||
return targetOnly;
|
||||
}
|
||||
|
||||
public boolean isAll(){
|
||||
return all;
|
||||
}
|
||||
|
||||
public boolean isContainAny(){
|
||||
return !targetOnly && !all;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specified(Edge<T> edge, Traversal<T> entry) {
|
||||
if (targets.isEmpty()) return true;
|
||||
if (checkTime() && targetOnly && edge.getTime() + entry.getTime() > time) return false;
|
||||
if (checkTime()){
|
||||
long time = edge.getTime();
|
||||
if (targetOnly && (time < start || time > end)) return false;
|
||||
}
|
||||
return all ? containsAll(edge, entry) == 0 : containsAny(edge, entry) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean content(Edge<T> edge, Traversal<T> entry) {
|
||||
if (checkTime() && edge.getTime() + entry.getTime() > time) return false;
|
||||
if (checkTime()){
|
||||
long time = edge.getTime();
|
||||
if (time < start || time > end) return false;
|
||||
}
|
||||
return targets.contains(edge.getTarget().getEntry());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastFound(Edge<T> edge, Traversal<T> entry) {
|
||||
if (targets.isEmpty()) return 0;
|
||||
if (checkTime() && targetOnly && edge.getTime() + entry.getTime() > time) return matchCount();
|
||||
if (checkTime()){
|
||||
long time = edge.getTime();
|
||||
if (targetOnly && (time < start || time > end)) return matchCount();
|
||||
}
|
||||
return all ? containsAll(edge, entry) : containsAny(edge, entry);
|
||||
}
|
||||
|
||||
@@ -50,53 +87,64 @@ public class RouteSpecificationByTargets<T> implements RouteSpecification<T> {
|
||||
|
||||
private int containsAll(Edge<T> edge, Traversal<T> entry) {
|
||||
Collection<T> founds = new HashSet<>();
|
||||
List<Traversal<T>> entries = entry.toList();
|
||||
for (Traversal<T> e : entries) {
|
||||
|
||||
Optional<Traversal<T>> t = Optional.of(entry);
|
||||
while (t.isPresent()){
|
||||
Traversal<T> e = t.get();
|
||||
t = e.getHead();
|
||||
if (checkTime()){
|
||||
long time = e.getTime();
|
||||
if (time > end) continue;
|
||||
if (time < start) break;
|
||||
}
|
||||
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);
|
||||
if (checkTime()){
|
||||
long time = edge.getTime();
|
||||
if (time < start || time > end) return targets.size() - founds.size();
|
||||
}
|
||||
if (targets.contains(target)){
|
||||
founds.add(target);
|
||||
}
|
||||
return targets.size() - founds.size();
|
||||
}
|
||||
|
||||
private int containsAny(Edge<T> edge, Traversal<T> entry) {
|
||||
T obj = edge.getTarget().getEntry();
|
||||
if (targets.contains(obj)){
|
||||
if (targetOnly){
|
||||
if (checkTime() && edge.getTime() + entry.getTime() > time) return 1;
|
||||
else return 0;
|
||||
} else {
|
||||
return 0;
|
||||
boolean check = true;
|
||||
if (checkTime()){
|
||||
long time = edge.getTime();
|
||||
if (time < start || time > end){
|
||||
if (targetOnly) return 1;
|
||||
check = false;
|
||||
}
|
||||
}
|
||||
if (check && targets.contains(obj)){
|
||||
return 0;
|
||||
}
|
||||
if (targetOnly){
|
||||
return 1;
|
||||
}
|
||||
List<Traversal<T>> entries = entry.toList();
|
||||
for (Traversal<T> e : entries) {
|
||||
Optional<Traversal<T>> t = Optional.of(entry);
|
||||
while (t.isPresent()){
|
||||
Traversal<T> e = t.get();
|
||||
t = e.getHead();
|
||||
if (checkTime()){
|
||||
long time = e.getTime();
|
||||
if (time > end) continue;
|
||||
if (time < start) break;
|
||||
}
|
||||
T target = e.getTarget().getEntry();
|
||||
if (targets.contains(target)){
|
||||
if (checkTime() && e.getTime() > time){
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -105,7 +153,11 @@ public class RouteSpecificationByTargets<T> implements RouteSpecification<T> {
|
||||
}
|
||||
|
||||
public static <T> RouteSpecificationByTargets<T> all(Collection<T> targets, long time){
|
||||
return new RouteSpecificationByTargets<>(targets, time, true, false);
|
||||
return new RouteSpecificationByTargets<>(targets, 0, time, true, false);
|
||||
}
|
||||
|
||||
public static <T> RouteSpecificationByTargets<T> all(Collection<T> targets, long startTime, long endTime){
|
||||
return new RouteSpecificationByTargets<>(targets, startTime, endTime, true, false);
|
||||
}
|
||||
|
||||
public static <T> RouteSpecificationByTargets<T> any(Collection<T> targets){
|
||||
@@ -113,7 +165,11 @@ public class RouteSpecificationByTargets<T> implements RouteSpecification<T> {
|
||||
}
|
||||
|
||||
public static <T> RouteSpecificationByTargets<T> any(Collection<T> targets, long time){
|
||||
return new RouteSpecificationByTargets<>(targets, time, false, true);
|
||||
return new RouteSpecificationByTargets<>(targets, 0, time, false, true);
|
||||
}
|
||||
|
||||
public static <T> RouteSpecificationByTargets<T> any(Collection<T> targets, long startTime, long endTime){
|
||||
return new RouteSpecificationByTargets<>(targets, startTime, endTime, false, true);
|
||||
}
|
||||
|
||||
public static <T> RouteSpecificationByTargets<T> containAny(Collection<T> targets){
|
||||
@@ -121,6 +177,10 @@ public class RouteSpecificationByTargets<T> implements RouteSpecification<T> {
|
||||
}
|
||||
|
||||
public static <T> RouteSpecificationByTargets<T> containAny(Collection<T> targets, long time){
|
||||
return new RouteSpecificationByTargets<>(targets, time, false, false);
|
||||
return new RouteSpecificationByTargets<>(targets, 0, time, false, false);
|
||||
}
|
||||
|
||||
public static <T> RouteSpecificationByTargets<T> containAny(Collection<T> targets, long startTime, long endTime){
|
||||
return new RouteSpecificationByTargets<>(targets, startTime, endTime, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,130 +2,9 @@ package ru.trader.analysis;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class RouteSpecificationMixer {
|
||||
public static <T> void andMix(RouteSpecificationByTargets<T> spec, RouteSpecification<T> other) {
|
||||
if (other instanceof RouteSpecificationByTarget){
|
||||
RouteSpecificationByTarget<T> os = (RouteSpecificationByTarget<T>)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<T> os = ((RouteSpecificationByTargets<T>)other);
|
||||
if (os.all){
|
||||
Collection<T> 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<T> os = (RouteSpecificationByPair<T>)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 <T> void andMix(RouteSpecificationByTarget<T> spec, RouteSpecification<T> other) {
|
||||
if (other instanceof RouteSpecificationByTarget){
|
||||
RouteSpecificationByTarget<T> os = (RouteSpecificationByTarget<T>)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<T> os = ((RouteSpecificationByTargets<T>)other);
|
||||
if (os.all){
|
||||
Collection<T> 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<T> os = (RouteSpecificationByPair<T>)other;
|
||||
T otherTarget = os.second;
|
||||
if (spec.getTarget() == otherTarget){
|
||||
if (os.time < spec.time){
|
||||
spec.remove();
|
||||
} else {
|
||||
os.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void andMix(RouteSpecificationByPair<T> spec, RouteSpecification<T> other) {
|
||||
if (other instanceof RouteSpecificationByTarget){
|
||||
RouteSpecificationByTarget<T> os = (RouteSpecificationByTarget<T>)other;
|
||||
T otherTarget = os.getTarget();
|
||||
if (spec.second == otherTarget){
|
||||
if (os.time >= spec.time) {
|
||||
os.remove();
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (other instanceof RouteSpecificationByTargets){
|
||||
RouteSpecificationByTargets<T> os = ((RouteSpecificationByTargets<T>)other);
|
||||
if (os.targetOnly){
|
||||
Collection<T> otherTargets = os.targets;
|
||||
if (otherTargets.contains(spec.second)){
|
||||
if (os.time >= spec.time) {
|
||||
os.targets.remove(spec.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (other instanceof RouteSpecificationByPair){
|
||||
RouteSpecificationByPair<T> os = (RouteSpecificationByPair<T>)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 <T> void andMix(RouteSpecification<T> spec, RouteSpecification<T> other) {
|
||||
if (spec instanceof RouteSpecificationByTarget){
|
||||
andMix((RouteSpecificationByTarget<T>)spec, other);
|
||||
} else
|
||||
if (spec instanceof RouteSpecificationByTargets){
|
||||
andMix((RouteSpecificationByTargets<T>)spec, other);
|
||||
} else
|
||||
if (spec instanceof RouteSpecificationByPair){
|
||||
andMix((RouteSpecificationByPair<T>)spec, other);
|
||||
}
|
||||
|
||||
}
|
||||
public interface RouteSpecificationMixer<T> {
|
||||
|
||||
RouteSpecification<T> mix(RouteSpecification<T> specification);
|
||||
Collection<RouteSpecification<T>> getMixed();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
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.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class RouteSpecificationOrMixer<T> implements RouteSpecificationMixer<T>, RouteSpecification<T> {
|
||||
|
||||
private final List<RouteSpecification<T>> specifications;
|
||||
|
||||
public RouteSpecificationOrMixer() {
|
||||
this.specifications = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RouteSpecification<T>> getMixed() {
|
||||
return specifications;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean specified(Edge<T> edge, Traversal<T> entry) {
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
if (specification.specified(edge, entry)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean content(Edge<T> edge, Traversal<T> entry) {
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
if (specification.content(edge, entry)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lastFound(Edge<T> edge, Traversal<T> entry) {
|
||||
int res = Integer.MAX_VALUE;
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
res = Math.min(res, specification.lastFound(edge, entry));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int matchCount() {
|
||||
int res = Integer.MAX_VALUE;
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
res = Math.min(res, specification.matchCount());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateMutated() {
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
if (specification.updateMutated()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mutable() {
|
||||
for (RouteSpecification<T> specification : specifications) {
|
||||
if (specification.mutable()){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Traversal<T> entry) {
|
||||
specifications.forEach(s -> s.update(entry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouteSpecification<T> and(RouteSpecification<T> specification) {
|
||||
Collection<RouteSpecification<T>> res = new ArrayList<>(specifications.size());
|
||||
for (RouteSpecification<T> s : specifications) {
|
||||
res.add(RouteSpecificationAndMixer.mix(s, specification));
|
||||
}
|
||||
specifications.clear();
|
||||
specifications.addAll(res);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouteSpecification<T> or(RouteSpecification<T> other) {
|
||||
return this.mix(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RouteSpecification<T> mix(RouteSpecification<T> specification) {
|
||||
if (specification instanceof NullRouteSpecification) return this;
|
||||
specifications.add(specification);
|
||||
specifications.sort(ROUTE_SPECIFICATION_COMPARATOR);
|
||||
return this;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> RouteSpecification<T> mix(RouteSpecification<T> ... specification){
|
||||
RouteSpecificationOrMixer<T> res = new RouteSpecificationOrMixer<>();
|
||||
for (RouteSpecification<T> s : specification) {
|
||||
res.mix(s);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
public final static RouteSpecificationComparator ROUTE_SPECIFICATION_COMPARATOR = new RouteSpecificationComparator();
|
||||
|
||||
private static class RouteSpecificationComparator implements Comparator<RouteSpecification> {
|
||||
|
||||
private int getHard(RouteSpecification specification){
|
||||
if (specification instanceof RouteSpecificationByTarget){
|
||||
return 1;
|
||||
}
|
||||
if (specification instanceof RouteSpecificationByTargets){
|
||||
RouteSpecificationByTargets s = (RouteSpecificationByTargets) specification;
|
||||
if (s.isAny()){
|
||||
return 2;
|
||||
}
|
||||
return s.isContainAny() ? 3 : 5;
|
||||
}
|
||||
if (specification instanceof RouteSpecificationByPair){
|
||||
return 4;
|
||||
}
|
||||
if (specification instanceof LoopRouteSpecification){
|
||||
return 4;
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(RouteSpecification o1, RouteSpecification o2) {
|
||||
int hard1 = getHard(o1);
|
||||
int hard2 = getHard(o2);
|
||||
int cmp = Integer.compare(hard1, hard2);
|
||||
if (cmp != 0) return cmp;
|
||||
return Integer.compare(o1.matchCount(), o2.matchCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,4 +213,56 @@ public class CrawlerSpecificatorTest extends Assert{
|
||||
paths.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMix() throws Exception {
|
||||
LOG.info("Test Mix");
|
||||
|
||||
// target A = A
|
||||
// contains A and B and C = [A&B&C]
|
||||
// target A or B or C = [A|B|C]
|
||||
// contains A or B or C = [A,B,C]
|
||||
// pair A or B or C to D = [A,B,C - D]
|
||||
|
||||
//A & A -> A
|
||||
//A & [A,B,C] -> A
|
||||
//A & [B,C] -> A & [B,C]
|
||||
//A & [A|B|C] -> A
|
||||
//A & [A&B&C] -> A & [B&C]
|
||||
//A & [A,B,C - D] -> A & [A,B,C - D]
|
||||
//A & [B,C - A] -> A & [B,C]
|
||||
|
||||
//[A,B,C] & A -> A & [B,C]
|
||||
//[A,B,C] & [B,C,D] -> [A,B,C,D]
|
||||
//[A,B,C] & [B|C|D] -> [B|C] | ([A] & D)
|
||||
//[A,B,C] & [B&C&D] -> [B&C&D]
|
||||
//[A,B,C] & [B,C,D - E] -> [B,C - E] | ([A] & [D - E])
|
||||
//[A,B,C] & [B,C,D - A] -> [B,C,D - A]
|
||||
|
||||
//[A|B|C] & A -> A
|
||||
//[A|B|C] & [B,C,D] -> ([D] & A) | ([B|C])
|
||||
//[A|B|C] & [B|C|D] -> [A|B|C|D]
|
||||
//[A|B|C] & [B&C&D] -> (A & [B&C]) | (B & [C&D]) | (C & [B&D])
|
||||
//[A|B|C] & [B,C,D - E] -> [A|B|C] & [B,C,D - E]
|
||||
//[A|B|C] & [B,C,D - A] -> (A & [B,C,D]) | ([B|C] & [B,C,D - A])
|
||||
|
||||
//[A&B&C] & A -> A & [B&C]
|
||||
//[A&B&C] & [B,C,D] -> [A&B&C]
|
||||
//[A&B&C] & [B|C|D] -> ([A&C] & B) | ([A&B] & C) | ([A&B&C] & D)
|
||||
//[A&B&C] & [B&C&D] -> [A&B&C&D]
|
||||
//[A&B&C] & [B,C,D - E] -> ([A&C] & [B - E]) | ([A&B] & [C - E]) | ([A&B&C] & [D - E])
|
||||
//[A&B&C] & [B,C,D,E - A] -> ([B&C] & [D,E - A]) | ([C] & [B - A])
|
||||
|
||||
//[A,B,C - D] & A -> [A,B,C - D] & A
|
||||
//[A,B,C - D] & D -> [A,B,C] & D
|
||||
//[A,B,C - D] & [B,C,D,E] -> [A,B,C - D]
|
||||
//[A,B,C - F] & [B,C,D,E] -> ([A - F] & [D,E]) | [B,C - F]
|
||||
//[A,B,C - D] & [B|C|D|E] -> ([A,B,C - D] & D) | ([A,B,C - D] & [B|C|E])
|
||||
//[A,B,C - F] & [B|C|D|E] -> [A,B,C - F] & [B|C|D|E]
|
||||
//[A,B,C - D] & [B&C&D&E] -> ([B - D] & [C&E]) | ([C - D] & [B&E]) | ([A - D] & [B&C&E])
|
||||
//[A,B,C - F] & [B&C&D&E] -> ([B - F] & [C&D&E]) | ([C - F] & [B&D&E]) | ([A - F] & [B&C&D&E])
|
||||
//[A,B,C - D] & [B,C,D - E] -> ([B,C - D - E]) | ([A - D] & [B,C - E])
|
||||
//[A,B,C - F] & [B,C,D - F] -> [B,C - F] | ([A - D - F]) | ([D - A - F])
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user