Interactive Operation of the MAGNET Customer Agent components
Prior to the Agents 2001 demo, the default mode of operation was
non-interactive. The Agent components were designed originally to
support bid-evaluation experiments, using
XAutoCustomer
as the top-level class. The demo requires interactive control of individual
components. Several Mantis bug reports relate to this issue,
including 6, 8, 16, 57, 59, 60, 63.
The first step in this transformation was to implement the bid process
timeline in the time map, and to use PropertyChangeEvents to
notify interested parties about state changes, incoming bids, etc.
The second step is to deconstruct the
BidManager
to allow for independent control of its elements, since this is where
most of the automation is happening.
Currently, you start up a BidManager by creating one with a
SessionStatus
instance (which has as a parent a
PlanStatus
instance containing your initial
TaskBidPlan)
and a Properties instance (presumably this is the one from
MagnetProperties,
but you are free to
create your own). It then creates a
BidScheduler
and a
TaskDurationAdjuster,
for later use. The specific subclasses used are controled by property
settings.
You then start up the BidManager by calling its
handleBids method, and it fires off a thread
that does the following:
- Uses its BidScheduler to generate an agenda. Currently
the only thing that gets put on the agenda is instances of
BidCommand.
You can get multiple entries on the agenda if you use a
BidScheduler that breaks down the bidding process into
multiple phases. Eventually, you could also get multiple instances if
you were bidding in multiple markets.
- Sends some statistics to the log files.
- Runs each BidCommand in turn, until the agenda is empty.
Running a bid command (see the method doBidCommand) involves
these steps:
- Sets the state of each task in the bid command to
TaskStatus.OFFERED.
- Sets the time windows on the tasks to be submitted with the RFQ,
using a
PlanTWAdjuster,
which wraps and controls the TaskDurationAdjuster. The
original
SubtaskRequest
instances are modified in this step.
- Creates a new TaskPlan, containing only the tasks to be bid out
in the current cycle.
- Composes an
RFQ,
containing the reconstructed TaskPlan, and timing info from the
BidCommand.
- Creates an
RFQStatus
instance to monitor and control the bidding process itself.
- Registers for state change events emitted by the
RFQStatus instance. The listener calls the
summarizeBids method when the state changes to
RFQStatus.BIDS_ACQUIRED.
- Creates a new
BidEvaluator
instance and initializes it. The BidEvaluator will
register with the RFQStatus instance for new
bids, and for the BIDS_ACQUIRED state change. When the state
change occurs, the BidEvaluator will proceed to evaluate the
bids, using the settings available in MagnetProperties.
- Invokes the acquireBids() method on the
RFQStatus instance to send out the RFQ and gather in the
bids. The RFQStatus instance issues NewBid events when new
bids arrive, and State events when the bidding closes, and again
when all bids have arrived.
- Waits for the BidEvaluator to finish its work by
calling its getResult() method, which will block until the
BidEvaluator has finished, and then return the search
result.
- If the BidEvaluator returned a non-null result, sets
each of the tasks in the RFQ to the TaskStatus.PENDING
state, which indicates that an award decision has been made.
- Reports the results of the whole process (the result is embodied
in the final TaskBidPlan).
This scheme works quite well for running bid-evaluation experiments.
However, interactive operation needs to be able to access and control
at least some of these steps independently. With the background given
above, let's examine the three relevant
Use Cases from the demo
requirements documentation.
- Compose RFQ
- This is basically steps 3.1-3.4 above. In interactive mode, you
have to create a BidManager, but don't start it. Then create a
BidCommand and call the
BidManager's composeRFQ(BidCommand) method, which returns the RFQ.
Time window settings will be controlled by the Properties object you
hand to the BidManager when you create it. Here's the basic process:
-
The methods of BidManager, including composeRFQ()
work against a
TaskBidPlan,
rather than directly against the TaskPlan. It gets the TBP
from the PlanStatus, which creates it during initialization
from the TaskPlan you supply. This is because the embedded
TaskBid
instances contain the necessary fields for the Critical Path (CPM)
algorithm to work against.
-
Normally, unless there's some particular reason to constrain the
start or end time of a task, the early start and late finish times
of the SubtaskRequest objects are null at this point. They
will be computed during this process.
-
All tasks specified in the BidCommand are put into the
OFFERED state. Once in this state, they should no longer
be editable.
-
A TaskDurationAdjuster (TDA) was created by the
BidManager at init time, as specified above. The specific
class of TDA is controlled by "TDA.Type" property.
-
A new PlanTWAdjuster is created. Its
setTimeWindows method is called with the current
TaskBidPlan, the plan start date, the plan slack ratio,
and the selected TDA. This method uses a version of the CPM
algorithm (other algorithms are under investigation) to update the
early start and late finish times in the underlying
SubtaskRequest objects. This is done in the following steps:
Currently, this process neither honors nor updates the planDeadline
property of the PlanStatus. This is a bug (#0000096).
After the time windows are computed, an RFQ instance is
created and filled in. The tasks are the ones in the OFFERED
state as specified in the BidCommane, and the RFQ timings
(bid deadline, early consider, early offer) are also taken from the
BidCommand. The Session ID and Agent ID are also set in the
RFQ (but see bugs #0000095 and #0000097).
Once the RFQ is composed, it can be viewed and further edited, before
passing it off to the next step. Note that you might want to wait to
set the RFQ time factors until that step (or set them again), even
though they are getting set in composeRFQ.
- Manage Bidding Process
- This is steps 3.5, 3.6, and 3.8 above. Steps 3.5 and 3.6 are
accomplished by calling BidManager.createRFQStatus(RFQ). You get back
the RFQStatus instance, which you can then use to register for events,
issue the RFQ, and retrieve bids. Step 3.8 is accomplished by calling
acquireBids() on the RFQStatus instance.
- Evaluate Bids
- This is steps 3.7, 3.9, and 3.10 above. You can simply call the
same methods the BidManager would call to run the BidEvaluator. If
you do this after the RFQStatus instance has already reached the
BIDS_ACQUIRED state, then no bids will be sent to the
BidEvaluator by the RFQStatus, and the state change event that causes
the BidEvaluator to run its search will not occur. That means you
have to call addBid(Bid) on the BidEvaluator for each
bid you want it to consider, and you have to call its
evaluateBids() method to run the search. You
can complete the BidManager's job by calling its
setCurrentPlan(TaskBidPlan) method with
the final TaskBidPlan you get from your evaluation process.
For more control of the evaluation process, the BidEvaluator now
offers PropertyChangeEvents and an alternative mode of activation.
Here's the process:
-
Create the BidEvaluator and initialize it. Initialization consists of
evaluator.setProperties(properties);
evaluator.setSessionId(sessionId);
evaluator.setPlanStatus(planStatus);
evaluator.setRFQStatus(rfqStatus);
where that last step will cause the new evaluator to register with
the RFQStatus object for new bid and state change events. The
search type(s) is set in the properties object. Search types and
other property settings can be found
here under the "Evaluation
Parameters" and "Search Control" headings. If multiple search
types are specified they will (currently) be run serially. The
evaluator is now ready to run a search, but the search hasn't been
started.
-
For each bid you wish to have considered in the evaluation, call
evaluator.addBid(bid).
-
Register with the BidEvaluator for property change events. You do
this by calling its addListener(PropertyChangeListener)
method. The events will be of class
BidEvaluatorEvent.
Events will carry one of the following property names:
- BidEvaluator.NEW_RESULT
- Emitted when the search turns up a new "best result". The
newValue property of the event will contain the TaskBidPlan
that represents the new result.
- BidEvaluator.SEARCH_COMPLETE
- Emitted when a search has completed normally. The
TaskBidPlan representing the search result will be included as
the newValue of the event.
- BidEvaluator.SEARCH_ABORTED
- Emitted when a search has been aborted by calling
abortSearch on the BidEvaluator. The
TaskBidPlan representing the best result found so far will be
included as the newValue of the event.
-
Call the startSearch() method on the BidEvaluator. This
will start the specified search(s) in a new thread. Events will
be thrown as the search progresses.
-
If you wish to apply a time limit to the search, you can create a
new
TMEntry
with an action that calls the BidEvaluator's abortSearch()
method. Then add the new TMEntry to the
TimeMap
of the current
PlanStatus
instance. You do that by calling the addEntry(TMEntry)
method. Just remember that the times represented by TMEntry
instances are scaled in accordance with the current
AgentTime
settings. If you don't want to mess with scaled time, you can use
an
AbsoluteDelay
instance instead, but then you won't be using the TimeMap.
Copyright: © 1999, 2000 by the Regents of the University
of Minnesota
Department of Computer Science and
Engineering. All rights reserved.
The University of Minnesota is an equal opportunity educator and
employer.
$Id: interactive.html,v 1.4.2.1 2002/05/08 00:27:51 jcollins Exp $