import numpy as np

def running_products(factors):
    """Print the running product after each multiplication."""
    product = 1.0
    trail = []
    for f in factors:
        product *= f
        trail.append(product)
        print(f"  x {f:>6} -> running product = {product:.6f}")
    return trail

print("VANISHING chain (typical sub-1 local gradients each step):")
vanishing_factors = [0.3, 0.2, 0.5, 0.8, 0.02, 0.1]
vanish_trail = running_products(vanishing_factors)
print(f"-> after {len(vanishing_factors)} steps, gradient ~ {vanish_trail[-1]:.6f}  (essentially 0)\n")

print("EXPLODING chain (same first four factors, then a >1 factor repeats):")
explode_factors = [0.3, 0.2, 0.5, 0.8, 1.8, 1.8, 1.8, 1.8]
explode_trail = running_products(explode_factors)
print(f"-> after {len(explode_factors)} steps, gradient ~ {explode_trail[-1]:.6f}  and still growing\n")

print("SIGN-FLIP / explosive chain (one large negative factor early):")
signflip_factors = [0.3, 0.2, -6.4]
signflip_trail = running_products(signflip_factors)
print(f"-> after just {len(signflip_factors)} steps: {signflip_trail[-1]:.6f}"
      " -- large magnitude AND flipped sign\n")

# Same root cause every time: repeated multiplication by a shared weight
# matrix (here, scalar factors standing in for it) across many timesteps.
# Vanishing: |factor| < 1 typically.  Exploding: some |factor| > 1.
