// ************************************************************** // * * // * Spheres -- DiscreteAL.cpp * // * * // * (C) Christian Scheideler, 2003 * // * * // ************************************************************** // DiscreteAL.cpp demonstrates the Discrete Awerbuch-Leighton algorithm // Special definitions and operations provided by Spheres.h: // // - Sphere: class that enables non-blocking method invocations (NMI). // To ensure the correct execution of NMIs, every method in a class // derived from Sphere that is to be called by NMI has to have the form // // void MethodName(usertype *plist) // // where plist is a pointer to any kind of usertype. // // - void Send(SpherePtr, SphereObj::Method, ParList): // This requests to call the method SphereObj::Method in the user object // referenced by SpherePtr using the parameter list referenced by ParList. // // - void Simulate(Time): // This runs a simulation for Time many rounds. // The Spheres.h class provides an environment for the simulation of // concurrent data structures, where concurrent executions are done at the // level of method invocations (i.e. each method invocation completes before // another method is invoked). To avoid inconsistencies in the data structure, // some general rules have to be obeyed: // // - A method may not have any side-effects other than modifying the // data inside the object. // // - A method must be total, meaning that it is well-defined for // EVERY legal state of the object. #include #include #include "Spheres.h" // some global values #define SIZE 9 // adjacency matrix of graph int A[SIZE][SIZE] = {{0,1,0,1,0,0,0,0,0}, {1,0,1,0,1,0,0,0,0}, {0,1,0,0,0,1,0,0,0}, {1,0,0,0,1,0,1,0,0}, {0,1,0,1,0,1,0,1,0}, {0,0,1,0,1,0,0,0,1}, {0,0,0,1,0,0,0,1,0}, {0,0,0,0,1,0,1,0,1}, {0,0,0,0,0,1,0,1,0}}; // parameter list for Node::Sync method class SPList { public: int ID; // origin of sync message int round; // round number of sync float val1; // flow or height value, commodity 1 float val2; // flow or height value, commodity 2 SPList(int i, int r, float v1, float v2) { ID = i; round = r; val1 = v1; val2 = v2; } }; class Node: public Sphere { private: int ID; // own ID int d; // own degree int round; // current round int current[SIZE]; // neighbor syncs for current round int next[SIZE]; // neighbor syncs for next round Node **neighbor; // array of pointers to neighbors int cost[SIZE]; // cost of edges (just 0 or 1 here) float height1[SIZE]; // height of queues for commodity 1 in node float nheight1[SIZE]; // height of queues for commodity 1 in neighbors float height2[SIZE]; // height of queues for commodity 2 float nheight2[SIZE]; // height of queues for commodity 2 in neighbors public: Node(int u) { int v; // set node ID and initialize values ID = u; d = 0; round = 1; // initialize edge costs, heights, and sync indicators for (v=0; v0) d++; height1[v] = 0; nheight1[v] = 0; height2[v] = 0; nheight2[v] = 0; current[v] = 0; next[v] = 0; } } void Connect(Node** np) { neighbor = np; } void SendFlows() { int v, i; float flow1, flow2; SPList *lp; // send flows to neighbors for (v=0; v0) { flow1 = (height1[v]-nheight1[v])/2.0; flow2 = (height2[v]-nheight2[v])/2.0; if (flow1 > flow2) { if (flow1<0) flow1 = 0; if (flow1>1) flow1 = 1; height1[v] -= flow1; flow2 = 0; cout << ID << ": send " << flow1 << " of commodity 1 to " << v << "\n"; } else { if (flow2<0) flow2 = 0; if (flow2>1) flow2 = 1; height2[v] -= flow2; flow1 = 0; cout << ID << ": send " << flow2 << " of commodity 2 to " << v << "\n"; } lp = new SPList(ID, round, flow1, flow2); Send(neighbor[v], Node::Sync, lp); } } void SendHeights() { int v; float flow1, flow2; SPList *lp; // source node: inject new flow if (ID == 0) // s1 { height1[1] += 0.5; height1[3] += 0.5; } if (ID == 6) // s2 { height2[3] += 0.5; height2[7] += 0.5; } // destination node: absorb all flow if (ID == 2) // t2 { height2[1] = 0; height2[5] = 0; } if (ID == 8) // t1 { height1[5] = 0; height1[7] = 0; } // balance heights flow1 = 0; flow2 = 0; for (v=0; v0) { flow1 += height1[v]; flow2 += height2[v]; } flow1 = flow1/(1.0*d); // take average for 1 flow2 = flow2/(1.0*d); // take average for 2 for (v=0; v0) { height1[v] = flow1; height2[v] = flow2; } for (v=0; v0) { cout << ID << ": send heights " << flow1 << "," << flow2 << " to " << v << "\n"; lp = new SPList(ID, round, flow1, flow2); Send(neighbor[v], Node::Sync, lp); } } void Sync(SPList *p) { int v, complete; SPList *lp; if (p->round % 2) { // odd round: add flow from neighbor height1[p->ID] += p->val1; height2[p->ID] += p->val2; } else // even round: update neighbor heights { nheight1[p->ID] = p->val1; nheight2[p->ID] = p->val2; } if (p->round == round) { current[p->ID] = 1; complete = 1; for (v=0; v0 && current[v]==0) complete = 0; if (complete) // received syncs from all neighbors? { // go to next round round++; if (round % 2) SendFlows(); // odd round: send flows else SendHeights(); // even round: send height // reset sync indicators for (v=0; vID] = 1; delete p; } void Start(void *p) { // send flows to neighbors cout << "start " << ID << "\n"; SendFlows(); } }; void main() { int i; // generate set of node objects Node **List = new (Node *)[SIZE]; for (i=0; iConnect(List); // generate requests to call Node::Start in every node of the list for (i=0; i> i; }