Revision 57666cd27ebaad61349990adfa9aac7b18216707 authored by dwarner-git on 24 July 2022, 13:11:48 UTC, committed by GitHub on 24 July 2022, 13:11:48 UTC
1 parent 850c5bd
Raw File
shapeformation_fault_tolerant.h
/* Copyright (C) 2021 Daniel Warner.
 * The full GNU GPLv3 can be found in the LICENSE file, and the full copyright
 * notice can be found at the top of main/main.cpp. */

// Defines the particle system and composing particles for the General
// Formation Algorithm as alluded to in 'An Algorithmic Framework for Shape
// Formation Problems in Self-Organizing Particle Systems'
// [arxiv.org/abs/1504.00744].
//
// Extension of the shape formation algorithms in order to make them tolerant to the failure of particles.
//
// mode == "h" --> hexagon formation
// mode == "s" --> square formation
// mode == "t1" --> vertex triangle formation
// mode == "t2" --> center triangle formation
// mode == "l" --> line formation

#ifndef AMOEBOTSIM_ALG_SHAPEFORMATION_FAULT_TOLERANT_H_
#define AMOEBOTSIM_ALG_SHAPEFORMATION_FAULT_TOLERANT_H_

#include <set>

#include <QString>

#include <bits/stl_list.h>

#include "core/amoebotparticle.h"
#include "core/amoebotsystem.h"

class ShapeFormationFaultTolerantParticle : public AmoebotParticle {
public:
    enum class State {
        Seed,
        Idle,
        Follower,
        Root,
        Retired,
        Crashed,  // When a particle crashes/is scheduled to crash, its state changes to the Crashed state.
        Error
    };

    enum class PathToRootState {
        Valid,
        Invalid,
        Invalidate
    };

    enum class SafeState : int {
        Undetermined = 0,
        Unsafe = 1,
        Safe = 2
    };

    // Constructs a new particle with a node position for its head, a global
    // compass direction from its head to its tail (-1 if contracted), an offset
    // for its local compass, a system which it belongs to, an initial state, and
    // a string to determine what shape to form.
    ShapeFormationFaultTolerantParticle(const Node head, const int globalTailDir,
                                        const int orientation, AmoebotSystem& system,
                                        State state, const QString mode);

    // Causes the particle to crash. (i.e. change the state of the particle to the state Crashed)
    virtual void crash();

    // Executes one particle activation.
    virtual void activate();

    // Determine whether the particle is in an error state (here: state Crashed or state Error).
    virtual bool isErrorParticle() const;

    // Determine whether the particle has a neighbour in an error state (using isErrorParticle)
    virtual bool hasErrorNbr() const;

    // Functions for altering a particle's cosmetic appearance.
    // particleColor returns the color to be used for the particle.
    // particleCenterColor returns the color to be used as a small marking
    // in the center of the particle (here: visualize a "noted" invalidate
    // for a particle in state Error which will be propagated as soon as the particle becomes a follower).
    // headMarkColor (respectively, tailMarkColor) returns the color to be used for the ring
    // drawn around the head (respectively, tail) node. Tail color is not shown
    // when the particle is contracted. headMarkDir returns the label of the port
    // on which the black head marker is drawn.
    virtual int particleColor() const;
    virtual int particleCenterColor() const;
    virtual int headMarkColor() const;
    virtual int headMarkDir() const;
    virtual int tailMarkColor() const;

    // Returns the string to be displayed when this particle is inspected; used
    // to snapshot the current values of this particle's memory at runtime.
    virtual QString inspectionText() const;

    // Returns the _borderColors array associated with the
    // particle to draw the boundaries of the hexagon layers.
    virtual std::array<int, 18> borderColors() const;
    // Updates the _borderColors array.
    void updateBorderColors();

    // Returns the safeFlags array associated with the
    // particle to draw the safeFlags of the particle.
    virtual std::array<std::array<std::array<VisFlagStates, 2>, 2>, 6> getSafeFlags() const;

    // Gets a reference to the neighboring particle incident to the specified port
    // label. Crashes if no such particle exists at this label; consider using
    // hasNbrAtLabel() first if unsure.
    ShapeFormationFaultTolerantParticle& nbrAtLabel(int label) const;

    // Returns the label of the first port incident to a neighboring particle in
    // any of the specified states, starting at the (optionally) specified label
    // and continuing clockwise.
    int labelOfFirstNbrInState(std::initializer_list<State> states,
                               int startLabel = 0, bool ignoreErrorParticles = true) const;

    // Checks whether this particle has a neighbor in any of the given states.
    bool hasNbrInState(std::initializer_list<State> states) const;

    // Checks whether this particle's state is one of the given states.
    bool isInState(std::initializer_list<State> states) const;

    // Returns the label of the port incident to a neighbor which is finished and
    // pointing at this particle's position as the next one to be filled; returns
    // -1 if such a neighbor does not exist.
    int constructionReceiveDir() const;

    // Checks whether this particle is occupying the next position to be filled and
    // therefore may become Retired.
    bool canRetire() const;

    // A particle is finished if it is in state Retired or Seed.
    bool isFinished() const;

    // Function updateConstructionDir tries to set this particle's constructionDir
    // to point at the next position to be filled as it is finishing.
    // Returns true on success.
    bool updateConstructionDir();

    // Function computeMoveLabel tries to compute this particle's label
    // to traverse the current surface of the forming shape counter-clockwise when it is a root.
    // Returns -1 if label could not be computed successfully.
    int computeMoveLabel() const;
    // Function updateMoveDir tries to update this particle's moveDir
    // using the function computeMoveLabel. Returns true on success.
    bool updateMoveDir();

