Repository navigation
Expand file tree
/
Copy pathExampleAgent.java
More file actions
329 lines (291 loc) · 13.1 KB
/
Copy pathExampleAgent.java
File metadata and controls
329 lines (291 loc) · 13.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
/**
* TAC Supply Chain Management Simulator
* http://www.sics.se/tac/ tac-dev@sics.se
* <p>
* Copyright (c) 2001-2003 SICS AB. All rights reserved.
* <p>
* SICS grants you the right to use, modify, and redistribute this
* software for noncommercial purposes, on the conditions that you:
* (1) retain the original headers, including the copyright notice and
* this text, (2) clearly document the difference between any derived
* software and the original, and (3) acknowledge your use of this
* software in pertaining publications and reports. SICS provides
* this software "as is", without any warranty of any kind. IN NO
* EVENT SHALL SICS BE LIABLE FOR ANY DIRECT, SPECIAL OR INDIRECT,
* PUNITIVE, INCIDENTAL OR CONSEQUENTIAL LOSSES OR DAMAGES ARISING OUT
* OF THE USE OF THE SOFTWARE.
* <p>
* -----------------------------------------------------------------
* <p>
* ExampleAgent
* <p>
* Author : Joakim Eriksson, Niclas Finne, Sverker Janson
* Created : Tue May 06 17:41:55 2003
* Updated : $Date: 2005/06/08 22:34:39 $
* $Revision: 1.13 $
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import java.util.logging.Logger;
import se.sics.tasim.props.*;
import se.sics.tasim.tac03.aw.Order;
import se.sics.tasim.tac03.aw.OrderStore;
import se.sics.tasim.tac03.aw.RFQStore;
import se.sics.tasim.tac03.aw.SCMAgent;
/**
* The <code>ExampleAgent</code> is an example of a simple
* Manufacturer agent using <code>{@link SCMAgent}</code> to simplify
* the implementation.<p>
*
* This example manufacturer uses strict build to order. In optimal
* case be possible to deliver in 6 days (including one day for the
* suppliers to produce the supply).<p>
*
* <dl>
* <dt>Day D:
* <dd>receive RFQ from customer and send offer to customer
* <dt>Day D + 1:
* <dd>receive order from customer and send RFQ to suppliers
* <dt>Day D + 2:
* <dd>receive offers from suppliers and send orders for supply
* <dt>Day D + 3:
* <dd>suppliers produce the requested supply
* <dt>Day D + 4:
* <dd>delivery of supply from suppliers
* <dt>Day D + 5:
* <dd>assembling products
* <dt>Day D + 6:
* <dd>delivery to customer
* </dl>
*<p>
* This means that the example manufacturer will never bid for
* requests with a too short due date.<p>
*
* Features of the example:
* <ul>
* <li> Orders supply from randomly selected supplier
* <li> Pricing based on random function of the reserve price
* <li> Bids on all customer RFQs with sufficiently late due date
* <li> Does not bid for customers orders beyond the end of the game
* <li> Ignores factory capacity limitations when bidding for customer orders
* <li> Assembles the PCs as soon as possible
* <li> Delivers to customers on due date (customers will not pay
* earlier anyway)
* <li> Removes too late orders when the customer cancels them and
* reuses the components/products for other orders.
* <li> Assumes that suppliers will deliver in time
* </ul>
*/
public class ExampleAgent extends SCMAgent {
private static final Logger log = Logger.getLogger(ExampleAgent.class.getName());
private Random random = new Random();
/** Latest possible due date when bidding for customer orders */
private int lastBidDueDate;
/** Offer price discount factor when bidding for customer orders */
private double priceDiscountFactor = 0.2;
/** Bookkeeper for component demand for accepted customer orders */
private InventoryStatus componentDemand = new InventoryStatus();
private double bidProbability = 1.0;
public ExampleAgent() {
}
/**
* Called when the agent received all startup information and it is
* time to start participating in the simulation.
*/
protected void simulationStarted() {
StartInfo info = getStartInfo();
// Calculate the latest possible due date that can be produced for
// and delivered in this game/simulation
this.lastBidDueDate = info.getNumberOfDays() - 2;
}
/**
* Called when a game/simulation has ended and the agent should
* free its resources.
*/
protected void simulationEnded() {
}
/**
* Called when a bundle of RFQs have been received from the
* customers. In TAC03 SCM the customers only send one bundle per
* day and the same RFQs are sent to all manufacturers.
*
* @param rfqBundle a bundle of RFQs
*/
protected void handleCustomerRFQs(RFQBundle rfqBundle) {
BOMBundle bom = getBOMBundle();
for (int i = 0; i < rfqBundle.size(); ++i) {
int dueDate = rfqBundle.getDueDate(i);
if (dueDate - getCurrentDate() < 6 || dueDate > this.lastBidDueDate)
continue;
int reservePricePerUnit = rfqBundle.getReservePricePerUnit(i);
int productIndex = bom.getIndexFor(rfqBundle.getProductID(i));
int productBasePrice = productIndex >= 0 ? bom.getProductBasePrice(productIndex) : 0;
productBasePrice *= 0.9;
if (reservePricePerUnit <= productBasePrice || this.random.nextDouble() >= this.bidProbability)
continue;
//Place yourself on the scale between max price and base price, randomly.
int unitPriceOffer = (int)(productBasePrice + (reservePricePerUnit - productBasePrice)
* (1.0 - this.random.nextDouble() * this.priceDiscountFactor));
addCustomerOffer(rfqBundle, i, unitPriceOffer);
}
sendCustomerOffers();
}
protected void handleFactoryStatus(FactoryStatus status) {
double d = status.getUtilization();
if (d > 0.9) {
this.bidProbability -= 0.1;
if (this.bidProbability < 0.0) {
this.bidProbability = 0.0;
}
} else if (d < 0.4) {
this.bidProbability += 0.05;
if (this.bidProbability > 1.0) {
this.bidProbability = 1.0;
}
}
}
/**
* Called when a bundle of orders have been received from the
* customers. In TAC03 SCM the customers only send one order bundle
* per day as response to offers (and only if they want to order
* something).
*
* @param newOrders the new customer orders
*/
protected void handleCustomerOrders(Order[] newOrders) {
// Add the component demand for the new customer orders
BOMBundle bomBundle = getBOMBundle();
for (int i = 0, n = newOrders.length; i < n; i++) {
Order order = newOrders[i];
int productID = order.getProductID();
int quantity = order.getQuantity();
int[] components = bomBundle.getComponentsForProductID(productID);
if (components != null) {
for (int j = 0, m = components.length; j < m; j++) {
componentDemand.addInventory(components[j], quantity);
}
}
}
// Order the components needed to fulfill the new orders from the suppliers.
ComponentCatalog catalog = getComponentCatalog();
int currentDate = getCurrentDate();
for (int i = 0, n = componentDemand.getProductCount(); i < n; i++) {
int quantity = componentDemand.getQuantity(i);
if (quantity > 0) {
int productID = componentDemand.getProductID(i);
String[] suppliers = catalog.getSuppliersForProduct(productID);
if (suppliers != null) {
// Order all components from one supplier chosen by random for simplicity.
int supIndex = random.nextInt(suppliers.length);
addSupplierRFQ(suppliers[supIndex], productID, quantity,
0, currentDate + 2);
// Assume that the supplier will be able to deliver the
// components and remove this demand.
componentDemand.addInventory(productID, -quantity);
} else {
// There should always be suppliers for all components so
// this point should never be reached.
log.severe("no suppliers for product " + productID);
}
}
}
sendSupplierRFQs();
}
/**
* Called when a bundle of offers have been received from a
* supplier. In TAC03 SCM suppliers only send on offer bundle per
* day in reply to RFQs (and only if they had something to offer).
*
* @param supplierAddress the supplier that sent the offers
* @param offers a bundle of offers
*/
protected void handleSupplierOffers(String supplierAddress, OfferBundle offers) {
// Earliest complete is always after partial offers so the offer
// bundle is traversed backwards to always accept earliest offer
// instead of the partial (the server will ignore the second
// order for the same offer).
for (int i = offers.size() - 1; i >= 0; i--) {
// Only order if quantity > 0 (otherwise it is only a price quote)
if (offers.getQuantity(i) > 0) {
addSupplierOrder(supplierAddress, offers, i);
}
}
sendSupplierOrders();
}
/**
* Called when a simulation status has been received and that all
* messages from the server this day have been received. The next
* message will be for the next day.
*
* @param status a simulation status
*/
protected synchronized void handleSimulationStatus(SimulationStatus status) {
// The inventory for next day is calculated with todays deliveries
// and production and is changed when production and delivery
// requests are made.
InventoryStatus inventory = getInventoryForNextDay();
// Generate production and delivery schedules
int currentDate = getCurrentDate();
int latestDueDate = currentDate - getDaysBeforeVoid() + 2;
OrderStore customerOrders = getCustomerOrders();
Order[] orders = customerOrders.getActiveOrders();
if (orders != null) {
for (int i = 0, n = orders.length; i < n; i++) {
Order order = orders[i];
int productID = order.getProductID();
int dueDate = order.getDueDate();
int orderedQuantity = order.getQuantity();
int inventoryQuantity = inventory.getInventoryQuantity(productID);
if ((currentDate >= (dueDate - 1)) && (dueDate >= latestDueDate)
&& addDeliveryRequest(order)) {
// It was time to deliver this order and it could be
// delivered (the method above ensures this). The order has
// automatically been marked as delivered and the products
// have been removed from the inventory status (to avoid
// delivering the same products again).
} else if (dueDate <= latestDueDate) {
// It is too late to produce and deliver this order
log.info("canceling to late order " + order.getOrderID()
+ " (dueDate=" + order.getDueDate()
+ ",date=" + currentDate + ')');
cancelCustomerOrder(order);
} else if (inventoryQuantity >= orderedQuantity) {
// There is enough products in the inventory to fulfill this
// order and nothing more should be produced for it. However
// to avoid reusing these products for another order they
// must be reserved.
reserveInventoryForNextDay(productID, orderedQuantity);
} else if (addProductionRequest(productID,
orderedQuantity - inventoryQuantity)) {
// The method above will ensure that the needed components
// was available and that the factory had enough free
// capacity. It also removed the needed components from the
// inventory status.
// Any existing products have been allocated to this order
// and must be reserved to avoid using them in another
// production or delivery.
reserveInventoryForNextDay(productID, inventoryQuantity);
} else {
// Otherwise the production could not be done (lack of
// free factory cycles or not enough components in
// inventory) and nothing can be done for this order at
// this time.
}
}
}
sendFactorySchedules();
}
private void cancelCustomerOrder(Order order) {
order.setCanceled();
// The components for the canceled order are now available to be
// used in other orders.
int[] components = getBOMBundle().getComponentsForProductID(order.getProductID());
if (components != null) {
int quantity = order.getQuantity();
for (int j = 0, m = components.length; j < m; j++) {
componentDemand.addInventory(components[j], -quantity);
}
}
}
} // ExampleAgent