import java.util.Iterator;
/**
*
* Implementation of IAgent for formation morphing algorithm.
*
*
* Associated state is described in TreeAgentState
*
* @author Michael Schuresko
* @version %I%, %G%
* @since 1.0
* @see TreeAgentState
*/
public class MorphAgentTestAlg implements IAgent
{
IMorphSpec m_shapeDesc;
double m_lfVel;
double m_lfTCom;
double m_lfD1, m_lfD2;
public MorphAgentTestAlg()
{
m_lfVel = 1.0;
}
public MorphAgentTestAlg(double lfRobotVelocity)
{
m_lfVel = lfRobotVelocity;
m_shapeDesc = new MorphSpecCombRect(); // dumb default
}
public MorphAgentTestAlg(MorphAgentTestAlg src)
{
m_lfVel = src.m_lfVel;
m_shapeDesc = src.m_shapeDesc; //hopefully these things
// will not be dynamic!
}
public void setMotionParams(double lfVel, double lfTCom, double lfRad)
{
m_lfVel = lfVel; m_lfTCom = lfTCom;
m_lfD2 = lfRad;
m_lfD1 = m_lfD2 - 2.0*m_lfTCom*m_lfVel;
}
/**
* checks that a particular discrete state is valid for this agent.
*/
public boolean checkStateValidity(StateBundle state)
{
if(state == null) { return false; }
TreeAgentState stateCast = (TreeAgentState)(state.getVars());
if(stateCast != null &&
state.getControlFunc() != null &&
state.getControlFunc().getNumStateVars() == 2)
{
return true;
}
return false;
}
// Discrete state components
/**
* Given the state of an agent, and the channels
* it can send messages on, push the next set of messages
* onto the appropriate channels.
* Channels are assumed to be modified by this operation.
* One weakness of this signature is that it requires
* programmer discipline not to look at the continuous state
* of agents other then your neighbors.
* @param state discrete component of agent state
* @param arrLfStateCont global vector of continuous state
* @param nIdxStateOffset offset into global state vector
* corresonding to this agent.
* @param channelsToSendOn Iterator containing objects of type
* CommLink CommLink corresponding to channels to send messages
* on (neighbor indices can be ascertained from channels).
* @see CommLink
* @since 1.0
*/
public void getMsgs(ILogicVarBundle state,
IDiscreteDynamicsCallback dynCallback,
double [] arrLfStateCont,
double lfCurrTime,
int nIdxStateOffset,
Iterator channelsToSendOn)
{
try {
dynCallback.doCallback(state, arrLfStateCont);
TreeMsg msg =
new TreeMsg((TreeAgentState)state,
arrLfStateCont,
nIdxStateOffset/2);
while(channelsToSendOn.hasNext()) {
CommLink linkSendOn =
(CommLink)channelsToSendOn.next();
if(linkSendOn != null && linkSendOn.queue() != null) {
linkSendOn.queue().sendMsg(new TreeMsg(msg) );
}
}
} catch(java.lang.ClassCastException e) {
// send nothing
}
}
/**
* Given the previous state of an agent, and the channels
* to recieve messages from, recieve messages (destructively)
* and return new state (non-destructively).
* @param statePrev previous state (do not modify)
* @param arrLfStateCont vector of all continuous states (do not modify)
* @param nIdxStateOffset offset into arrLfStateCont corresponding to
* start of this agents continuous variables
* @param channelsRecieveFrom iterator storing CommLink
* classes corresponding incoming channels
* @see CommLink
* @return new discrete state of agent
*/
public StateBundle updateState(ILogicVarBundle statePrev,
double [] arrLfStateCont, double lfCurrTime,
int nIdxStateOffset, IEnvironment env,
Iterator channelsRecieveFrom)
{
if(statePrev == null) {
return new StateBundle(new TreeAgentState(),
new ControlFuncDoNothing(2));
}
TreeAgentState state = null;
try {
state = (TreeAgentState)statePrev;
} catch(java.lang.ClassCastException e) {
return new StateBundle(new TreeAgentState(),
new ControlFuncDoNothing(2));
}
TreeAgentState stateOut = new TreeAgentState(state);
double [] arrLfTarget = new double[2];
arrLfTarget[0] = arrLfStateCont[nIdxStateOffset];
arrLfTarget[1] = arrLfStateCont[nIdxStateOffset+1];
int nId = nIdxStateOffset/2;
stateOut.setTargetConfig(m_shapeDesc.getTopoDepth(nId),
m_shapeDesc.getTopoFirstVisit(nId),
m_shapeDesc.getTopoLastVisit(nId),
m_shapeDesc.getNumChildren(nId));
switch(stateOut.getCurrRound()) {
case TreeAgentState.ROUND_ATTACH :
break;
case TreeAgentState.ROUND_UPDATE_DEPTH :
break;
case TreeAgentState.ROUND_SET_PARLESS :
break;
case TreeAgentState.ROUND_PROPOSE_NEW :
break;
default :
// somehow flag this as an error
break;
}
if(stateOut.getDfsFinished() == false) {
doDfsPhase(stateOut, arrLfTarget, channelsRecieveFrom);
}
else {
if(stateOut.getAlgVars().getBoolVar(new Integer(1)).booleanValue()
== false) {
doPhase1(stateOut, arrLfTarget, channelsRecieveFrom);
if(stateOut.getAlgVars().getBoolVar(new
Integer(1)).booleanValue()
== true) {
arrLfTarget[0] = arrLfStateCont[nIdxStateOffset];
arrLfTarget[1] = arrLfStateCont[nIdxStateOffset+1];
}
}
else {
doPhase2(stateOut, arrLfTarget,
arrLfStateCont, nIdxStateOffset,
channelsRecieveFrom);
if(false) {
arrLfTarget[0] = arrLfStateCont[nIdxStateOffset];
arrLfTarget[1] = arrLfStateCont[nIdxStateOffset+1];
}
}
int nParentId = stateOut.getParentId();
double lfSqrdDst = (arrLfStateCont[nIdxStateOffset]-
arrLfStateCont[2*nParentId])*
(arrLfStateCont[nIdxStateOffset]-
arrLfStateCont[2*nParentId]) +
(arrLfStateCont[nIdxStateOffset+1]-
arrLfStateCont[2*nParentId+1])*
(arrLfStateCont[nIdxStateOffset+1]-
arrLfStateCont[2*nParentId+1]);
if(Math.sqrt(lfSqrdDst) > m_lfD1) {
arrLfTarget[0] = arrLfStateCont[2*nParentId];
arrLfTarget[1] = arrLfStateCont[2*nParentId+1];
}
}
if(nIdxStateOffset == 0) {
arrLfTarget[0] = arrLfStateCont[nIdxStateOffset];
arrLfTarget[1] = arrLfStateCont[nIdxStateOffset+1];
}
return new StateBundle(stateOut,
new ControlFuncMoveTowards(arrLfTarget,
m_lfVel));
}
void doDfsPhase(TreeAgentState stateToUpdate,
double [] arrLfNewTarget,
Iterator channelsRecieveFrom)
{
// try {
int nId = -1;
if(stateToUpdate.getParentId() < 0) {
// wait till we find a parent
while(channelsRecieveFrom.hasNext()) {
CommLink linkRecvFrom =
(CommLink)channelsRecieveFrom.next();
nId = linkRecvFrom.to();
if(linkRecvFrom != null && linkRecvFrom.queue() != null) {
IMsg currMsg =
linkRecvFrom.queue().readMsg();
if(currMsg != null) {
TreeMsg currTreeMsg = (TreeMsg)currMsg;
TreeAgentState senderState =
(TreeAgentState)(currTreeMsg.getState());
if(senderState.getParentId() >= 0 ||
linkRecvFrom.from() == 0) {
if(linkRecvFrom.to() > 0 &&
stateToUpdate.getParentId() < 0) {
stateToUpdate.setParentId(linkRecvFrom.from());
stateToUpdate.setDepthEst(senderState.
getDepthEst()+1);
}
}
}
}
}
}
else {
// wait till our children all settle down
boolean bSettled = true;
while(channelsRecieveFrom.hasNext()) {
CommLink linkRecvFrom =
(CommLink)channelsRecieveFrom.next();
if(linkRecvFrom != null && linkRecvFrom.queue() != null) {
IMsg currMsg =
linkRecvFrom.queue().readMsg();
if(currMsg != null) {
TreeMsg currTreeMsg = (TreeMsg)currMsg;
TreeAgentState senderState =
(TreeAgentState)(currTreeMsg.getState());
if(senderState.getParentId() < 0)
{
bSettled = false;
}
if(senderState.getParentId() ==
linkRecvFrom.to() &&
linkRecvFrom.to() != 0 &&
senderState.getDfsFinished() != true)
{
bSettled = false;
}
if(linkRecvFrom.from() == stateToUpdate.getParentId()
&& linkRecvFrom.to() != 0)
{
stateToUpdate.setDepthEst(senderState.
getDepthEst()+1);
}
}
}
}
stateToUpdate.setDfsFinished(bSettled);
}
if(nId == 0)
{
System.out.println("Phase Dfs, root bot\n");
stateToUpdate.setParentId(0);
stateToUpdate.setDepthEst(0);
}
// } catch(java.lang.ClassCastException e) {
// // if we recieve an invalid message, abort silently
//}
stateToUpdate.getAlgVars().insertBoolVar(new Integer(1), false);
}
void doPhase1(TreeAgentState stateToUpdate,
double [] arrLfNewTarget,
Iterator channelsRecieveFrom)
{
// int nNewParent = stateToUpdate.getParentId();
double [] arrLfTargTmp = null;
int nId = -1;
int nMaxDepth = -1;
int nDepthEst = stateToUpdate.getDepthEst();
boolean bChildrenFinished = true;
while(channelsRecieveFrom.hasNext()) {
CommLink linkRecvFrom =
(CommLink)channelsRecieveFrom.next();
if(linkRecvFrom != null && linkRecvFrom.queue() != null) {
IMsg currMsg =
linkRecvFrom.queue().readMsg();
if(currMsg != null) {
TreeMsg currTreeMsg = (TreeMsg)currMsg;
TreeAgentState senderState =
(TreeAgentState)(currTreeMsg.getState());
nId = linkRecvFrom.to();
if(senderState.isAncest(stateToUpdate) &&
senderState.getTargetDepth() > nMaxDepth)
{
if(
senderState.getDepthEst() <
stateToUpdate.getDepthEst() &&
senderState.getDfsFinished() == true) {
nMaxDepth = senderState.getTargetDepth();
stateToUpdate.setParentId(linkRecvFrom.from());
}
}
if(senderState.getDepthEst() <
stateToUpdate.getDepthEst() -1 &&
nMaxDepth < 0 &&
senderState.getDfsFinished() == true)
{
stateToUpdate.setParentId(linkRecvFrom.from());
}
if(linkRecvFrom.from() == stateToUpdate.getParentId())
{
System.out.println(nId+" -- "+
senderState.getFirstVisit() +
", "+
senderState.getLastVisit()+
"\t|\t"+
stateToUpdate.getFirstVisit()
+", "+
stateToUpdate.getLastVisit());
System.out.println("children finished == "+
bChildrenFinished +
" and isAncest == " +
senderState.isAncest(stateToUpdate));
nDepthEst =
senderState.getDepthEst()+1;
if(nMaxDepth < 0) {
arrLfNewTarget[0] = 0.0;
arrLfNewTarget[1] = 0.0;
arrLfTargTmp =
currTreeMsg.getPhase1Targ(m_lfD1);
arrLfNewTarget[0] = arrLfTargTmp[0];
arrLfNewTarget[1] = arrLfTargTmp[1];
}
} else if(senderState.getParentId() ==
linkRecvFrom.to() &&
linkRecvFrom.from() != linkRecvFrom.to()) {
nId = linkRecvFrom.to();
boolean bPhase1 = senderState.getAlgVars().
getBoolVar(new Integer(1)).booleanValue();
bChildrenFinished = bChildrenFinished &&
bPhase1;
}
}
}
}
if(nId == 0) {
nDepthEst = 0;
nMaxDepth = 0;
System.out.println("Phase 1, root bot\n");
}
if(nDepthEst - stateToUpdate.getDepthEst() > 1) {
System.out.println("Illogical Jump\n");
}
System.out.println("Robot "+nId+" goes from "+
stateToUpdate.getDepthEst()+
" to "+nDepthEst +
" parentId is "+
stateToUpdate.getParentId()+
" nMaxDetph is "+nMaxDepth);
stateToUpdate.setDepthEst(nDepthEst);
if(bChildrenFinished && nMaxDepth >= 0) {
stateToUpdate.getAlgVars().insertBoolVar(new Integer(1), true);
System.out.println("Robot "+nId+" has completed phase 1\n");
}
}
void doPhase2(TreeAgentState stateToUpdate,
double [] arrLfNewTarget,
double [] arrLfWorldState, int nIdxAgentOffset,
Iterator channelsRecieveFrom)
{
// int nNewParent = stateToUpdate.getParentId();
double [] arrLfTargTmp = null;
int nMaxDepth = -1;
int nDepthEst= stateToUpdate.getDepthEst();
int nId = -1;
while(channelsRecieveFrom.hasNext()) {
CommLink linkRecvFrom =
(CommLink)channelsRecieveFrom.next();
nId = linkRecvFrom.to();
if(linkRecvFrom != null && linkRecvFrom.queue() != null) {
IMsg currMsg =
linkRecvFrom.queue().readMsg();
if(currMsg != null) {
TreeMsg currTreeMsg = (TreeMsg)currMsg;
TreeAgentState senderState =
(TreeAgentState)(currTreeMsg.getState());
if(senderState.isAncest(stateToUpdate) &&
senderState.getTargetDepth() > nMaxDepth &&
( senderState.getParentId() ==
stateToUpdate.getParentId() ||
senderState.getDepthEst() <
stateToUpdate.getDepthEst()
) &&
senderState.getDfsFinished() == true)
{
nMaxDepth = senderState.getTargetDepth();
stateToUpdate.setParentId(linkRecvFrom.from());
}
if(linkRecvFrom.from() == stateToUpdate.getParentId())
{
nDepthEst = senderState.getDepthEst() +1;
if(nMaxDepth < stateToUpdate.getTargetDepth()-1) {
arrLfNewTarget[0] = 0.0;
arrLfNewTarget[1] = 0.0;
arrLfTargTmp =
currTreeMsg.getPhase2Targ(arrLfWorldState,
nIdxAgentOffset,
m_lfVel*
m_lfTCom
);
arrLfNewTarget[0] = arrLfTargTmp[0];
arrLfNewTarget[1] = arrLfTargTmp[1];
} else {
arrLfTargTmp =
m_shapeDesc.getFinalUv(nIdxAgentOffset/2);
// arrLfTargTmp[0] = 0.0;
// arrLfTargTmp[1] = 0.0;
arrLfTargTmp =
currTreeMsg.uvToWorld(arrLfTargTmp,
0);
arrLfNewTarget[0] = arrLfTargTmp[0];
arrLfNewTarget[1] = arrLfTargTmp[1];
}
}
}
}
}
if(nId == 0) {
nDepthEst = 0;
System.out.println("Phase 2, root bot\n");
}
stateToUpdate.setDepthEst(nDepthEst);
}
/**
* in case the agent has some internal state, this
* allows syncrhonized wrapper calls to cache a snapshot of the
* agent at some rational point in time.
* If the agent has no internal state, this function can just return
* "this".
*/
public IAgent makeCopy() { return new MorphAgentTestAlg(this); }
}