Archived
0

improve search with complex specification

This commit is contained in:
iMoHax
2015-12-30 15:04:32 +03:00
parent 68c303d040
commit 54e31697a8
9 changed files with 1232 additions and 368 deletions

View File

@@ -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;
}
}

View File

@@ -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);
}
@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);
}
};
if (other instanceof RouteSpecificationAndMixer){
((RouteSpecificationAndMixer<T>) other).mix(this);
return other;
}
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);
}
@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);
}
};
if (other instanceof RouteSpecificationOrMixer){
((RouteSpecificationOrMixer<T>) other).mix(this);
return other;
}
return RouteSpecificationOrMixer.mix(this, other);
}
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);
}
};
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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,51 +87,62 @@ 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);
}
founds.add(target);
}
if (targets.size() == founds.size()) return 0;
}
T target = edge.getTarget().getEntry();
if (checkTime()){
long time = edge.getTime();
if (time < start || time > end) return targets.size() - founds.size();
}
if (targets.contains(target)){
if (checkTime() && edge.getTime() + entry.getTime() > time){
return targets.size() - founds.size();
} else {
founds.add(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 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);
}
}

View File

@@ -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();
}

View File

@@ -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());
}
}
}

View File

@@ -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])
}
}