    // Checks whether this (expanded) particle has an immediate child
    // in the spanning tree following its tail.
    bool hasTailFollower() const;

    // Checks whether this (expanded) particle has a tail follower or
    // an idle or error neighbour which is adjacent to its tail.
    bool hasBlockingTailNbr() const;

    // Fault-tolerant method (as part of the fault-tolerant shape formation protocol)
    // that may perform movements:
    void performMovement();

    // Fault-tolerant methods (as part of the fault-tolerant shape formation protocol)
    // that may change the state of the particle but do not perform any movements:
    bool tryToBecomeRetired_Hexagon();
    bool tryToBecomeRoot_Hexagon();
    bool tryToBecomeFollower();
    bool tryFollowerRecoveryByPropagation();

    // Update the flags of the particle.
    void updateFlags();

    // Propagate Invalidate
    void propagateInvalidate();

    // Propagate Valid
    void propagateValid();

protected:
    // General state of this (error or non-error) particle.
    State state;

    // mode stores a string that specifies which shape (hexagon, triangle, etc.) is formed.
    QString mode;
    // turnSignal is used for the square and vertex triangle shape formation algorithms.
    int turnSignal;

    // Shape formation specific variables of this (non-error) particle:
    int constructionDir;
    int moveDir;
    int followDir;

    // State of this (error or non-error) particle as node(s) on a path upwards to a root particle.
    //
    // All particles are initially Valid. Error particles are initialized Invalid.
    // Seed, Retired, Root and Idle particles are always Valid.
    // Follower particles can be in state Valid, Invalid or Invalidate.
    // Error particles can be in state Invalid or Invalidate.
    //
    // The pathToRoot state is only propagated by non-error particles:
    // - Follower in state Invalidate: Becomes Invalid and propagates upwards:
    //   If it has a follower or Error particle as parent, the parent's pathToRoot state becomes Invalidate.
    // - Follower in state Invalid: Remains invalid and no propagation.
    // - Follower in state Valid or Root: Remains Valid and propagates downwards:
    //   If it has an invalid follower child (an invalid neighbour follower pointing at it), the child becomes valid.
    //   In particular, if the child is in state Invalidate, the child does not change its pathToRoot state (Invalidate "beats" Valid).
    //
    // Basic idea: By propagating "Invalidate" upwards to the root, all particles on the path upwards become "Invalid" (=> Safety).
    // After "Invalidate" is finally "consumed" by the root, the status "Valid" is propagated
    // from the root downwards to the leaves (=> Liveness), whereby the validation process might again be interrupted by an ascending "Invalidate".
    PathToRootState pathToRootState;

    // safeFlags of this (error particle):
    // safeFlags are used to determine how many rounds the current value of safeState is based on.
    std::array<std::array<std::array<SafeState, 2>, 2>, 6> safeFlags;

    // safeState of this (error) particle:
    // A particle p in state Error may become a follower if all of the following conditions are met:
    // 1) p.safeState == Safe
    // 2) p has a follower neighbour in pathToRootState Valid which was previously invalidated by p, or p has a root neighbour.
    SafeState safeState;

    // hasInvalidated array of this (error) particle:
    // A particle that is in safeState Safe sends "invalidate" messages to followers
    // who could be potential parents. The hasInvalidated array stores which neighbours
    // have been contacted so far. This is visualized by small circles
    // in dark (instead of light) green in the corresponding directions.
    std::array<bool, 10> hasInvalidated;

    // _borderColorsSet and _borderColors are used to draw the boundaries of the hexagon layers.
    bool _borderColorsSet;
    std::array<int, 18> _borderColors;

private:
    friend class ShapeFormationFaultTolerantSystem;
};

class ShapeFormationFaultTolerantSystem : public AmoebotSystem  {
public:
    // Constructs a system of ShapeFormationFaultTolerantParticles with an optionally specified
    // size (#particles), hole probability, and shape to form. holeProb in [0,1]
    // controls how "spread out" the system is; closer to 0 is more compressed,
    // closer to 1 is more expanded. The current shapes accepted are...
    //   "h"  --> hexagon
    //   "s"  --> square
    //   "t1" --> vertex triangle
    //   "t2" --> center triangle
    //   "l"  --> line
    ShapeFormationFaultTolerantSystem(int numParticles = 200, double holeProb = 0.2,
                                      QString mode = "h");

    // Checks whether or not the system's run of the ShapeFormation formation
    // algorithm has terminated (all particles finished, i.e. apart from Seed all particles in state Retired).
    bool hasTerminated() const override;

    // nuke causes all particles except the Seed particle to crash.
    void nuke() override;

    // Returns a set of strings containing the current accepted modes of
    // Shapeformation.
    static std::set<QString> getAcceptedModes();
};

class NotImplementedException : public std::logic_error
{
private:

    std::string _text;

public:

    NotImplementedException()
        :
          NotImplementedException("Not implememented", __FUNCTION__)
    {
    }

    NotImplementedException(const char* message)
        :
          NotImplementedException(message, __FUNCTION__)
    {
    }

    NotImplementedException(const char* message, const char* function)
        :
          std::logic_error("Not implemented")
    {
        _text = "Not implemented : ";
        _text += message;
        _text += " : ";
        _text += function;
    };

    virtual const char *what() const throw()
    {
        return _text.c_str();
    }
};

#endif  // AMOEBOTSIM_ALG_SHAPEFORMATION_FAULT_TOLERANT_H_
back to top