Chapter 3

Coordination Mechanisms

弘益人間 (홍익인간) · Benefit All Humanity

Coordination is the art of harmonizing individual actions toward collective goals. Like an orchestra where each musician plays their part in perfect synchrony, multi-agent systems achieve remarkable outcomes through sophisticated coordination mechanisms that ensure agents work together effectively for the benefit of all.

The Need for Coordination

In multi-agent systems, coordination addresses the challenge of managing interdependencies between agents' activities. Without coordination, agents might work at cross-purposes, duplicate efforts, or create conflicts that prevent the system from achieving its goals.

Definition: Coordination is the process of managing dependencies between activities performed by different agents to ensure coherent system behavior and goal achievement.

Coordination becomes necessary when:

Centralized vs. Decentralized Coordination

Centralized Coordination

A central coordinator agent manages all coordination decisions. This approach provides global optimization but creates a single point of failure and scalability bottleneck.

class CentralCoordinator {
    constructor() {
        this.agents = new Map();
        this.tasks = [];
        this.schedule = [];
    }

    registerAgent(agent) {
        this.agents.set(agent.id, {
            agent: agent,
            capabilities: agent.getCapabilities(),
            currentLoad: 0,
            status: 'available'
        });
    }

    allocateTasks(tasks) {
        // Central coordinator makes all allocation decisions
        const allocation = new Map();

        for (const task of tasks) {
            const bestAgent = this.findBestAgent(task);
            if (bestAgent) {
                allocation.set(task.id, bestAgent.id);
                bestAgent.currentLoad += task.estimatedEffort;
            }
        }

        return this.executeAllocation(allocation);
    }

    findBestAgent(task) {
        let best = null;
        let bestScore = -Infinity;

        for (const [id, agentInfo] of this.agents) {
            if (!agentInfo.agent.canPerform(task)) continue;

            const score = this.scoreAgent(agentInfo, task);
            if (score > bestScore) {
                bestScore = score;
                best = agentInfo;
            }
        }

        return best;
    }

    scoreAgent(agentInfo, task) {
        // Score based on capability match, current load, and availability
        const capabilityScore = this.matchCapabilities(
            agentInfo.capabilities,
            task.requirements
        );
        const loadScore = 100 - agentInfo.currentLoad;

        return capabilityScore * 0.7 + loadScore * 0.3;
    }
}

// 弘益人間: Central coordination for global optimization

Decentralized Coordination

Agents coordinate through peer-to-peer interactions without a central authority. This provides better scalability and robustness but may not achieve global optimization.

class DecentralizedAgent {
    constructor(id) {
        this.id = id;
        this.neighbors = [];
        this.state = { tasks: [], resources: {} };
    }

    async coordinateWithNeighbors(task) {
        // Decentralized coordination through local interactions
        const proposals = [];

        for (const neighbor of this.neighbors) {
            const proposal = await this.negotiateWithNeighbor(neighbor, task);
            if (proposal) proposals.push(proposal);
        }

        return this.selectBestProposal(proposals);
    }

    async negotiateWithNeighbor(neighbor, task) {
        // Peer-to-peer negotiation
        const canHelp = await neighbor.canAssist(task);

        if (canHelp) {
            const cost = await neighbor.calculateCost(task);
            return { neighborId: neighbor.id, cost: cost };
        }

        return null;
    }

    // Consensus through local voting
    async reachLocalConsensus(decision) {
        const votes = await Promise.all(
            this.neighbors.map(n => n.vote(decision))
        );

        const favor = votes.filter(v => v === true).length;
        const total = votes.length;

        return favor / total > 0.5; // Majority consensus
    }
}

// 弘益人間: Decentralized coordination empowering all agents

Negotiation Mechanisms

Negotiation allows agents to reach agreements through iterative proposal and counter-proposal exchanges.

Monotonic Concession Protocol

Agents make successive concessions until agreement is reached or negotiations fail.

class NegotiatingAgent {
    constructor(id, initialPosition, minAcceptable) {
        this.id = id;
        this.position = initialPosition;
        this.minAcceptable = minAcceptable;
        this.concessionRate = 0.1;
    }

    async negotiate(otherAgent, issue) {
        let round = 0;
        const maxRounds = 10;

        while (round < maxRounds) {
            // Make proposal
            const myProposal = this.makeProposal(issue);
            const theirProposal = await otherAgent.receiveProposal(myProposal);

            // Check if proposals overlap (agreement zone)
            if (this.isAcceptable(theirProposal)) {
                return this.formAgreement(myProposal, theirProposal);
            }

            // Make concession
            this.makeConcession(theirProposal);
            round++;
        }

        return null; // Negotiation failed
    }

    makeProposal(issue) {
        return {
            agent: this.id,
            issue: issue,
            value: this.position,
            round: this.currentRound
        };
    }

