Source code for decent_bench.algorithms.p2p._ed

from dataclasses import dataclass

import decent_bench.utils.interoperability as iop
from decent_bench.algorithms.utils import initial_states
from decent_bench.networks import P2PNetwork
from decent_bench.utils._tags import tags
from decent_bench.utils.types import InitialStates

from ._p2p_algorithm import P2PAlgorithm


[docs] @tags("peer-to-peer", "gradient-tracking") @dataclass(eq=False) class ED(P2PAlgorithm): r""" Gradient tracking algorithm characterized by the update step below. .. math:: \mathbf{y}_{i, k+1} = \mathbf{x}_{i, k} - \rho \nabla f_i(\mathbf{x}_{i,k}) .. math:: \mathbf{x}_{i, k+1} = \sum_j \frac{1}{2} (\mathbf{I} + \mathbf{W})_{ij} (\mathbf{x}_{j,k} + \mathbf{y}_{j, k+1} - \mathbf{y}_{j, k}) where :math:`\mathbf{x}_{i, k}` is agent i's local optimization variable at iteration k, :math:`\rho` is the step size (the corresponding argument is ``step_size``), :math:`f_i` is agent i's local cost function, j is a neighbor of i or i itself, and :math:`\mathbf{W}_{ij}` is the metropolis weight between agent i and j. Alias: :class:`ExactDiffusion` """ iterations: int = 100 step_size: float = 0.001 x0: InitialStates = None name: str = "ED" def __post_init__(self) -> None: """ Validate hyperparameters. Raises: ValueError: if hyperparameters are invalid. """ if self.step_size <= 0: raise ValueError("`step_size` must be positive") def initialize(self, network: P2PNetwork) -> None: self.x0 = initial_states(self.x0, network) for i in network.agents(): y0 = self.x0[i] y1 = self.x0[i] - self.step_size * i.cost.gradient(self.x0[i]) i.initialize(x=self.x0[i], aux_vars={"y": y0, "y_new": y1}) self.W = network.weights self.W = 0.5 * (iop.eye_like(self.W) + self.W) def step(self, network: P2PNetwork, _: int) -> None: for i in network.active_agents(): msg = i.x + i.aux_vars["y_new"] - i.aux_vars["y"] i.aux_vars["msg"] = msg network.broadcast(i, msg) for i in network.active_agents(): s = self.W[i, i] * i.aux_vars["msg"] for j, msg in i.messages().items(): s += self.W[i, j] * msg i.x = s i.aux_vars["y"] = i.aux_vars["y_new"] i.aux_vars["y_new"] = i.x - self.step_size * i.cost.gradient(i.x)
ExactDiffusion = ED # alias