Skip to content

Commit

Permalink
With KnapsackSolver
Browse files Browse the repository at this point in the history
  • Loading branch information
Mintas committed Mar 2, 2016
1 parent 5436e5d commit 5a8ea93
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 21 deletions.
9 changes: 7 additions & 2 deletions src/Main.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import excel.CSVCommodityParserImpl;
import knapsack.GreedyBoundedKnapsackSolver;
import model.Purchase;
import model.Purchases;
import service.JackSparrowHelperImpl;
import service.JackSparrowHelper;
import service.JackSparrowHelperGreedy;
import service.JackSparrowHelperWithSolver;

/**
* Created by SBT-Kovalev-DA on 24.02.2016.
*/
public class Main {
public static void main(String[] args) {
JackSparrowHelperImpl jackSparrowHelper = new JackSparrowHelperImpl(new CSVCommodityParserImpl(";"));
//JackSparrowHelper jackSparrowHelper = new JackSparrowHelperGreedy(new CSVCommodityParserImpl(";"));
JackSparrowHelper jackSparrowHelper = new JackSparrowHelperWithSolver(new CSVCommodityParserImpl(";"), new GreedyBoundedKnapsackSolver());

Purchases abr = jackSparrowHelper.helpJackSparrow("C:\\Users\\SBT-Kovalev-DA\\Downloads\\pirates\\sources.csv", 500);

System.out.println(abr.calculateAveragePrice());
Expand Down
3 changes: 2 additions & 1 deletion src/excel/CSVCommodityParserImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.List;

import static java.lang.Integer.valueOf;
import static model.Commodity.init;

/**
* Created by SBT-Kovalev-DA on 25.02.2016.
Expand All @@ -32,7 +33,7 @@ public List<Commodity> parseFile(String fileName) {
br.readLine(); //avoid headers
while ((line = br.readLine()) != null) {
String[] commodity = line.split(separator);
commodities.add(new Commodity(commodity[0],
commodities.add(init(commodity[0],
valueOf(commodity[1]), Double.valueOf(commodity[2]),
valueOf(commodity[3]), valueOf(commodity[4])));
}
Expand Down
14 changes: 14 additions & 0 deletions src/knapsack/BoundedKnapsackSolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package knapsack;

import model.Commodity;
import model.Purchase;

import java.util.List;
import java.util.Set;

/**
* Created by SBT-Kovalev-DA on 01.03.2016.
*/
public interface BoundedKnapsackSolver {
Set<Purchase> solveKnapsack(int capacity, List<Commodity> commodities);
}
53 changes: 53 additions & 0 deletions src/knapsack/GreedyBoundedKnapsackSolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package knapsack;

import model.Commodity;
import model.Purchase;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import static java.lang.Math.min;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

/**
* Created by SBT-Kovalev-DA on 01.03.2016.
*/
public class GreedyBoundedKnapsackSolver implements BoundedKnapsackSolver {
@Override
public Set<Purchase> solveKnapsack(int capacity, List<Commodity> commodities) {
List<Commodity> cmdtDescendingPrice = commodities.stream().sorted(comparing(Commodity::getAvgPrice).reversed()).collect(toList());

int gotWeight = 0;
Set<Purchase> purchases = new LinkedHashSet<>();
while (gotWeight < capacity) {
Purchase purchase = decidePurchase(capacity - gotWeight, cmdtDescendingPrice);
if (purchase == null || gotWeight + purchase.getNumberOfGallons() > capacity) break;

purchases.add(purchase);
gotWeight += purchase.getNumberOfGallons();
}
return purchases;
}

private Purchase decidePurchase(int needGallons, List<Commodity> commodities) {
List<Commodity> cmdtsLeft = commodities.stream()
.filter(c -> c.getAmountLeft() != 0)
.collect(toList());
for (Commodity commodity : cmdtsLeft) {
Purchase purchase = bestForCommodity(commodity, needGallons);
if (purchase != null) return purchase;
}
return null;
}

private Purchase bestForCommodity(Commodity cmdty, int needGallons) {
int canTake = min(cmdty.getAmountLeft(), needGallons);
int canTakeByServings = (canTake / cmdty.getServingSize()) * cmdty.getServingSize();
if (canTake < cmdty.getMinSize() || canTakeByServings == 0) return null;

cmdty.decreaseAmount(canTakeByServings);
return new Purchase(cmdty.getSource(), canTakeByServings, cmdty.getAvgPrice());
}
}
12 changes: 11 additions & 1 deletion src/model/Commodity.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,33 @@
*/
public class Commodity {
private final String source;
private final int totalAmount;
private int amountLeft;
private final double avgPrice;
private final int minSize;
private final int servingSize;

public Commodity(String source, int amount, double avgPrice, int minSize, int servingSize) {
private Commodity(String source, int totalAmount, int amount, double avgPrice, int minSize, int servingSize) {
this.source = source;
this.amountLeft = amount;
this.totalAmount = totalAmount;
this.avgPrice = avgPrice;
this.minSize = minSize;
this.servingSize = servingSize;
}

public static Commodity init(String source, int amount, double avgPrice, int minSize, int servingSize) {
return new Commodity(source, amount, amount, avgPrice, minSize, servingSize);
}

public String getSource() {
return source;
}

public int getTotalAmount() {
return totalAmount;
}

public int getAmountLeft() {
return amountLeft;
}
Expand Down
38 changes: 38 additions & 0 deletions src/service/AbstractJackSparrowHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package service;

import excel.CommodityParser;
import model.Commodity;
import model.Purchase;
import model.Purchases;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import static java.lang.Math.min;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

public abstract class AbstractJackSparrowHelper implements JackSparrowHelper {
private final CommodityParser parser;

public AbstractJackSparrowHelper(CommodityParser parser) {
this.parser = parser;
}

@Override
public Purchases helpJackSparrow(String pathToPrices, int numberOfGallons) {
List<Commodity> commodities = getCommodities(pathToPrices);

Set<Purchase> purchases = getPurchases(numberOfGallons, commodities);

return new Purchases(numberOfGallons, purchases);
}

protected abstract Set<Purchase> getPurchases(int numberOfGallons, List<Commodity> commodities);

private List<Commodity> getCommodities(String pathToPrices) {
return parser.parseFile(pathToPrices)
.stream().sorted(comparing(Commodity::getAvgPrice)).collect(toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,22 @@
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;

public class JackSparrowHelperImpl implements JackSparrowHelper {
private final CommodityParser parser;

public JackSparrowHelperImpl(CommodityParser parser) {
this.parser = parser;
@Deprecated
public class JackSparrowHelperGreedy extends AbstractJackSparrowHelper {
public JackSparrowHelperGreedy(CommodityParser parser) {
super(parser);
}

@Override
public Purchases helpJackSparrow(String pathToPrices, int numberOfGallons) {
List<Commodity> commodities = getCommodities(pathToPrices);

protected Set<Purchase> getPurchases(int numberOfGallons, List<Commodity> commodities) {
int gotGallons = 0;
Set<Purchase> purchases = new LinkedHashSet<>();
while (gotGallons < numberOfGallons) {
Purchase purchase = decidePurchase(numberOfGallons - gotGallons, commodities);
purchases.add(purchase);
gotGallons+=purchase.getNumberOfGallons();
gotGallons += purchase.getNumberOfGallons();
}

return new Purchases(numberOfGallons, purchases);
return purchases;
}

private Purchase decidePurchase(int needGallons, List<Commodity> commodities) {
Expand All @@ -46,7 +42,6 @@ private Purchase decidePurchase(int needGallons, List<Commodity> commodities) {
return null;
}


private Purchase bestForCommodity(Commodity cmdty, int needGallons) {
int canTake = min(cmdty.getAmountLeft(), needGallons);
int canTakeByServings = (canTake / cmdty.getServingSize()) * cmdty.getServingSize();
Expand All @@ -55,9 +50,4 @@ private Purchase bestForCommodity(Commodity cmdty, int needGallons) {
cmdty.decreaseAmount(canTakeByServings);
return new Purchase(cmdty.getSource(), canTakeByServings, cmdty.getAvgPrice());
}

private List<Commodity> getCommodities(String pathToPrices) {
return parser.parseFile(pathToPrices)
.stream().sorted(comparing(Commodity::getAvgPrice)).collect(toList());
}
}
59 changes: 59 additions & 0 deletions src/service/JackSparrowHelperWithSolver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package service;

import excel.CommodityParser;
import knapsack.BoundedKnapsackSolver;
import model.Commodity;
import model.Purchase;

import java.util.List;
import java.util.Optional;
import java.util.Set;

import static java.util.stream.Collectors.toSet;

public class JackSparrowHelperWithSolver extends AbstractJackSparrowHelper {
private final BoundedKnapsackSolver knapsackSolver;

public JackSparrowHelperWithSolver(CommodityParser parser, BoundedKnapsackSolver knapsackSolver) {
super(parser);
this.knapsackSolver = knapsackSolver;
}

@Override
protected Set<Purchase> getPurchases(int numberOfGallons, List<Commodity> commodities) {
int knapsackSize = getKnapsackSize(commodities, numberOfGallons);
Set<Purchase> excludePurchases = fillKnapsack(knapsackSize, commodities);
return findNeededPurchases(commodities, excludePurchases);
}

private Set<Purchase> findNeededPurchases(List<Commodity> commodities, Set<Purchase> excludePurchases) {
return commodities.stream()
.map(c -> findNeeded(c, excludePurchases))
.filter(p -> p.getNumberOfGallons()!=0)
.collect(toSet());
}

private Purchase findNeeded(Commodity commodity, Set<Purchase> excludePurchases) {
Optional<Purchase> excludeFromCmdty = excludePurchases.stream()
.filter(p -> commodity.getSource().equals(p.getSourceName())).findFirst();
return new Purchase(commodity.getSource(),
getAmount(commodity, excludeFromCmdty),
commodity.getAvgPrice());
}

private Integer getAmount(Commodity commodity, Optional<Purchase> excludeFromCmdty) {
return commodity.getTotalAmount() - (excludeFromCmdty.isPresent() ? excludeFromCmdty.get().getNumberOfGallons() : 0);
}

private int getKnapsackSize(List<Commodity> commodities, int numberOfGallons) {
return calculateTotalPurchaseSize(commodities) - numberOfGallons;
}

private int calculateTotalPurchaseSize(List<Commodity> commodities) {
return commodities.stream().mapToInt(Commodity::getAmountLeft).sum();
}

private Set<Purchase> fillKnapsack(int knapsackSize, List<Commodity> commodities) {
return knapsackSolver.solveKnapsack(knapsackSize, commodities);
}
}

0 comments on commit 5a8ea93

Please sign in to comment.