    isAcceptable(proposal) {
        return proposal.value >= this.minAcceptable;
    }

    makeConcession(theirProposal) {
        // Move toward their position
        const gap = theirProposal.value - this.position;
        this.position += gap * this.concessionRate;

        // Don't go below minimum
        this.position = Math.max(this.position, this.minAcceptable);
    }

    formAgreement(myProposal, theirProposal) {
        // Split the difference
        return {
            agents: [this.id, theirProposal.agent],
            agreedValue: (myProposal.value + theirProposal.value) / 2,
            timestamp: Date.now()
        };
    }
}

// 弘益人間: Fair negotiation benefiting all parties

Multi-Issue Negotiation

Real-world negotiations often involve multiple interconnected issues. Agents can make trade-offs across issues to reach better agreements.

Voting and Consensus

When agents must make collective decisions, voting mechanisms aggregate individual preferences into group decisions.

Voting Methods

Method Description Pros/Cons
Plurality Option with most votes wins Simple but can elect minority preference
Majority Option with >50% votes wins Ensures broad support, may require runoff
Unanimous All agents must agree Strong consensus, but slow and blocking
Weighted Votes have different weights Reflects expertise/stake, less democratic
Ranked Choice Agents rank preferences Captures nuanced preferences, complex
Borda Count Points based on rankings Rewards consensus choices
class VotingSystem {
    constructor(method = 'majority') {
        this.method = method;
        this.votes = [];
    }

    collectVotes(agents, proposal) {
        this.votes = agents.map(agent => ({
            agentId: agent.id,
            vote: agent.vote(proposal),
            weight: agent.getVotingWeight()
        }));
    }

    // Majority voting
    majorityVote() {
        const favor = this.votes.filter(v => v.vote === true).length;
        const total = this.votes.length;
        return favor / total > 0.5;
    }

    // Weighted voting
    weightedVote() {
        const favorWeight = this.votes
            .filter(v => v.vote === true)
            .reduce((sum, v) => sum + v.weight, 0);

        const totalWeight = this.votes
            .reduce((sum, v) => sum + v.weight, 0);

        return favorWeight / totalWeight > 0.5;
    }

    // Ranked choice voting
    rankedChoiceVote(candidates) {
        let remaining = [...candidates];
        const ballots = this.votes.map(v => v.rankings);

        while (remaining.length > 1) {
            const counts = this.countFirstChoices(ballots, remaining);
            const total = ballots.length;

            // Check if anyone has majority
            for (const [candidate, count] of counts.entries()) {
                if (count / total > 0.5) {
                    return candidate;
                }
            }

            // Eliminate candidate with fewest first-choice votes
            const minCandidate = this.findMinCandidate(counts);
            remaining = remaining.filter(c => c !== minCandidate);
        }

        return remaining[0];
    }

    // Borda count
    bordaCount(candidates) {
        const points = new Map();
        candidates.forEach(c => points.set(c, 0));

        for (const vote of this.votes) {
            const rankings = vote.rankings;
            for (let i = 0; i < rankings.length; i++) {
                const candidate = rankings[i];
                const pts = candidates.length - i - 1;
                points.set(candidate, points.get(candidate) + pts);
            }
        }

        return this.findMaxCandidate(points);
    }
}

// 弘益人間: Democratic decision-making for collective benefit

Consensus Algorithms

Distributed consensus algorithms ensure agents agree on system state despite failures and network issues.

Raft Consensus

Raft is a consensus algorithm designed for understandability. It ensures that a cluster of agents agrees on a sequence of values (log entries).

class RaftAgent {
    constructor(id, peers) {
        this.id = id;
        this.peers = peers;
        this.state = 'follower'; // follower, candidate, or leader
        this.currentTerm = 0;
        this.votedFor = null;
        this.log = [];
        this.commitIndex = 0;
    }

    // Start election when election timeout expires
    startElection() {
        this.state = 'candidate';
        this.currentTerm++;
        this.votedFor = this.id;

        let votesReceived = 1; // Vote for self

        // Request votes from all peers
        for (const peer of this.peers) {
            const response = peer.requestVote({
                term: this.currentTerm,
                candidateId: this.id,
                lastLogIndex: this.log.length - 1,
                lastLogTerm: this.log[this.log.length - 1]?.term || 0
            });

            if (response.voteGranted) votesReceived++;
        }

        // Become leader if majority votes received
        if (votesReceived > (this.peers.length + 1) / 2) {
            this.becomeLeader();
        } else {
            this.state = 'follower';
        }
    }

    becomeLeader() {
        this.state = 'leader';
        console.log(`Agent ${this.id} became leader for term ${this.currentTerm}`);

        // Send heartbeats to maintain leadership
        this.sendHeartbeats();
    }

