Archived
0

Expand path added

This commit is contained in:
iMoHax
2014-08-17 18:26:29 +04:00
parent 7d15c8461b
commit 531866b227
4 changed files with 177 additions and 134 deletions

View File

@@ -22,14 +22,9 @@ public class Path<T extends Connectable<T>> {
return new Path<>(this, vertex, refill); return new Path<>(this, vertex, refill);
} }
public void finish(){ protected void finish(){
finish(target);
}
protected void finish(Vertex<T> target){
if (!isRoot()){ if (!isRoot()){
head.finish(target); head.finish();
if (target != head.target) head.finish();
} }
} }
@@ -91,11 +86,15 @@ public class Path<T extends Connectable<T>> {
return target; return target;
} }
public T get() {
return target.getEntry();
}
public boolean isRefill(){ public boolean isRefill(){
return refill; return refill;
} }
protected Path<T> getHead(){ protected Path<T> getPrevious(){
return head; return head;
} }

View File

@@ -1,5 +1,7 @@
package ru.trader.graph; package ru.trader.graph;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.core.Offer; 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;
@@ -7,50 +9,107 @@ import ru.trader.core.Vendor;
import java.util.*; import java.util.*;
public class PathRoute extends Path<Vendor> { public class PathRoute extends Path<Vendor> {
private final ArrayList<Order> orders = new ArrayList<>(); private final static Logger LOG = LoggerFactory.getLogger(PathRoute.class);
private double profit = 0;
private int transitIndex = 0;
private PathRoute tail;
private final ArrayList<Order> orders = new ArrayList<>();
private final boolean expand;
private double profit = 0;
private PathRoute tail;
private int ordersCount = 0;
public final static Order TRANSIT = null;
public PathRoute(Vertex<Vendor> source, boolean expand) {
super(source);
this.expand = expand;
}
public PathRoute(Vertex<Vendor> source) { public PathRoute(Vertex<Vendor> source) {
super(source); super(source);
expand = false;
} }
private PathRoute(PathRoute 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; assert head.tail == null;
head.tail = this; head.tail = this;
expand = head.expand;
//transit
orders.add(ordersCount++, TRANSIT);
} }
@Override @Override
public Path<Vendor> connectTo(Vertex<Vendor> vertex, boolean refill) { public Path<Vendor> connectTo(Vertex<Vendor> vertex, boolean refill) {
LOG.trace("Connect path {} to {}", this, vertex);
return new PathRoute(this.getCopy(), vertex, refill); return new PathRoute(this.getCopy(), vertex, refill);
} }
public PathRoute getCopy(){
PathRoute path = (PathRoute) getRoot();
PathRoute res = new PathRoute(path.getTarget());
while (path.hasNext()){
path = path.getNext();
res = new PathRoute(res, path.getTarget(), path.isRefill());
}
return res;
}
private void addOrder(Order order){
LOG.trace("Add order {} to path {}", order, this);
orders.add(ordersCount++, order);
if (!expand) return;
LOG.trace("Expand orders");
if (hasNext()){
PathRoute next = getNext();
LOG.trace("Add {} clone of order", next.ordersCount - 1);
for (int i = 1; i < next.ordersCount; i++) {
orders.add(ordersCount++, new Order(order.getSell(), order.getBuy()));
addTransitsToHead();
}
cloneTailOrders(next.ordersCount);
}
addTransitsToHead();
}
private void addTransitsToHead(){
PathRoute p = getPrevious();
while (!p.isRoot()) {
LOG.trace("Add transit order to path {}", p);
p.orders.add(p.ordersCount++, TRANSIT);
p = p.getPrevious();
}
}
private void cloneTailOrders(int count){
if (hasNext()) {
PathRoute p = getNext();
LOG.trace("Duplicate {} orders of path {}", count, p);
for (int i = 0; i < count; i++) {
Order o = p.orders.get(i);
if (o == TRANSIT) p.orders.add(TRANSIT);
else p.orders.add(new Order(o.getSell(), o.getBuy()));
}
p.cloneTailOrders(count);
}
}
@Override @Override
protected void finish(Vertex<Vendor> target) { protected void finish() {
if (!isRoot()) { if (!isRoot()){
if (!contains(target.getEntry())){ fillOrders();
updateOrders(target.getEntry()); getPrevious().finish();
getHead().finish(target);
if (getHead().getTarget() != target) getHead().finish();
}
} }
} }
private boolean contains(Vendor buyer){ private void fillOrders(){
for (Order order : orders) { LOG.trace("Fill orders of path {}", this);
if (order.isBuyer(buyer)) return true; Vendor seller = getPrevious().get();
}
return false;
}
private void updateOrders(Vendor buyer){
Vendor seller = getHead().getTarget().getEntry();
for (Offer sell : seller.getAllSellOffers()) { for (Offer sell : seller.getAllSellOffers()) {
Offer buy = buyer.getBuy(sell.getItem()); PathRoute p = this;
if (buy != null) orders.add(new Order(sell, buy)); while (p != null) {
Offer buy = p.get().getBuy(sell.getItem());
if (buy != null) addOrder(new Order(sell, buy));
p = p.getNext();
}
} }
} }
@@ -58,40 +117,37 @@ public class PathRoute extends Path<Vendor> {
return Collections.unmodifiableList(orders); return Collections.unmodifiableList(orders);
} }
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Order order : orders) {
if (sb.length() > 0) sb.append(", ");
sb.append(order.getBuy().getItem());
sb.append(" (").append(order.getBuyer()).append(") ");
}
String o = sb.toString();
sb = new StringBuilder();
if (isRoot()){
sb.append(getTarget().getEntry());
if (o.length()>0) sb.append(" (").append(o).append(") ");
} else {
sb.append(getHead().toString());
if (isRefill()) sb.append("(R)");
if (o.length()>0) sb.append(" (").append(o).append(") ");
sb.append(" -> ").append(getTarget().getEntry());
}
return sb.toString();
}
public boolean isEmpty(){ public boolean isEmpty(){
return orders.isEmpty(); return ordersCount <= 1;
} }
public PathRoute getCopy(){ @Override
PathRoute path = (PathRoute) getRoot(); protected PathRoute getPrevious() {
PathRoute res = new PathRoute(path.getTarget()); return (PathRoute) super.getPrevious();
while (path.tail != null){
res = new PathRoute(res, path.tail.getTarget(), path.tail.isRefill());
path = path.tail;
} }
return res;
public PathRoute getNext() {
return tail;
}
public boolean hasNext(){
return tail != null;
}
public void resort(double balance, long limit){
if (isRoot()) return;
for (Order order : orders) {
if (order == TRANSIT) continue;
order.setMax(balance, limit);
}
orders.sort(this::compareOrders);
updateProfit();
getPrevious().resort(balance, limit);
}
private double getTransitProfit(){
return hasNext() ? getNext().getProfit() : 0;
} }
public double getProfit(){ public double getProfit(){
@@ -99,53 +155,21 @@ public class PathRoute extends Path<Vendor> {
} }
public double getProfit(Order order){ public double getProfit(Order order){
if (order == TRANSIT) return getTransitProfit();
if (isPathFrom(order.getBuyer())) return order.getProfit() + profit; if (isPathFrom(order.getBuyer())) return order.getProfit() + profit;
return tail != null ? tail.getProfit(order) : order.getProfit(); return hasNext() ? getNext().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() { private void updateProfit() {
if (isEmpty()){
profit = tail != null ? tail.getProfit() : 0;
} else {
Order best = orders.get(0); Order best = orders.get(0);
profit = getProfit(best); if (best == TRANSIT) profit = getTransitProfit();
} else profit = getProfit(best);
} }
private int compareOrders(Order o1, Order o2){ private int compareOrders(Order o1, Order o2){
if (tail == null || o1.isBuyer(o2.getBuyer())){ if (o1 != TRANSIT && o2 != TRANSIT){
//reverse if (!hasNext() || o1.isBuyer(o2.getBuyer()))
return o2.compareTo(o1); return o2.compareTo(o1);
} }
double profit1 = getProfit(o1); double profit1 = getProfit(o1);
@@ -154,11 +178,30 @@ public class PathRoute extends Path<Vendor> {
} }
public PathRoute getTail() {
return tail; @Override
public String toString() {
StringBuilder sb = new StringBuilder();
int step = !hasNext() || tail.ordersCount == 0 ? 1 : tail.ordersCount;
for (int i = 0; i < ordersCount; i += step) {
Order order = orders.get(i);
if (order == TRANSIT) continue;
if (sb.length() > 0) sb.append(", ");
sb.append(order.getBuy().getItem());
sb.append(" (").append(order.getBuyer()).append(") ");
}
String o = sb.toString();
sb = new StringBuilder();
if (isRoot()){
sb.append(get());
if (o.length()>0) sb.append(" (").append(o).append(") ");
} else {
sb.append(getPrevious().toString());
if (isRefill()) sb.append("(R)");
if (o.length()>0) sb.append(" (").append(o).append(") ");
sb.append(" -> ").append(get());
}
return sb.toString();
} }
public int getTransitIndex() {
return transitIndex;
}
} }

View File

@@ -13,7 +13,7 @@ public class TestUtil {
assertSize(collection, items); assertSize(collection, items);
int curIndx=0; int curIndx=0;
for (T actual : collection) { for (T actual : collection) {
if (!actual.equals(items[curIndx])){ if ((actual == null && items[curIndx] != null) || (actual != null && !actual.equals(items[curIndx]))){
Assert.fail(String.format("Entry by index %d is different. Expected: %s Actual: %s", curIndx, items[curIndx], actual)); Assert.fail(String.format("Entry by index %d is different. Expected: %s Actual: %s", curIndx, items[curIndx], actual));
return; return;
} }

View File

@@ -2,12 +2,15 @@ package ru.trader.graph;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.TestUtil; import ru.trader.TestUtil;
import ru.trader.core.*; import ru.trader.core.*;
import java.util.Collection; import java.util.Collection;
public class PathRouteTest extends Assert { public class PathRouteTest extends Assert {
private final static Logger LOG = LoggerFactory.getLogger(PathRouteTest.class);
private final static Item ITEM1 = new Item("ITEM1"); private final static Item ITEM1 = new Item("ITEM1");
private final static Item ITEM2 = new Item("ITEM2"); private final static Item ITEM2 = new Item("ITEM2");
@@ -19,6 +22,7 @@ public class PathRouteTest extends Assert {
private static Vendor v5; private static Vendor v5;
private PathRoute initTest1(){ private PathRoute initTest1(){
LOG.info("Init test 1");
v1 = new SimpleVendor("v1"); v1 = new SimpleVendor("v1");
v2 = new SimpleVendor("v2"); v2 = new SimpleVendor("v2");
@@ -39,7 +43,8 @@ public class PathRouteTest extends Assert {
@Test @Test
public void testPathRoute1() throws Exception { public void testPathRoute1() throws Exception {
PathRoute path = initTest1().getTail(); LOG.info("Start path route test 1");
PathRoute path = initTest1().getNext();
Collection<Order> orders = path.getOrders(); Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5); Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5);
@@ -47,11 +52,11 @@ public class PathRouteTest extends Assert {
Order order3 = new Order(v1.getSell(ITEM3), v2.getBuy(ITEM3), 5); Order order3 = new Order(v1.getSell(ITEM3), v2.getBuy(ITEM3), 5);
assertEquals(1000, path.getProfit(), 0.0001); assertEquals(1000, path.getProfit(), 0.0001);
assertEquals(3, path.getTransitIndex()); TestUtil.assertCollectionEquals(orders, order1, order2, order3, PathRoute.TRANSIT);
TestUtil.assertCollectionEquals(orders, order1, order2, order3);
} }
private PathRoute initTest2(){ private PathRoute initTest2(){
LOG.info("Init test 2");
v1 = new SimpleVendor("v1"); v1 = new SimpleVendor("v1");
v2 = new SimpleVendor("v2"); v2 = new SimpleVendor("v2");
v3 = new SimpleVendor("v3"); v3 = new SimpleVendor("v3");
@@ -73,7 +78,8 @@ public class PathRouteTest extends Assert {
@Test @Test
public void testPathRoute2() throws Exception { public void testPathRoute2() throws Exception {
PathRoute path = initTest2().getTail(); LOG.info("Start path route test 2");
PathRoute path = initTest2().getNext();
Collection<Order> orders = path.getOrders(); Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5); Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
@@ -81,18 +87,17 @@ public class PathRouteTest extends Assert {
Order order3 = new Order(v1.getSell(ITEM3), v3.getBuy(ITEM3), 5); Order order3 = new Order(v1.getSell(ITEM3), v3.getBuy(ITEM3), 5);
assertEquals(1000, path.getProfit(), 0.0001); assertEquals(1000, path.getProfit(), 0.0001);
assertEquals(1, path.getTransitIndex()); TestUtil.assertCollectionEquals(orders, order1, PathRoute.TRANSIT, order3);
TestUtil.assertCollectionEquals(orders, order1, order3);
path = path.getTail(); path = path.getNext();
orders = path.getOrders(); orders = path.getOrders();
assertEquals(750, path.getProfit(), 0.0001); assertEquals(750, path.getProfit(), 0.0001);
assertEquals(1, path.getTransitIndex()); TestUtil.assertCollectionEquals(orders, order2, PathRoute.TRANSIT);
TestUtil.assertCollectionEquals(orders, order2);
} }
private PathRoute initTest3(){ private PathRoute initTest3(){
LOG.info("Init test 3");
v1 = new SimpleVendor("v1"); v1 = new SimpleVendor("v1");
v2 = new SimpleVendor("v2"); v2 = new SimpleVendor("v2");
v3 = new SimpleVendor("v3"); v3 = new SimpleVendor("v3");
@@ -120,7 +125,8 @@ public class PathRouteTest extends Assert {
@Test @Test
public void testPathRoute3() throws Exception { public void testPathRoute3() throws Exception {
PathRoute path = initTest3().getTail(); LOG.info("Start path route test 3");
PathRoute path = initTest3().getNext();
Collection<Order> orders = path.getOrders(); Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5); Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
@@ -131,25 +137,23 @@ public class PathRouteTest extends Assert {
Order order7 = new Order(v3.getSell(ITEM3), v4.getBuy(ITEM3), 5); Order order7 = new Order(v3.getSell(ITEM3), v4.getBuy(ITEM3), 5);
assertEquals(800, path.getProfit(), 0.0001); assertEquals(800, path.getProfit(), 0.0001);
assertEquals(3, path.getTransitIndex()); TestUtil.assertCollectionEquals(orders, order2, order1, order3, PathRoute.TRANSIT);
TestUtil.assertCollectionEquals(orders, order2, order1, order3);
path = path.getTail(); path = path.getNext();
orders = path.getOrders(); orders = path.getOrders();
assertEquals(650, path.getProfit(), 0.0001); assertEquals(650, path.getProfit(), 0.0001);
assertEquals(2, path.getTransitIndex()); TestUtil.assertCollectionEquals(orders, order5, order4, PathRoute.TRANSIT);
TestUtil.assertCollectionEquals(orders, order5, order4);
path = path.getTail(); path = path.getNext();
orders = path.getOrders(); orders = path.getOrders();
assertEquals(300, path.getProfit(), 0.0001); assertEquals(300, path.getProfit(), 0.0001);
assertEquals(1, path.getTransitIndex()); TestUtil.assertCollectionEquals(orders, order7, PathRoute.TRANSIT);
TestUtil.assertCollectionEquals(orders, order7);
} }
private PathRoute initTest4(){ private PathRoute initTest4(){
LOG.info("Init test 4");
v1 = new SimpleVendor("v1"); v1 = new SimpleVendor("v1");
v2 = new SimpleVendor("v2"); v2 = new SimpleVendor("v2");
v3 = new SimpleVendor("v3"); v3 = new SimpleVendor("v3");
@@ -179,7 +183,8 @@ public class PathRouteTest extends Assert {
@Test @Test
public void testPathRoute4() throws Exception { public void testPathRoute4() throws Exception {
PathRoute path = initTest4().getTail(); LOG.info("Start path route test 4");
PathRoute path = initTest4().getNext();
Collection<Order> orders = path.getOrders(); Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5); Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5);
@@ -191,28 +196,24 @@ public class PathRouteTest extends Assert {
assertEquals(1000, path.getProfit(), 0.0001); assertEquals(1000, path.getProfit(), 0.0001);
assertEquals(3, path.getTransitIndex()); TestUtil.assertCollectionEquals(orders, order3, order1, order4, PathRoute.TRANSIT, order2);
TestUtil.assertCollectionEquals(orders, order3, order1, order4, order2);
path = path.getTail(); path = path.getNext();
orders = path.getOrders(); orders = path.getOrders();
assertEquals(650, path.getProfit(), 0.0001); assertEquals(650, path.getProfit(), 0.0001);
assertEquals(1, path.getTransitIndex()); TestUtil.assertCollectionEquals(orders, order5, PathRoute.TRANSIT);
TestUtil.assertCollectionEquals(orders, order5);
path = path.getTail(); path = path.getNext();
orders = path.getOrders(); orders = path.getOrders();
assertEquals(500, path.getProfit(), 0.0001); assertEquals(500, path.getProfit(), 0.0001);
assertEquals(0, path.getTransitIndex()); TestUtil.assertCollectionEquals(orders, PathRoute.TRANSIT);
assertTrue(orders.isEmpty());
path = path.getTail(); path = path.getNext();
orders = path.getOrders(); orders = path.getOrders();
assertEquals(500, path.getProfit(), 0.0001); assertEquals(500, path.getProfit(), 0.0001);
assertEquals(1, path.getTransitIndex()); TestUtil.assertCollectionEquals(orders, order6, PathRoute.TRANSIT);
TestUtil.assertCollectionEquals(orders, order6);
} }
} }