package bargainingchips.utilityfunctions; import bargainingchips.Bundle; import bargainingchips.BundleBuilder; import bargainingchips.Chip; import bargainingchips.ChipIssueValue; import bargainingchips.ChipIssueValueBuilder; import bargainingchips.wishlist.WishList; import bargainingchips.wishlist.WishListBuilder; /** * * This utility function inputs {@link wishList} (i.e., quantity of each desired {@link Chip}), and the curves for price * and quantity ranges per each {@link Chip} as peaked curves. The curves are in a Bezier form. * The buyer would designate a series of `n' prices per each {@link Chip}, and then a Bezier function (of rank `n') is * applied to determine the value of the offered price. That is the buyer inputs an array of prices per each desired * {@link Chip} (i.e., in {@link wishList}). The prices could be in integer or real format, determined by type T[] * (i.e, `Integer[]' or `Double[]', etc). * For quantity, similarly, the buyer may accept, with degrees of satisfaction, offered quantity around the peak (introduced * via {@link wishList}) per each {@link Chip}. That is, this Bezier curve is of rank `n+1', i.e. `n' points plus wished quantity. * It is worth to mention that this function considers the importance of issues (i.e., for price, quantity, etc.) * as well as the importance of Chips (i.e., colors) with respect to each other. * * * @author Faria Nassiri-Mofakham * */ public class UF_BezierPriceBezierQuantity implements UtilityFunction { // T for the type of `price' data points private WishList wishlist; // the exact wished quantity per each Chip // Other parts of the buyer's preferences are assigned with desirability degrees of a variety of prices and quantities per each Chip. private int n; // number or data points at Bezier curve private ChipIssueValue bezierQuantity; // list of `n' data points determining the quantity curve. // It could give an asymmetric deviation around desired quantity // of the Chip; quantities less than or more than the exact qty per chip. private ChipIssueValue bezierPrice; // list of `n' data points of type T determining the price curve private ChipIssueValue lambdaC; // importance of each Chip (i.e, color) private double lambdaP,lambdaQ; // importance of issues (i.e., price, quantity, etc) public UF_BezierPriceBezierQuantity(WishList w, int m, ChipIssueValue bz, ChipIssueValue qtyDev, ChipIssueValue lc, double lp, double lq) { wishlist=w; n=m; bezierQuantity=qtyDev; bezierPrice=bz; lambdaC=lc; lambdaP=lp; lambdaQ=lq; } @Override public Double getUtility(Bundle b) { double sumWeightedPrice = 0.0; double sumWeightedQty = 0.0; if (b!=null) { for (Chip c : wishlist) { int desiredQ = wishlist.getQuantity(c); T[] desiredP = bezierPrice.getUnitValue(c); if (desiredP.length > n) throw new IllegalStateException("\n\n[Warning] UF_BezierPriceAndBezierQuantity::getUtility(Bundle). Input only "+n+" price data points! "+ desiredP); Double importanceC= lambdaC.getUnitValue(c); Integer[] devC= bezierQuantity.getUnitValue(c); if (devC.length > n) throw new IllegalStateException("\n\n[Warning] UF_BezierPriceAndBezierQuantity::getUtility(Bundle). Input totally "+ (n-1) +" quantity data points around the exact wished! "+ desiredQ); Integer offeredQ = b.getQuantity(c); if (offeredQ == null) offeredQ = 0; Double offeredP= b.getUnitPrice(c); sumWeightedPrice += importanceC * bezier(desiredP, offeredP); sumWeightedQty += importanceC * bezier(desiredQ, devC, offeredQ); } double u = lambdaP * sumWeightedPrice + lambdaQ * sumWeightedQty; return ( (u>1) ? 1 : ( (u<0) ? 0 : u) ); } return 0.0; } /** * @param input parameter (e.g., an offered price per a {@link Chip}, * and `n' data points of type T (e.g., as of Double[], Integer[], etc). * * @return Bezier value of rank `n' for the offered parameter. **/ private double bezier(T[] desired, Double offered) { double bez = 0.0; int n= desired.length; for (int i=0; i (double) desired[n-1]) ? 0.0 : comb(n,i)*Math.pow(1-offered, n)*Math.pow(i, n)*(double)desired[i])); } return ( (bez>1) ? 1 : (bez<0) ? 0 : bez); } /** * @param input parameter (e.g., an offered quantity per a {@link Chip}, and `n+1' data points. * * @return Bezier value of rank `n+1' for the offered parameter. **/ private double bezier(Integer q, Integer[] desired, Integer offered) { double bez = 0.0; int n = desired.length; Integer[] data = new Integer[n+1]; for (int i = 0; i < (int)Math.ceil(n/2); i++) { data[i] = desired[i]; data[n-i] = desired[n-1-i]; } data[(int)Math.ceil(n/2)] = q; for (int i=0; i data[n]) ? 0.0 : comb(n+1,i)*Math.pow(1-offered, n+1)*Math.pow(i, n+1)*data[i])); } return ( (bez>1) ? 1 : (bez<0) ? 0 : bez); } /** * @return combination of `m' and `k' **/ private int comb(int m, int k) { return fc(m)/(fc(m-k)*fc(k)); } /** * @return factorial of `m' **/ private int fc(int m) { int result = 1; for (; m > 1; m--) { result *= m; } return result; } /** * @return an String list of values assigned to a single variable, e.g. list of quantities or prices of a {@link Chip} **/ private String writeT(ChipIssueValue t) { String s = "{"; T[] j; if (t!=null) { for (Chip c: t) { s += " " + c.toString() + "={"; j = t.getUnitValue(c); for (int k=0; k t) { String s = "{"; Integer[] j; if (t!=null) { for (Chip c: t) { s += " " + c.toString() + "={"; j = t.getUnitValue(c); for (int k=0; k prices = new ChipIssueValueBuilder().addIssue("Green", new Double[] {3.0, 3.5, 4.8, 5.0}).addIssue("Yellow", new Double[] {5.0, 5.2, 6.2, 8.0}).addIssue("Orange", new Double[] {1.0, 1.8, 2.5, 3.0}).build(); ChipIssueValue deviations = new ChipIssueValueBuilder().addIssue("Green", new Integer[] {2,1,2,3}).addIssue("Yellow", new Integer[] {3,2,2,3}).addIssue("Orange", new Integer[] {10,2,5,10}).build(); ChipIssueValue wC = new ChipIssueValueBuilder().addIssue("Green", 0.5).addIssue("Yellow", 0.3).addIssue("Orange", 0.2).build(); double wP = 0.6; double wQ = 0.4; UF_BezierPriceBezierQuantity u = new UF_BezierPriceBezierQuantity (wishlist, m, prices, deviations, wC, wP, wQ); System.out.println(u); Bundle offer = new BundleBuilder() .addStack("Green", 2.0, 3) .addStack("Yellow", 5.0, 4) .addStack("Orange", 1.0, 17) //--- // .addStack("Green", 3.0, 4) //should give utility 1.0 in weighted additive // .addStack("Yellow", 5.0, 6) // .addStack("Orange", 1.0, 40) //--- // .addStack("Green", 10.0, 1) //should give utility 0.0 in weighted additive // .addStack("Yellow", 10.0, 1) // .addStack("Orange", 10.0, 1) //--- // .addStack("Red", 1.0, 6) // .addStack("Green", 3.0, 15) // .addStack("Purple", 0.10, 10) .build(); System.out.println(u.getUtility(offer)); } }