import java.util.LinkedList; import java.util.Vector; import java.util.Iterator; /** *

* Stores the topology of an instantaneous communication graph, as well * as the message queues between each pair of robots connected in the graph. * Can be used to hold directed and undirected edges. * Edge addition functions copy message queues from prior graph, if one * is provided. *

* Graph representation is in the form of two adjacency lists * (see * http://www.nist.gov/dads/HTML/adjacencyListRep.html for * documentation on adjacency lists) (also see Cormen, Leierson, Rivest, Stein * Chapter 22) * One adjacency list is for quick lookup for all edges incoming to a * particular node, the other is for all edges outgoing to a particular node. * The two structures edge share representation memory for each shared edge. *

* @author Michael Schuresko * @version %I%, %G% * @since 1.0 */ public class CommGraph { Vector > m_adjListTo; Vector > m_adjListFrom; IMsgChannel m_channelToClone; public CommGraph() { m_adjListTo = m_adjListFrom = null; m_channelToClone = new MsgQueue(); } /** * Creates an empty graph (no edges) on nNumNodes nodes */ public CommGraph(int nNumNodes) { m_adjListTo = new Vector >(nNumNodes); m_adjListFrom = new Vector >(nNumNodes); // Make sure we never have an empty linked list in here for(int i = 0; i < nNumNodes; ++i) { m_adjListTo.add(i,new LinkedList()); m_adjListFrom.add(i,new LinkedList()); } m_channelToClone = new MsgQueue(); } /** * Copy constructor -- performs deep copy of graph */ public CommGraph(CommGraph src) { m_channelToClone = src.m_channelToClone.makeCopy(); int nSrcCapacity = src.m_adjListTo.capacity(); m_adjListTo = new Vector >(nSrcCapacity); nSrcCapacity = src.m_adjListFrom.capacity(); m_adjListFrom = new Vector >(nSrcCapacity); for(int i = 0; i < nSrcCapacity; ++i) { m_adjListTo.add(i, new LinkedList()); m_adjListFrom.add(i, new LinkedList()); Iterator iterTo = src.getEdgesTo(i); while(iterTo.hasNext()) { CommLink currLink = (CommLink)iterTo.next(); m_adjListTo.get(i).addLast(new CommLink(currLink)); } Iterator iterFrom = src.getEdgesFrom(i); while(iterFrom.hasNext()) { CommLink currLink = (CommLink)iterFrom.next(); m_adjListFrom.get(i).addLast(new CommLink(currLink)); } } } /** * Changes the default channel type for new links * new channels are all of the same type as channelToClone */ public void setChannelType(IMsgChannel channelToClone) { m_channelToClone = channelToClone.makeCopy(); } public IMsgChannel getChannelType() { return m_channelToClone.makeCopy(); } /** * @param nNodeFrom node to get outgoing edges of * @return iterator for list of outgoing edges of nNodeFrom * Each iterator element should be cast to type CommLink. */ public Iterator getEdgesFrom(int nNodeFrom) { return m_adjListFrom.elementAt(nNodeFrom).iterator(); } /** * @param nNodeTo node to get incoming edges of * @return iterator for list of incoming edges of nNodeTo * Each iterator element should be cast to type CommLink. */ public Iterator getEdgesTo(int nNodeTo) { return m_adjListTo.elementAt(nNodeTo).iterator(); } /** * Insert an exsting CommLink into this graph. * @param link link to insert */ public void insertExistLink(CommLink link) { // Don't check for error, instead force the exception. m_adjListTo.elementAt(link.to()).addLast(link); m_adjListFrom.elementAt(link.from()).addLast(link); } /** * Clones a link between two nodes (if it exists) * Used internally by addLink * @param iSrc source of link to clone * @param iDst dest of link to clone * @return copy of link from iSrc to iDst, or new link if none exists */ CommLink cloneLink(int iSrc, int iDst) { LinkedList lToSearch = m_adjListFrom.get(iSrc); CommLink toClone = null; for(Iterator I = lToSearch.iterator(); I.hasNext();) { CommLink currListEl = (CommLink)I.next(); if(currListEl != null && currListEl.to() == iDst) { toClone = currListEl; } } if(toClone != null) { return new CommLink(toClone); } return new CommLink(iSrc, iDst, m_channelToClone.makeLazyCopy()); } /** * Adds a new link (directed edge) to a graph. * Copies channel from previous state communication graph if * available * @param iSrc source index of link to add * @param iDst destination index of link to add * @param gCopyLinksFrom previous graph (to copy communication channels from if available) Can be null. * @return newly created link */ public CommLink addLink(int iSrc, int iDst, CommGraph gCopyLinksFrom) { CommLink linkNew = null; if(gCopyLinksFrom == null) { linkNew = new CommLink(iSrc, iDst, m_channelToClone); } else { linkNew = gCopyLinksFrom.cloneLink(iSrc, iDst); } insertExistLink(linkNew); return linkNew; } /** * Adds a new link (directed edge) to a graph. * Copies channel from previous state communication graph if * available * @param iSrc source index of link to add * @param iDst destination index of link to add * @param channelData associated channel data * @param gCopyLinksFrom previous graph (to copy communication channels from if available) Can be null. * @return newly created link */ public CommLink addLink(int iSrc, int iDst, CommLink.IChannelData channelData, CommGraph gCopyLinksFrom) { CommLink linkNew = null; if(gCopyLinksFrom == null) { linkNew = new CommLink(iSrc, iDst, m_channelToClone); } else { linkNew = gCopyLinksFrom.cloneLink(iSrc, iDst); } linkNew.setChannelData(channelData); insertExistLink(linkNew); return linkNew; } /** * @return Number of nodes in graph */ public int getSize() { if(m_adjListTo == null) { return 0; } return m_adjListTo.capacity(); } }