    // Leader sends append entries (heartbeat/replication)
    sendHeartbeats() {
        for (const peer of this.peers) {
            peer.appendEntries({
                term: this.currentTerm,
                leaderId: this.id,
                entries: [], // Empty for heartbeat
                leaderCommit: this.commitIndex
            });
        }
    }

    // Follower receives append entries
    handleAppendEntries(request) {
        if (request.term < this.currentTerm) {
            return { success: false, term: this.currentTerm };
        }

        this.currentTerm = request.term;
        this.state = 'follower';

        // Append new entries to log
        this.log.push(...request.entries);

        // Update commit index
        if (request.leaderCommit > this.commitIndex) {
            this.commitIndex = Math.min(
                request.leaderCommit,
                this.log.length - 1
            );
        }

        return { success: true, term: this.currentTerm };
    }
}

// 弘益人間: Consensus ensuring system integrity for all

Practical Byzantine Fault Tolerance (PBFT)

PBFT provides consensus even when some agents behave maliciously, as long as less than 1/3 are faulty.

Market-Based Coordination

Market mechanisms use economic principles to coordinate agent behavior through supply, demand, and pricing.

Auction Mechanisms

class Auctioneer {
    constructor() {
        this.auctions = new Map();
    }

    // English Auction (ascending price)
    async englishAuction(item, startPrice, minIncrement) {
        let currentBid = startPrice;
        let currentWinner = null;
        let bidders = this.getBidders(item);
        let noBidRounds = 0;

        while (noBidRounds < 3) {
            const bids = [];

            for (const bidder of bidders) {
                const bid = await bidder.considerBid(item, currentBid);
                if (bid > currentBid + minIncrement) {
                    bids.push({ bidder: bidder.id, amount: bid });
                }
            }

            if (bids.length === 0) {
                noBidRounds++;
            } else {
                noBidRounds = 0;
                const highestBid = Math.max(...bids.map(b => b.amount));
                currentBid = highestBid;
                currentWinner = bids.find(b => b.amount === highestBid).bidder;
            }
        }

        return { winner: currentWinner, price: currentBid };
    }

    // Sealed-bid (First-price)
    async sealedBidAuction(item) {
        const bidders = this.getBidders(item);
        const bids = await Promise.all(
            bidders.map(b => b.submitSealedBid(item))
        );

        const highestBid = Math.max(...bids.map(b => b.amount));
        const winner = bids.find(b => b.amount === highestBid);

        return { winner: winner.bidder, price: winner.amount };
    }

    // Vickrey Auction (Second-price sealed-bid)
    async vickreyAuction(item) {
        const bidders = this.getBidders(item);
        const bids = await Promise.all(
            bidders.map(b => b.submitSealedBid(item))
        );

        bids.sort((a, b) => b.amount - a.amount);

        return {
            winner: bids[0].bidder,
            price: bids[1].amount // Pay second-highest price
        };
    }

    // Dutch Auction (descending price)
    async dutchAuction(item, startPrice, decrementRate) {
        let currentPrice = startPrice;
        const bidders = this.getBidders(item);

        while (currentPrice > 0) {
            for (const bidder of bidders) {
                if (await bidder.acceptsPrice(item, currentPrice)) {
                    return { winner: bidder.id, price: currentPrice };
                }
            }

            currentPrice -= decrementRate;
            await this.sleep(100); // Time between decrements
        }

        return null; // No winner
    }
}

// 弘益人間: Market mechanisms for efficient resource allocation

Plan Merging and Coordination

When agents create individual plans, these plans must be coordinated to avoid conflicts and exploit synergies.

class PlanCoordinator {
    constructor() {
        this.agents = [];
        this.globalPlan = [];
    }

    async coordinatePlans(agentPlans) {
        // Detect conflicts between plans
        const conflicts = this.detectConflicts(agentPlans);

        if (conflicts.length === 0) {
            return this.mergePlans(agentPlans);
        }

        // Resolve conflicts through negotiation
        for (const conflict of conflicts) {
            await this.resolveConflict(conflict, agentPlans);
        }

        return this.mergePlans(agentPlans);
    }

    detectConflicts(plans) {
        const conflicts = [];

        for (let i = 0; i < plans.length; i++) {
            for (let j = i + 1; j < plans.length; j++) {
                const conflict = this.checkPlanConflict(plans[i], plans[j]);
                if (conflict) {
                    conflicts.push({
                        agents: [plans[i].agentId, plans[j].agentId],
                        type: conflict.type,
                        details: conflict.details
                    });
                }
            }
        }

        return conflicts;
    }

    checkPlanConflict(plan1, plan2) {
        // Check for resource conflicts
        const resourceConflict = this.checkResourceConflict(plan1, plan2);
        if (resourceConflict) return resourceConflict;

        // Check for temporal conflicts
        const temporalConflict = this.checkTemporalConflict(plan1, plan2);
        if (temporalConflict) return temporalConflict;

        // Check for goal conflicts
        const goalConflict = this.checkGoalConflict(plan1, plan2);
        if (goalConflict) return goalConflict;

        return null;
    }

