Archived
0

PathRoute implement

This commit is contained in:
iMoHax
2014-08-17 14:01:33 +04:00
parent 5fcf43b0a0
commit 7d15c8461b
5 changed files with 338 additions and 41 deletions

View File

@@ -40,10 +40,6 @@ public class Order implements Comparable<Order> {
return profit; return profit;
} }
public Order getCopy(long count){
return new Order(sell, buy, count);
}
public long getCount() { public long getCount() {
return count; return count;
} }
@@ -56,6 +52,10 @@ public class Order implements Comparable<Order> {
return buy.getVendor().equals(buyer); return buy.getVendor().equals(buyer);
} }
public Vendor getBuyer(){
return buy.getVendor();
}
@Override @Override
public int compareTo(@NotNull Order order) { public int compareTo(@NotNull Order order) {
Objects.requireNonNull(order, "Not compare with null"); Objects.requireNonNull(order, "Not compare with null");
@@ -100,4 +100,7 @@ public class Order implements Comparable<Order> {
return sb.toString(); return sb.toString();
} }
public void setMax(double balance, long limit) {
setCount((long) Math.min(balance/sell.getPrice(), limit));
}
} }

View File

@@ -113,7 +113,7 @@ public class Graph<T extends Connectable<T>> {
if (edge != null ){ if (edge != null ){
if (!(withRefill && Math.min(limit, maxDistance) < edge.getLength() && !source.getEntry().canRefill())){ if (!(withRefill && Math.min(limit, maxDistance) < edge.getLength() && !source.getEntry().canRefill())){
found = true; found = true;
Path<T> path = head.connectTo(edge, limit < edge.getLength()); Path<T> path = head.connectTo(edge.getTarget(), limit < edge.getLength());
path.finish(); path.finish();
LOG.trace("Last edge find, add path {}", path); LOG.trace("Last edge find, add path {}", path);
paths.add(path); paths.add(path);
@@ -124,10 +124,10 @@ public class Graph<T extends Connectable<T>> {
LOG.trace("Search around"); LOG.trace("Search around");
for (Edge<T> next : source.getEdges()) { for (Edge<T> next : source.getEdges()) {
if (withRefill && Math.min(limit, maxDistance) < next.getLength() && !source.getEntry().canRefill()) continue; if (withRefill && Math.min(limit, maxDistance) < next.getLength() && !source.getEntry().canRefill()) continue;
if (head.contains(next)) continue; if (head.isConnect(next.getTarget())) continue;
// target already added if source consist edge // target already added if source consist edge
if (next.isConnect(target)) continue; if (next.isConnect(target)) continue;
Path<T> path = head.connectTo(next, limit < next.getLength()); Path<T> path = head.connectTo(next.getTarget(), limit < next.getLength());
double nextLimit = withRefill ? limit - next.getLength(): stock; double nextLimit = withRefill ? limit - next.getLength(): stock;
// refill // refill
if (nextLimit < 0 ) nextLimit = maxDistance - next.getLength(); if (nextLimit < 0 ) nextLimit = maxDistance - next.getLength();
@@ -151,9 +151,9 @@ public class Graph<T extends Connectable<T>> {
if (deep == source.getLevel()){ if (deep == source.getLevel()){
for (Edge<T> next : source.getEdges()) { for (Edge<T> next : source.getEdges()) {
if (withRefill && Math.min(limit, maxDistance) < next.getLength() && !source.getEntry().canRefill()) continue; if (withRefill && Math.min(limit, maxDistance) < next.getLength() && !source.getEntry().canRefill()) continue;
if (head.contains(next)) continue; if (head.isConnect(next.getTarget())) continue;
if (next.isConnect(target)) { if (next.isConnect(target)) {
Path<T> path = head.connectTo(next, limit < next.getLength()); Path<T> path = head.connectTo(next.getTarget(), limit < next.getLength());
path.finish(); path.finish();
LOG.trace("Last edge find, path {}", path); LOG.trace("Last edge find, path {}", path);
return path; return path;
@@ -165,7 +165,7 @@ public class Graph<T extends Connectable<T>> {
for (Edge<T> next : source.getEdges()) { for (Edge<T> next : source.getEdges()) {
if (next.getTarget().getLevel() >= source.getLevel()) continue; if (next.getTarget().getLevel() >= source.getLevel()) continue;
if (withRefill && Math.min(limit, maxDistance) < next.getLength() && !source.getEntry().canRefill()) continue; if (withRefill && Math.min(limit, maxDistance) < next.getLength() && !source.getEntry().canRefill()) continue;
Path<T> path = head.connectTo(next, limit < next.getLength()); Path<T> path = head.connectTo(next.getTarget(), limit < next.getLength());
double nextLimit = withRefill ? limit - next.getLength(): stock; double nextLimit = withRefill ? limit - next.getLength(): stock;
// refill // refill
if (nextLimit < 0 ) nextLimit = stock - next.getLength(); if (nextLimit < 0 ) nextLimit = stock - next.getLength();

View File

@@ -18,8 +18,8 @@ public class Path<T extends Connectable<T>> {
this.refill = refill; this.refill = refill;
} }
public Path<T> connectTo(Edge<T> edge, boolean refill){ public Path<T> connectTo(Vertex<T> vertex, boolean refill){
return new Path<>(this, edge.getTarget(), refill); return new Path<>(this, vertex, refill);
} }
public void finish(){ public void finish(){
@@ -37,6 +37,11 @@ public class Path<T extends Connectable<T>> {
return head == null; return head == null;
} }
public Path<T> getRoot(){
if (isRoot()) return this;
return head.getRoot();
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) return true; if (this == o) return true;
@@ -63,18 +68,21 @@ public class Path<T extends Connectable<T>> {
return sb.toString(); return sb.toString();
} }
public boolean contains(Edge<T> edge) { public boolean isConnect(Vertex<T> vertex) {
return target.equals(edge.getTarget()) || (!isRoot() && head.contains(edge)); return target.equals(vertex) || (!isRoot() && head.isConnect(vertex));
}
public boolean isPathFrom(T entry) {
return !isRoot() && head.target.getEntry().equals(entry);
} }
@SafeVarargs @SafeVarargs
public static <T extends Connectable<T>> Path<T> toPath(T... items){ public static <T extends Connectable<T>> Path<T> toPath(T... items){
T s = items[0]; T t = items[0];
Path<T> path = new Path<>(new Vertex<>(s)); Path<T> path = new Path<>(new Vertex<>(t));
for (int i = 1; i < items.length; i++) { for (int i = 1; i < items.length; i++) {
T t = items[i]; t = items[i];
path = new Path<>(path, new Vertex<>(t), false); path = new Path<>(path, new Vertex<>(t), false);
s = t;
} }
return path; return path;
} }

View File

@@ -4,25 +4,28 @@ import ru.trader.core.Offer;
import ru.trader.core.Order; import ru.trader.core.Order;
import ru.trader.core.Vendor; import ru.trader.core.Vendor;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
public class PathRoute extends Path<Vendor> { public class PathRoute extends Path<Vendor> {
private final ArrayList<Order> orders = new ArrayList<>(); private final ArrayList<Order> orders = new ArrayList<>();
private double profit = 0;
private int transitIndex = 0;
private PathRoute tail;
public PathRoute(Vertex<Vendor> source) { public PathRoute(Vertex<Vendor> source) {
super(source); super(source);
} }
protected PathRoute(Path<Vendor> head, Vertex<Vendor> vertex, boolean refill) { private PathRoute(PathRoute head, Vertex<Vendor> vertex, boolean refill) {
super(head, vertex, refill); super(head, vertex, refill);
assert head.tail == null;
head.tail = this;
} }
@Override @Override
public Path<Vendor> connectTo(Edge<Vendor> edge, boolean refill) { public Path<Vendor> connectTo(Vertex<Vendor> vertex, boolean refill) {
return new PathRoute(this.getCopy(), edge.getTarget(), refill); return new PathRoute(this.getCopy(), vertex, refill);
} }
@Override @Override
@@ -51,8 +54,8 @@ public class PathRoute extends Path<Vendor> {
} }
} }
public Collection<Order> getOrders() { public List<Order> getOrders() {
return orders; return Collections.unmodifiableList(orders);
} }
@Override @Override
@@ -61,7 +64,7 @@ public class PathRoute extends Path<Vendor> {
for (Order order : orders) { for (Order order : orders) {
if (sb.length() > 0) sb.append(", "); if (sb.length() > 0) sb.append(", ");
sb.append(order.getBuy().getItem()); sb.append(order.getBuy().getItem());
sb.append(" (").append(order.getBuy().getVendor()).append(") "); sb.append(" (").append(order.getBuyer()).append(") ");
} }
String o = sb.toString(); String o = sb.toString();
sb = new StringBuilder(); sb = new StringBuilder();
@@ -77,20 +80,85 @@ public class PathRoute extends Path<Vendor> {
return sb.toString(); return sb.toString();
} }
public Path<Vendor> getCopy(){ public boolean isEmpty(){
Path<Vendor> res; return orders.isEmpty();
LinkedList<Path<Vendor>> v = new LinkedList<>(); }
Path<Vendor> p = this;
while (!p.isRoot()){ public PathRoute getCopy(){
v.add(p); PathRoute path = (PathRoute) getRoot();
p = p.getHead(); PathRoute res = new PathRoute(path.getTarget());
} while (path.tail != null){
res = p; res = new PathRoute(res, path.tail.getTarget(), path.tail.isRefill());
Iterator<Path<Vendor>> it = v.descendingIterator(); path = path.tail;
while (it.hasNext()){
p = it.next();
res = new PathRoute(res, p.getTarget(), p.isRefill());
} }
return res; return res;
} }
public double getProfit(){
return profit;
}
public double getProfit(Order order){
if (isPathFrom(order.getBuyer())) return order.getProfit() + profit;
return tail != null ? tail.getProfit(order) : order.getProfit();
}
@Override
protected PathRoute getHead() {
return (PathRoute) super.getHead();
}
public void resort(double balance, long limit){
if (isRoot()) return;
for (Order order : orders) {
order.setMax(balance, limit);
}
orders.sort(this::compareOrders);
updateProfit();
updateTransitIndex();
getHead().resort(balance, limit);
}
private void updateTransitIndex() {
transitIndex = orders.size();
if (isEmpty()) return;
double transitProfit = tail != null ? tail.getProfit() : 0;
ListIterator<Order> itr = orders.listIterator(orders.size());
while (itr.hasPrevious()){
Order o = itr.previous();
if (getProfit(o) > transitProfit){
return;
}
transitIndex--;
}
}
private void updateProfit() {
if (isEmpty()){
profit = tail != null ? tail.getProfit() : 0;
} else {
Order best = orders.get(0);
profit = getProfit(best);
}
}
private int compareOrders(Order o1, Order o2){
if (tail == null || o1.isBuyer(o2.getBuyer())){
//reverse
return o2.compareTo(o1);
}
double profit1 = getProfit(o1);
double profit2 = getProfit(o2);
return Double.compare(profit2, profit1);
}
public PathRoute getTail() {
return tail;
}
public int getTransitIndex() {
return transitIndex;
}
} }

View File

@@ -0,0 +1,218 @@
package ru.trader.graph;
import org.junit.Assert;
import org.junit.Test;
import ru.trader.TestUtil;
import ru.trader.core.*;
import java.util.Collection;
public class PathRouteTest extends Assert {
private final static Item ITEM1 = new Item("ITEM1");
private final static Item ITEM2 = new Item("ITEM2");
private final static Item ITEM3 = new Item("ITEM3");
private static Vendor v1;
private static Vendor v2;
private static Vendor v3;
private static Vendor v4;
private static Vendor v5;
private PathRoute initTest1(){
v1 = new SimpleVendor("v1");
v2 = new SimpleVendor("v2");
v1.add(new Offer(OFFER_TYPE.SELL, ITEM1, 100));
v1.add(new Offer(OFFER_TYPE.SELL, ITEM2, 200));
v1.add(new Offer(OFFER_TYPE.SELL, ITEM3, 300));
v2.add(new Offer(OFFER_TYPE.BUY, ITEM1, 300));
v2.add(new Offer(OFFER_TYPE.BUY, ITEM2, 350));
v2.add(new Offer(OFFER_TYPE.BUY, ITEM3, 400));
PathRoute res = new PathRoute(new Vertex<>(v1));
res = (PathRoute) res.connectTo(new Vertex<>(v2), false);
res.finish();
res.resort(10000, 5);
return (PathRoute) res.getRoot();
}
@Test
public void testPathRoute1() throws Exception {
PathRoute path = initTest1().getTail();
Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5);
Order order2 = new Order(v1.getSell(ITEM2), v2.getBuy(ITEM2), 5);
Order order3 = new Order(v1.getSell(ITEM3), v2.getBuy(ITEM3), 5);
assertEquals(1000, path.getProfit(), 0.0001);
assertEquals(3, path.getTransitIndex());
TestUtil.assertCollectionEquals(orders, order1, order2, order3);
}
private PathRoute initTest2(){
v1 = new SimpleVendor("v1");
v2 = new SimpleVendor("v2");
v3 = new SimpleVendor("v3");
v1.add(new Offer(OFFER_TYPE.SELL, ITEM1, 100));
v1.add(new Offer(OFFER_TYPE.SELL, ITEM3, 300));
v2.add(new Offer(OFFER_TYPE.SELL, ITEM2, 200));
v3.add(new Offer(OFFER_TYPE.BUY, ITEM1, 300));
v3.add(new Offer(OFFER_TYPE.BUY, ITEM2, 350));
v3.add(new Offer(OFFER_TYPE.BUY, ITEM3, 400));
PathRoute res = new PathRoute(new Vertex<>(v1));
res = (PathRoute) res.connectTo(new Vertex<>(v2), false);
res = (PathRoute) res.connectTo(new Vertex<>(v3), false);
res.finish();
res.resort(10000, 5);
return (PathRoute) res.getRoot();
}
@Test
public void testPathRoute2() throws Exception {
PathRoute path = initTest2().getTail();
Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
Order order2 = new Order(v2.getSell(ITEM2), v3.getBuy(ITEM2), 5);
Order order3 = new Order(v1.getSell(ITEM3), v3.getBuy(ITEM3), 5);
assertEquals(1000, path.getProfit(), 0.0001);
assertEquals(1, path.getTransitIndex());
TestUtil.assertCollectionEquals(orders, order1, order3);
path = path.getTail();
orders = path.getOrders();
assertEquals(750, path.getProfit(), 0.0001);
assertEquals(1, path.getTransitIndex());
TestUtil.assertCollectionEquals(orders, order2);
}
private PathRoute initTest3(){
v1 = new SimpleVendor("v1");
v2 = new SimpleVendor("v2");
v3 = new SimpleVendor("v3");
v4 = new SimpleVendor("v4");
v1.add(new Offer(OFFER_TYPE.SELL, ITEM1, 100));
v1.add(new Offer(OFFER_TYPE.SELL, ITEM2, 200));
v1.add(new Offer(OFFER_TYPE.SELL, ITEM3, 300));
v2.add(new Offer(OFFER_TYPE.SELL, ITEM1, 150));
v2.add(new Offer(OFFER_TYPE.SELL, ITEM3, 320));
v3.add(new Offer(OFFER_TYPE.SELL, ITEM3, 390));
v2.add(new Offer(OFFER_TYPE.BUY, ITEM2, 230));
v3.add(new Offer(OFFER_TYPE.BUY, ITEM1, 200));
v4.add(new Offer(OFFER_TYPE.BUY, ITEM3, 450));
PathRoute res = new PathRoute(new Vertex<>(v1));
res = (PathRoute) res.connectTo(new Vertex<>(v2), false);
res = (PathRoute) res.connectTo(new Vertex<>(v3), false);
res = (PathRoute) res.connectTo(new Vertex<>(v4), false);
res.finish();
res.resort(10000, 5);
return (PathRoute) res.getRoot();
}
@Test
public void testPathRoute3() throws Exception {
PathRoute path = initTest3().getTail();
Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
Order order2 = new Order(v1.getSell(ITEM2), v2.getBuy(ITEM2), 5);
Order order3 = new Order(v1.getSell(ITEM3), v4.getBuy(ITEM3), 5);
Order order4 = new Order(v2.getSell(ITEM1), v3.getBuy(ITEM1), 5);
Order order5 = new Order(v2.getSell(ITEM3), v4.getBuy(ITEM3), 5);
Order order7 = new Order(v3.getSell(ITEM3), v4.getBuy(ITEM3), 5);
assertEquals(800, path.getProfit(), 0.0001);
assertEquals(3, path.getTransitIndex());
TestUtil.assertCollectionEquals(orders, order2, order1, order3);
path = path.getTail();
orders = path.getOrders();
assertEquals(650, path.getProfit(), 0.0001);
assertEquals(2, path.getTransitIndex());
TestUtil.assertCollectionEquals(orders, order5, order4);
path = path.getTail();
orders = path.getOrders();
assertEquals(300, path.getProfit(), 0.0001);
assertEquals(1, path.getTransitIndex());
TestUtil.assertCollectionEquals(orders, order7);
}
private PathRoute initTest4(){
v1 = new SimpleVendor("v1");
v2 = new SimpleVendor("v2");
v3 = new SimpleVendor("v3");
v4 = new SimpleVendor("v4");
v5 = new SimpleVendor("v5");
v1.add(new Offer(OFFER_TYPE.SELL, ITEM1, 410));
v1.add(new Offer(OFFER_TYPE.SELL, ITEM2, 200));
v1.add(new Offer(OFFER_TYPE.SELL, ITEM3, 300));
v2.add(new Offer(OFFER_TYPE.SELL, ITEM2, 270));
v4.add(new Offer(OFFER_TYPE.SELL, ITEM1, 300));
v2.add(new Offer(OFFER_TYPE.BUY, ITEM1, 470));
v3.add(new Offer(OFFER_TYPE.BUY, ITEM2, 300));
v4.add(new Offer(OFFER_TYPE.BUY, ITEM3, 370));
v5.add(new Offer(OFFER_TYPE.BUY, ITEM1, 400));
PathRoute res = new PathRoute(new Vertex<>(v1));
res = (PathRoute) res.connectTo(new Vertex<>(v2), false);
res = (PathRoute) res.connectTo(new Vertex<>(v3), false);
res = (PathRoute) res.connectTo(new Vertex<>(v4), false);
res = (PathRoute) res.connectTo(new Vertex<>(v5), false);
res.finish();
res.resort(10000, 5);
return (PathRoute) res.getRoot();
}
@Test
public void testPathRoute4() throws Exception {
PathRoute path = initTest4().getTail();
Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5);
Order order2 = new Order(v1.getSell(ITEM1), v5.getBuy(ITEM1), 5);
Order order3 = new Order(v1.getSell(ITEM2), v3.getBuy(ITEM2), 5);
Order order4 = new Order(v1.getSell(ITEM3), v4.getBuy(ITEM3), 5);
Order order5 = new Order(v2.getSell(ITEM2), v3.getBuy(ITEM2), 5);
Order order6 = new Order(v4.getSell(ITEM1), v5.getBuy(ITEM1), 5);
assertEquals(1000, path.getProfit(), 0.0001);
assertEquals(3, path.getTransitIndex());
TestUtil.assertCollectionEquals(orders, order3, order1, order4, order2);
path = path.getTail();
orders = path.getOrders();
assertEquals(650, path.getProfit(), 0.0001);
assertEquals(1, path.getTransitIndex());
TestUtil.assertCollectionEquals(orders, order5);
path = path.getTail();
orders = path.getOrders();
assertEquals(500, path.getProfit(), 0.0001);
assertEquals(0, path.getTransitIndex());
assertTrue(orders.isEmpty());
path = path.getTail();
orders = path.getOrders();
assertEquals(500, path.getProfit(), 0.0001);
assertEquals(1, path.getTransitIndex());
TestUtil.assertCollectionEquals(orders, order6);
}
}