PathRoute implement
This commit is contained in:
@@ -40,10 +40,6 @@ public class Order implements Comparable<Order> {
|
||||
return profit;
|
||||
}
|
||||
|
||||
public Order getCopy(long count){
|
||||
return new Order(sell, buy, count);
|
||||
}
|
||||
|
||||
public long getCount() {
|
||||
return count;
|
||||
}
|
||||
@@ -56,6 +52,10 @@ public class Order implements Comparable<Order> {
|
||||
return buy.getVendor().equals(buyer);
|
||||
}
|
||||
|
||||
public Vendor getBuyer(){
|
||||
return buy.getVendor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull Order order) {
|
||||
Objects.requireNonNull(order, "Not compare with null");
|
||||
@@ -100,4 +100,7 @@ public class Order implements Comparable<Order> {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void setMax(double balance, long limit) {
|
||||
setCount((long) Math.min(balance/sell.getPrice(), limit));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public class Graph<T extends Connectable<T>> {
|
||||
if (edge != null ){
|
||||
if (!(withRefill && Math.min(limit, maxDistance) < edge.getLength() && !source.getEntry().canRefill())){
|
||||
found = true;
|
||||
Path<T> path = head.connectTo(edge, limit < edge.getLength());
|
||||
Path<T> path = head.connectTo(edge.getTarget(), limit < edge.getLength());
|
||||
path.finish();
|
||||
LOG.trace("Last edge find, add path {}", path);
|
||||
paths.add(path);
|
||||
@@ -124,10 +124,10 @@ public class Graph<T extends Connectable<T>> {
|
||||
LOG.trace("Search around");
|
||||
for (Edge<T> next : source.getEdges()) {
|
||||
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
|
||||
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;
|
||||
// refill
|
||||
if (nextLimit < 0 ) nextLimit = maxDistance - next.getLength();
|
||||
@@ -151,9 +151,9 @@ public class Graph<T extends Connectable<T>> {
|
||||
if (deep == source.getLevel()){
|
||||
for (Edge<T> next : source.getEdges()) {
|
||||
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)) {
|
||||
Path<T> path = head.connectTo(next, limit < next.getLength());
|
||||
Path<T> path = head.connectTo(next.getTarget(), limit < next.getLength());
|
||||
path.finish();
|
||||
LOG.trace("Last edge find, path {}", path);
|
||||
return path;
|
||||
@@ -165,7 +165,7 @@ public class Graph<T extends Connectable<T>> {
|
||||
for (Edge<T> next : source.getEdges()) {
|
||||
if (next.getTarget().getLevel() >= source.getLevel()) 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;
|
||||
// refill
|
||||
if (nextLimit < 0 ) nextLimit = stock - next.getLength();
|
||||
|
||||
@@ -18,8 +18,8 @@ public class Path<T extends Connectable<T>> {
|
||||
this.refill = refill;
|
||||
}
|
||||
|
||||
public Path<T> connectTo(Edge<T> edge, boolean refill){
|
||||
return new Path<>(this, edge.getTarget(), refill);
|
||||
public Path<T> connectTo(Vertex<T> vertex, boolean refill){
|
||||
return new Path<>(this, vertex, refill);
|
||||
}
|
||||
|
||||
public void finish(){
|
||||
@@ -37,6 +37,11 @@ public class Path<T extends Connectable<T>> {
|
||||
return head == null;
|
||||
}
|
||||
|
||||
public Path<T> getRoot(){
|
||||
if (isRoot()) return this;
|
||||
return head.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
@@ -63,18 +68,21 @@ public class Path<T extends Connectable<T>> {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean contains(Edge<T> edge) {
|
||||
return target.equals(edge.getTarget()) || (!isRoot() && head.contains(edge));
|
||||
public boolean isConnect(Vertex<T> vertex) {
|
||||
return target.equals(vertex) || (!isRoot() && head.isConnect(vertex));
|
||||
}
|
||||
|
||||
public boolean isPathFrom(T entry) {
|
||||
return !isRoot() && head.target.getEntry().equals(entry);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T extends Connectable<T>> Path<T> toPath(T... items){
|
||||
T s = items[0];
|
||||
Path<T> path = new Path<>(new Vertex<>(s));
|
||||
T t = items[0];
|
||||
Path<T> path = new Path<>(new Vertex<>(t));
|
||||
for (int i = 1; i < items.length; i++) {
|
||||
T t = items[i];
|
||||
t = items[i];
|
||||
path = new Path<>(path, new Vertex<>(t), false);
|
||||
s = t;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -4,25 +4,28 @@ import ru.trader.core.Offer;
|
||||
import ru.trader.core.Order;
|
||||
import ru.trader.core.Vendor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.*;
|
||||
|
||||
public class PathRoute extends Path<Vendor> {
|
||||
private final ArrayList<Order> orders = new ArrayList<>();
|
||||
private double profit = 0;
|
||||
private int transitIndex = 0;
|
||||
private PathRoute tail;
|
||||
|
||||
|
||||
public PathRoute(Vertex<Vendor> 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);
|
||||
assert head.tail == null;
|
||||
head.tail = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path<Vendor> connectTo(Edge<Vendor> edge, boolean refill) {
|
||||
return new PathRoute(this.getCopy(), edge.getTarget(), refill);
|
||||
public Path<Vendor> connectTo(Vertex<Vendor> vertex, boolean refill) {
|
||||
return new PathRoute(this.getCopy(), vertex, refill);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,8 +54,8 @@ public class PathRoute extends Path<Vendor> {
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Order> getOrders() {
|
||||
return orders;
|
||||
public List<Order> getOrders() {
|
||||
return Collections.unmodifiableList(orders);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,7 +64,7 @@ public class PathRoute extends Path<Vendor> {
|
||||
for (Order order : orders) {
|
||||
if (sb.length() > 0) sb.append(", ");
|
||||
sb.append(order.getBuy().getItem());
|
||||
sb.append(" (").append(order.getBuy().getVendor()).append(") ");
|
||||
sb.append(" (").append(order.getBuyer()).append(") ");
|
||||
}
|
||||
String o = sb.toString();
|
||||
sb = new StringBuilder();
|
||||
@@ -77,20 +80,85 @@ public class PathRoute extends Path<Vendor> {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Path<Vendor> getCopy(){
|
||||
Path<Vendor> res;
|
||||
LinkedList<Path<Vendor>> v = new LinkedList<>();
|
||||
Path<Vendor> p = this;
|
||||
while (!p.isRoot()){
|
||||
v.add(p);
|
||||
p = p.getHead();
|
||||
}
|
||||
res = p;
|
||||
Iterator<Path<Vendor>> it = v.descendingIterator();
|
||||
while (it.hasNext()){
|
||||
p = it.next();
|
||||
res = new PathRoute(res, p.getTarget(), p.isRefill());
|
||||
public boolean isEmpty(){
|
||||
return orders.isEmpty();
|
||||
}
|
||||
|
||||
public PathRoute getCopy(){
|
||||
PathRoute path = (PathRoute) getRoot();
|
||||
PathRoute res = new PathRoute(path.getTarget());
|
||||
while (path.tail != null){
|
||||
res = new PathRoute(res, path.tail.getTarget(), path.tail.isRefill());
|
||||
path = path.tail;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
218
core/src/test/java/ru/trader/graph/PathRouteTest.java
Normal file
218
core/src/test/java/ru/trader/graph/PathRouteTest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user