[338] | 1 | package bargainingchips.utilityfunctions;
|
---|
| 2 |
|
---|
| 3 | import bargainingchips.Bundle;
|
---|
| 4 | import bargainingchips.BundleBuilder;
|
---|
| 5 | import bargainingchips.Chip;
|
---|
| 6 | import bargainingchips.ChipIssueValue;
|
---|
| 7 | import bargainingchips.ChipIssueValueBuilder;
|
---|
[340] | 8 | import bargainingchips.wishlist.WishList;
|
---|
| 9 | import bargainingchips.wishlist.WishListBuilder;
|
---|
[338] | 10 |
|
---|
| 11 | /**
|
---|
| 12 | *
|
---|
| 13 | * This utility function inputs {@link wishList} (i.e., quantity of each desired {@link Chip}), and the curves for price
|
---|
| 14 | * and quantity ranges per each {@link Chip} as peaked curves. The curves are in a Bezier form.
|
---|
| 15 | * The buyer would designate a series of `n' prices per each {@link Chip}, and then a Bezier function (of rank `n') is
|
---|
| 16 | * applied to determine the value of the offered price. That is the buyer inputs an array of prices per each desired
|
---|
| 17 | * {@link Chip} (i.e., in {@link wishList}). The prices could be in integer or real format, determined by type T[]
|
---|
| 18 | * (i.e, `Integer[]' or `Double[]', etc).
|
---|
| 19 | * For quantity, similarly, the buyer may accept, with degrees of satisfaction, offered quantity around the peak (introduced
|
---|
| 20 | * via {@link wishList}) per each {@link Chip}. That is, this Bezier curve is of rank `n+1', i.e. `n' points plus wished quantity.
|
---|
| 21 | * It is worth to mention that this function considers the importance of issues (i.e., for price, quantity, etc.)
|
---|
| 22 | * as well as the importance of Chips (i.e., colors) with respect to each other.
|
---|
| 23 | *
|
---|
| 24 | *
|
---|
| 25 | * @author Faria Nassiri-Mofakham
|
---|
| 26 | *
|
---|
| 27 | */
|
---|
| 28 |
|
---|
| 29 | public class UF_BezierPriceBezierQuantity<T> implements UtilityFunction {
|
---|
| 30 |
|
---|
| 31 | // T for the type of `price' data points
|
---|
| 32 |
|
---|
| 33 | private WishList wishlist; // the exact wished quantity per each Chip
|
---|
| 34 | // Other parts of the buyer's preferences are assigned with desirability degrees of a variety of prices and quantities per each Chip.
|
---|
| 35 | private int n; // number or data points at Bezier curve
|
---|
| 36 | private ChipIssueValue<Integer[]> bezierQuantity; // list of `n' data points determining the quantity curve.
|
---|
| 37 | // It could give an asymmetric deviation around desired quantity
|
---|
| 38 | // of the Chip; quantities less than or more than the exact qty per chip.
|
---|
| 39 | private ChipIssueValue<T[]> bezierPrice; // list of `n' data points of type T determining the price curve
|
---|
| 40 | private ChipIssueValue<Double> lambdaC; // importance of each Chip (i.e, color)
|
---|
| 41 | private double lambdaP,lambdaQ; // importance of issues (i.e., price, quantity, etc)
|
---|
| 42 |
|
---|
| 43 |
|
---|
| 44 | public UF_BezierPriceBezierQuantity(WishList w, int m, ChipIssueValue<T[]> bz, ChipIssueValue<Integer[]> qtyDev, ChipIssueValue<Double> lc, double lp, double lq)
|
---|
| 45 | {
|
---|
| 46 | wishlist=w;
|
---|
| 47 | n=m;
|
---|
| 48 | bezierQuantity=qtyDev;
|
---|
| 49 | bezierPrice=bz;
|
---|
| 50 | lambdaC=lc;
|
---|
| 51 | lambdaP=lp;
|
---|
| 52 | lambdaQ=lq;
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | @Override
|
---|
| 56 | public Double getUtility(Bundle b)
|
---|
| 57 | {
|
---|
| 58 | double sumWeightedPrice = 0.0;
|
---|
| 59 | double sumWeightedQty = 0.0;
|
---|
| 60 |
|
---|
| 61 | if (b!=null)
|
---|
| 62 | {
|
---|
| 63 | for (Chip c : wishlist)
|
---|
| 64 | {
|
---|
| 65 | int desiredQ = wishlist.getQuantity(c);
|
---|
| 66 | T[] desiredP = bezierPrice.getUnitValue(c);
|
---|
| 67 | if (desiredP.length > n)
|
---|
| 68 | throw new IllegalStateException("\n\n[Warning] UF_BezierPriceAndBezierQuantity::getUtility(Bundle). Input only "+n+" price data points! "+ desiredP);
|
---|
| 69 |
|
---|
| 70 | Double importanceC= lambdaC.getUnitValue(c);
|
---|
| 71 |
|
---|
| 72 | Integer[] devC= bezierQuantity.getUnitValue(c);
|
---|
| 73 | if (devC.length > n)
|
---|
[339] | 74 | throw new IllegalStateException("\n\n[Warning] UF_BezierPriceAndBezierQuantity::getUtility(Bundle). Input totally "+ (n-1) +" quantity data points around the exact wished! "+ desiredQ);
|
---|
[338] | 75 |
|
---|
| 76 | Integer offeredQ = b.getQuantity(c);
|
---|
| 77 | if (offeredQ == null)
|
---|
| 78 | offeredQ = 0;
|
---|
| 79 | Double offeredP= b.getUnitPrice(c);
|
---|
| 80 |
|
---|
| 81 | sumWeightedPrice += importanceC * bezier(desiredP, offeredP);
|
---|
| 82 | sumWeightedQty += importanceC * bezier(desiredQ, devC, offeredQ);
|
---|
| 83 | }
|
---|
| 84 | double u = lambdaP * sumWeightedPrice + lambdaQ * sumWeightedQty;
|
---|
| 85 | return ( (u>1) ? 1 : ( (u<0) ? 0 : u) );
|
---|
| 86 | }
|
---|
| 87 | return 0.0;
|
---|
| 88 | }
|
---|
| 89 |
|
---|
| 90 | /**
|
---|
| 91 | * @param input parameter (e.g., an offered price per a {@link Chip},
|
---|
| 92 | * and `n' data points of type T (e.g., as of Double[], Integer[], etc).
|
---|
| 93 | *
|
---|
| 94 | * @return Bezier value of rank `n' for the offered parameter.
|
---|
| 95 | **/
|
---|
| 96 | private double bezier(T[] desired, Double offered)
|
---|
| 97 | {
|
---|
| 98 | double bez = 0.0;
|
---|
| 99 | int n= desired.length;
|
---|
| 100 | for (int i=0; i<n; i++)
|
---|
| 101 | {
|
---|
| 102 | bez = ( (offered < (double) desired[0]) ? 1.0 : ( (offered > (double) desired[n-1]) ? 0.0 : comb(n,i)*Math.pow(1-offered, n)*Math.pow(i, n)*(double)desired[i]));
|
---|
| 103 | }
|
---|
| 104 | return ( (bez>1) ? 1 : (bez<0) ? 0 : bez);
|
---|
| 105 | }
|
---|
| 106 |
|
---|
| 107 | /**
|
---|
| 108 | * @param input parameter (e.g., an offered quantity per a {@link Chip}, and `n+1' data points.
|
---|
| 109 | *
|
---|
| 110 | * @return Bezier value of rank `n+1' for the offered parameter.
|
---|
| 111 | **/
|
---|
| 112 | private double bezier(Integer q, Integer[] desired, Integer offered)
|
---|
| 113 | {
|
---|
| 114 | double bez = 0.0;
|
---|
| 115 | int n = desired.length;
|
---|
| 116 | Integer[] data = new Integer[n+1];
|
---|
| 117 | for (int i = 0; i < (int)Math.ceil(n/2); i++)
|
---|
| 118 | {
|
---|
| 119 | data[i] = desired[i];
|
---|
| 120 | data[n-i] = desired[n-1-i];
|
---|
| 121 | }
|
---|
| 122 | data[(int)Math.ceil(n/2)] = q;
|
---|
| 123 | for (int i=0; i<n+1; i++)
|
---|
| 124 | {
|
---|
| 125 | bez = ( (offered < data[0]) ? 1.0 : ( (offered > data[n]) ? 0.0 : comb(n+1,i)*Math.pow(1-offered, n+1)*Math.pow(i, n+1)*data[i]));
|
---|
| 126 | }
|
---|
| 127 | return ( (bez>1) ? 1 : (bez<0) ? 0 : bez);
|
---|
| 128 | }
|
---|
| 129 |
|
---|
| 130 | /**
|
---|
| 131 | * @return combination of `m' and `k'
|
---|
| 132 | **/
|
---|
| 133 | private int comb(int m, int k)
|
---|
| 134 | {
|
---|
| 135 | return fc(m)/(fc(m-k)*fc(k));
|
---|
| 136 | }
|
---|
| 137 |
|
---|
| 138 | /**
|
---|
| 139 | * @return factorial of `m'
|
---|
| 140 | **/
|
---|
| 141 | private int fc(int m) {
|
---|
| 142 | int result = 1;
|
---|
| 143 | for (; m > 1; m--) {
|
---|
| 144 | result *= m;
|
---|
| 145 | }
|
---|
| 146 | return result;
|
---|
| 147 | }
|
---|
| 148 |
|
---|
| 149 | /**
|
---|
| 150 | * @return an String list of values assigned to a single variable, e.g. list of quantities or prices of a {@link Chip}
|
---|
| 151 | **/
|
---|
| 152 | private String writeT(ChipIssueValue<T[]> t)
|
---|
| 153 | {
|
---|
| 154 | String s = "{";
|
---|
| 155 | T[] j;
|
---|
| 156 | if (t!=null)
|
---|
| 157 | {
|
---|
| 158 | for (Chip c: t)
|
---|
| 159 | {
|
---|
| 160 | s += " " + c.toString() + "={";
|
---|
| 161 | j = t.getUnitValue(c);
|
---|
| 162 | for (int k=0; k<j.length; k++)
|
---|
| 163 | s += j[k].toString()+((k<j.length-1) ? ", " : "");
|
---|
| 164 | s += "}";
|
---|
| 165 | }
|
---|
| 166 | }
|
---|
| 167 | s += " }";
|
---|
| 168 | return s;
|
---|
| 169 | }
|
---|
| 170 |
|
---|
| 171 | private String writeI(ChipIssueValue<Integer[]> t)
|
---|
| 172 | {
|
---|
| 173 | String s = "{";
|
---|
| 174 | Integer[] j;
|
---|
| 175 | if (t!=null)
|
---|
| 176 | {
|
---|
| 177 | for (Chip c: t)
|
---|
| 178 | {
|
---|
| 179 | s += " " + c.toString() + "={";
|
---|
| 180 | j = t.getUnitValue(c);
|
---|
| 181 | for (int k=0; k<j.length; k++)
|
---|
| 182 | s += j[k].toString()+((k<j.length-1) ? ", " : "");
|
---|
| 183 | s += "}";
|
---|
| 184 | }
|
---|
| 185 | }
|
---|
| 186 | s += " }";
|
---|
| 187 | return s;
|
---|
| 188 | }
|
---|
| 189 |
|
---|
| 190 | @Override
|
---|
| 191 | public String toString()
|
---|
| 192 | {
|
---|
| 193 | return this.getClass().getSimpleName() + ": WishList " + wishlist + ": BezierPrice "+ writeT(bezierPrice)+ ": BezierQuantity "+ writeI(bezierQuantity) + ": Colors' weights "+ lambdaC + ": Issue Price's weight "+ lambdaP + ": Issue Quantity's weight " + lambdaQ;
|
---|
| 194 | }
|
---|
| 195 |
|
---|
| 196 | public static void main(String[] args)
|
---|
| 197 | {
|
---|
| 198 | WishList wishlist = new WishListBuilder().addWish("Green", 4).addWish("Yellow", 6).addWish("Orange", 40).build();
|
---|
| 199 | int m=4;
|
---|
| 200 | ChipIssueValue<Double[]> prices = new ChipIssueValueBuilder<Double[]>().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();
|
---|
| 201 | ChipIssueValue<Integer[]> deviations = new ChipIssueValueBuilder<Integer[]>().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();
|
---|
| 202 | ChipIssueValue<Double> wC = new ChipIssueValueBuilder<Double>().addIssue("Green", 0.5).addIssue("Yellow", 0.3).addIssue("Orange", 0.2).build();
|
---|
| 203 | double wP = 0.6;
|
---|
| 204 | double wQ = 0.4;
|
---|
| 205 |
|
---|
| 206 | UF_BezierPriceBezierQuantity<Double> u = new UF_BezierPriceBezierQuantity<Double> (wishlist, m, prices, deviations, wC, wP, wQ);
|
---|
| 207 | System.out.println(u);
|
---|
| 208 |
|
---|
| 209 | Bundle offer = new BundleBuilder()
|
---|
| 210 | .addStack("Green", 2.0, 3)
|
---|
| 211 | .addStack("Yellow", 5.0, 4)
|
---|
| 212 | .addStack("Orange", 1.0, 17)
|
---|
| 213 | //---
|
---|
| 214 | // .addStack("Green", 3.0, 4) //should give utility 1.0 in weighted additive
|
---|
| 215 | // .addStack("Yellow", 5.0, 6)
|
---|
| 216 | // .addStack("Orange", 1.0, 40)
|
---|
| 217 | //---
|
---|
| 218 | // .addStack("Green", 10.0, 1) //should give utility 0.0 in weighted additive
|
---|
| 219 | // .addStack("Yellow", 10.0, 1)
|
---|
| 220 | // .addStack("Orange", 10.0, 1)
|
---|
| 221 | //---
|
---|
| 222 | // .addStack("Red", 1.0, 6)
|
---|
| 223 | // .addStack("Green", 3.0, 15)
|
---|
| 224 | // .addStack("Purple", 0.10, 10)
|
---|
| 225 | .build();
|
---|
| 226 | System.out.println(u.getUtility(offer));
|
---|
| 227 | }
|
---|
| 228 | }
|
---|
| 229 |
|
---|
| 230 |
|
---|