    async resolveConflict(conflict, plans) {
        const [agent1, agent2] = conflict.agents;
        const plan1 = plans.find(p => p.agentId === agent1);
        const plan2 = plans.find(p => p.agentId === agent2);

        if (conflict.type === 'resource') {
            // Time-share or prioritize
            await this.negotiateResourceSharing(plan1, plan2, conflict);
        } else if (conflict.type === 'temporal') {
            // Reschedule one plan
            await this.reschedulePlan(plan1, plan2, conflict);
        } else if (conflict.type === 'goal') {
            // Find compromise
            await this.negotiateGoals(plan1, plan2, conflict);
        }
    }

    mergePlans(plans) {
        // Create global schedule from individual plans
        const merged = [];

        for (const plan of plans) {
            for (const action of plan.actions) {
                merged.push({
                    agent: plan.agentId,
                    action: action,
                    startTime: action.startTime,
                    endTime: action.endTime,
                    resources: action.resources
                });
            }
        }

        // Sort by start time
        merged.sort((a, b) => a.startTime - b.startTime);

        return merged;
    }
}

// 弘益人間: Coordinated planning for collective success

Swarm Coordination

Swarm coordination enables large numbers of simple agents to achieve complex collective behaviors through local interactions.

class SwarmAgent {
    constructor(id, position) {
        this.id = id;
        this.position = position;
        this.velocity = { x: 0, y: 0 };
        this.neighbors = [];
    }

    // Reynolds' Boids algorithm for flocking
    updateVelocity(allAgents) {
        const neighbors = this.findNeighbors(allAgents, 50);

        const separation = this.separate(neighbors);
        const alignment = this.align(neighbors);
        const cohesion = this.cohere(neighbors);

        // Combine behaviors with weights
        this.velocity.x += separation.x * 1.5 + alignment.x * 1.0 + cohesion.x * 1.0;
        this.velocity.y += separation.y * 1.5 + alignment.y * 1.0 + cohesion.y * 1.0;

        // Limit speed
        const speed = Math.sqrt(this.velocity.x ** 2 + this.velocity.y ** 2);
        const maxSpeed = 5;
        if (speed > maxSpeed) {
            this.velocity.x = (this.velocity.x / speed) * maxSpeed;
            this.velocity.y = (this.velocity.y / speed) * maxSpeed;
        }
    }

    // Avoid crowding neighbors
    separate(neighbors) {
        const steer = { x: 0, y: 0 };
        for (const neighbor of neighbors) {
            const dx = this.position.x - neighbor.position.x;
            const dy = this.position.y - neighbor.position.y;
            const dist = Math.sqrt(dx * dx + dy * dy);

            if (dist > 0 && dist < 25) {
                steer.x += dx / dist;
                steer.y += dy / dist;
            }
        }
        return steer;
    }

    // Align with neighbors' average velocity
    align(neighbors) {
        if (neighbors.length === 0) return { x: 0, y: 0 };

        const avgVel = neighbors.reduce(
            (sum, n) => ({
                x: sum.x + n.velocity.x,
                y: sum.y + n.velocity.y
            }),
            { x: 0, y: 0 }
        );

        return {
            x: avgVel.x / neighbors.length - this.velocity.x,
            y: avgVel.y / neighbors.length - this.velocity.y
        };
    }

    // Move toward average position of neighbors
    cohere(neighbors) {
        if (neighbors.length === 0) return { x: 0, y: 0 };

        const avgPos = neighbors.reduce(
            (sum, n) => ({
                x: sum.x + n.position.x,
                y: sum.y + n.position.y
            }),
            { x: 0, y: 0 }
        );

        return {
            x: avgPos.x / neighbors.length - this.position.x,
            y: avgPos.y / neighbors.length - this.position.y
        };
    }
}

// 弘益人間: Emergent coordination through simple local rules

Chapter Summary

Review Questions

  1. What is the fundamental difference between centralized and decentralized coordination?
  2. Describe the monotonic concession protocol for agent negotiation.
  3. Compare majority voting, weighted voting, and Borda count methods.
  4. How does the Raft consensus algorithm work? What are its key components?
  5. Explain the difference between English, Dutch, and Vickrey auctions.
  6. What types of conflicts can arise when merging agent plans?
  7. Describe the three basic behaviors in Reynolds' Boids flocking algorithm.
  8. When is centralized coordination preferable to decentralized approaches?
  9. What is the advantage of Vickrey (second-price) auctions over first-price auctions?
  10. How do coordination mechanisms support the 弘익人間 principle in multi-agent systems?