Project: s41467-025-60800-7 | Function: Tip_Dynamics (cpp)

system: You are an expert C++ programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow C++ best practices and maintain consistent code style.
Return **only** the complete C++ function code.

user: Complete this C++ function:

**DESCRIPTION:** Implements three-state stochastic dynamics (growing, paused, shrinking) for dendritic tip growth with state transitions and velocity assignments based on experimental parameters

**KEY TERMS:** {
  "state[i]": "tip state (1=growing, 0=paused, -1=shrinking)",
  "Kgs/Kgp": "growing to shrinking/paused transition rates",
  "Ksg/Ksp": "shrinking to growing/paused transition rates",
  "Kpg/Kps": "paused to growing/shrinking transition rates",
  "v[i]": "tip velocity",
  "Vg_mean/Vg_sig": "growing velocity log-normal parameters",
  "Vs_mean/Vs_sig": "shrinking velocity log-normal parameters",
  "Vp_sig": "paused velocity standard deviation"
}

**CONTEXT CODE:** #include <stdio.h>
#include <stdlib.h>

void add_tiplength(int i, double l_add){
  // Uses external storage for tip lengths; if not present in the compilation unit,
  // link-time will fail (these symbols are expected to exist elsewhere in the program).
  extern int N_tips;
  extern double *tip_length;

  if(i < 0 || i >= N_tips) return;
  if(!tip_length) return;

  tip_length[i] += l_add;
  // Prevent negative physical lengths
  if(tip_length[i] < 0.0) tip_length[i] = 0.0;
}

void Tip_Dynamics(){
  // External state used by the simulation (must be defined elsewhere).
  extern int N_tips;
  extern int *state;        // 1 = growing, 0 = paused, -1 = shrinking
  extern double *v;         // tip velocities
  extern double dt;         // time step
  extern double *tip_length;

  // Transition rates (per unit time)
  extern double Kgs, Kgp;   // growing -> shrinking / paused
  extern double Ksg, Ksp;   // shrinking -> growing / paused
  extern double Kpg, Kps;   // paused   -> growing / shrinking

  // Velocity distribution parameters
  // Vg_mean, Vg_sig are parameters for log-normal (log-space mean & std)
  // Vs_mean, Vs_sig similar for shrinking magnitudes
  // Vp_sig is std dev for paused (zero-mean Gaussian noise)
  extern double Vg_mean, Vg_sig;
  extern double Vs_mean, Vs_sig;
  extern double Vp_sig;

  if(N_tips <= 0) return;
  if(!state || !v) return;
  // simple uniform RNG and Box-Muller for normals
  auto uniform01 = []() -> double {
    // (rand()+1)/(RAND_MAX+2) to avoid exact 0 or 1
    return (static_cast<double>(rand()) + 1.0) / (static_cast<double>(RAND_MAX) + 2.0);
  };

  // Box-Muller with state captured in static variables via lambda closure
  struct NormalRNG {
    bool has_spare = false;
    double spare = 0.0;
    double operator()() {
      if(has_spare){
        has_spare = false;
        return spare;
      }
      double u1, u2;
      do {
        u1 = (static_cast<double>(rand()) + 1.0) / (static_cast<double>(RAND_MAX) + 2.0);
        u2 = (static_cast<double>(rand()) + 1.0) / (static_cast<double>(RAND_MAX) + 2.0);
      } while(u1 <= 1e-15);
      double r = sqrt(-2.0 * log(u1));
      double theta = 2.0 * 3.14159265358979323846 * u2;
      spare = r * cos(theta);
      has_spare = true;
      return r * sin(theta);
    }
  } normal_rng;

  // Clip dt to non-negative
  double local_dt = dt;
  if(local_dt < 0.0) local_dt = 0.0;

  for(int i = 0; i < N_tips; ++i){
    int s = state[i];
    // Determine transition probabilities over dt
    double p1 = 0.0, p2 = 0.0; // two possible outgoing transitions (order dependent on state)
    if(s == 1){ // growing: can go to shrinking (Kgs) or paused (Kgp)
      p1 = Kgs * local_dt;
      p2 = Kgp * local_dt;
      if(p1 < 0.0) p1 = 0.0; if(p2 < 0.0) p2 = 0.0;
      if(p1 > 1.0) p1 = 1.0; if(p2 > 1.0) p2 = 1.0;
      double r = uniform01();
      if(r < p1){
        s = -1;
      } else if(r < p1 + p2){
        s = 0;
      } else {
        s = 1;
      }
    } else if(s == -1){ // shrinking: can go to growing (Ksg) or paused (Ksp)
      p1 = Ksg * local_dt;
      p2 = Ksp * local_dt;
      if(p1 < 0.0) p1 = 0.0; if(p2 < 0.0) p2 = 0.0;
      if(p1 > 1.0) p1 = 1.0; if(p2 > 1.0) p2 = 1.0;
      double r = uniform01();
      if(r < p1){
        s = 1;
      } else if(r < p1 + p2){
        s = 0;
      } else {
        s = -1;
      }
    } else { // paused (0): can go to growing (Kpg) or shrinking (Kps)
      p1 = Kpg * local_dt;
      p2 = Kps * local_dt;
      if(p1 < 0.0) p1 = 0.0; if(p2 < 0.0) p2 = 0.0;
      if(p1 > 1.0) p1 = 1.0; if(p2 > 1.0) p2 = 1.0;
      double r = uniform01();
      if(r < p1){
        s = 1;
      } else if(r < p1 + p2){
        s = -1;
      } else {
        s = 0;
      }
    }



Complete the function implementation replacing "throw std::runtime_error("Not implemented");".