DND Hybrid Model Simulation
5 minutes

Hybrid D-ND Model with modular transformations, adaptive probabilities, and visualization.
The current implementation includes a modularized Python code for simulating the Hybrid Dual-Non-Dual (D-ND) model.

"The current implementation includes a modularized Python code for simulating the Hybrid Dual-Non-Dual (D-ND) model. It incorporates the following key features:\n\n1. **System Parameters**: All simulation parameters (iterations, transition thresholds, lambda_linear, etc.) are stored in the `SystemParameters` class for better manageability.\n\n2. 

**Linear and Fractal Phase Functions**:\n - Implemented separate transformations for linear and fractal phases.\n - Transformations include homothetic contraction, reflection, and probabilistic transformations.\n\n3. 

**Adaptive Probabilities**:\n - Probabilities (α, β, γ) are updated dynamically based on dispersion and average distance from Proto-Assioma.\n\n4. 

**Visualization**:\n - Real-time interactive visualization using `ipywidgets` to display the evolution of points in the complex plane.\n - Integrated sliders for adjusting iterations, lambda, and threshold interactively.\n\n5. 

**Stabilization Logic**:\n - Uses the Hausdorff distance to determine the transition from linear to fractal phases.\n\n6. 

**Logging**:\n - Integrated logging for debugging and tracking updates in probabilities, transformations, and transitions.\n\nThe system is set up for future improvements, such as:\n- Adding parallelization to speed up processing.\n- Reintroducing fractal dimension calculations.\n- Enabling machine learning integration to predict stabilization behavior.\n\nThe results indicate successful transitions and provide insights into the geometric patterns generated by the model."

Image



import random
import matplotlib.pyplot as plt
import numpy as np
from scipy.spatial.distance import directed_hausdorff
import ipywidgets as widgets
from IPython.display import display
import logging
from multiprocessing import Pool
from sklearn.linear_model import LinearRegression
import time

# Initialize logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# ==============================================================
# SYSTEM PARAMETERS CLASS
# ==============================================================
class SystemParameters:
   def __init__(self, iterations=10000, transition_threshold=0.005, lambda_linear=0.1,
                P=complex(0.5, 0.5), alpha=0.4, beta=0.4, gamma=0.2):
       self.iterations = iterations
       self.transition_threshold = transition_threshold
       self.lambda_linear = lambda_linear
       self.P = P
       self.alpha = alpha
       self.beta = beta
       self.gamma = gamma

# ==============================================================
# LINEAR PHASE FUNCTIONS
# ==============================================================
def f1_linear(A, B):
   """
   Combines sets A and B.
   """
   return A.union(B)

def f2_linear(R_t, P, params):
   """
   Moves each point z in R_t towards P by a fraction lambda_linear.
   """
   return {z + params.lambda_linear * (P - z) for z in R_t}

def f3_linear(R_t, P):
   """
   Reflects each point z with respect to P.
   """
   return {P - z for z in R_t}

# ==============================================================
# FRACTAL PHASE FUNCTIONS
# ==============================================================
def T_A(z):
   """
   Transformation A: contraction towards (0 + i).
   """
   return z / 2 + 1j

def T_B(z):
   """
   Transformation B: contraction towards (1 + 0j).
   """
   return (z + 1) / 2

def f1_fractal(points):
   """
   Applies T_A or T_B with 50/50 probability.
   """
   new_set = set()
   for z in points:
       if random.random() < 0.5:
           new_set.add(T_A(z))
       else:
           new_set.add(T_B(z))
   return new_set

def f2_fractal(points, P, params):
   """
   Homothetic contraction towards P with factor lambda_linear.
   """
   return {z * (1 - params.lambda_linear) + params.lambda_linear * P for z in points}

def f3_fractal(points, P):
   """
   Light translation of points towards P (fixed alpha_lin coefficient of 0.1).
   """
   alpha_lin = 0.1
   return {P + alpha_lin * (z - P) for z in points}

# ==============================================================
# TRANSFORMATION SELECTION FUNCTIONS
# ==============================================================
def pick_linear_transform(R_t, P, params):
   """
   Randomly selects a linear transformation with probabilities α, β, and γ.
   """
   x = random.random()
   if x < params.alpha:
       B = {complex(1, 0), complex(0, 2)}  # Fixed set for f1_linear
       return f1_linear(R_t, B)
   elif x < params.alpha + params.beta:
       return f2_linear(R_t, P, params)
   else:
       return f3_linear(R_t, P)

def pick_fractal_transform(R_t, P, params):
   """
   Randomly selects a fractal transformation with probabilities α, β, and γ.
   """
   x = random.random()
   if x < params.alpha:
       return f1_fractal(R_t)
   elif x < params.alpha + params.beta:
       return f2_fractal(R_t, P, params)
   else:
       return f3_fractal(R_t, P)

# ==============================================================
# ADAPTIVE PROBABILITIES
# ==============================================================
def update_probabilities(R, P):
   """
   Updates the probabilities α, β, and γ based on the set dispersion.
   """
   try:
       if not R:
           return 0.4, 0.4, 0.2  # Return default if R is empty

       points_arr = np.array([(z.real, z.imag) for z in R])
       if points_arr.size == 0:
           return 0.4, 0.4, 0.2  # Return default if no points in the set

       center = np.mean(points_arr, axis=0)
       dispersion = np.std(points_arr - center)
       avg_distance_p = np.mean(np.abs(points_arr - np.array([P.real, P.imag])))  # Calculate average distance from Proto-Assioma

       # Example logic: Adjust probabilities based on dispersion and distance from P
       alpha_new = 0.4 - 0.05 * dispersion + 0.05 * avg_distance_p
       beta_new = 0.4 + 0.05 * dispersion - 0.02 * avg_distance_p
       gamma_new = 0.2 - 0.03 * dispersion - 0.03 * avg_distance_p

       # Ensure probabilities are within [0, 1]
       alpha_new = max(0, min(1, alpha_new))
       beta_new = max(0, min(1, beta_new))
       gamma_new = max(0, min(1, gamma_new))

       # Normalize to ensure alpha + beta + gamma = 1
       total = alpha_new + beta_new + gamma_new
       if total == 0:
           return 0.4, 0.4, 0.2  # Return default if normalization fails

       alpha_new /= total
       beta_new /= total
       gamma_new /= total

       return alpha_new, beta_new, gamma_new

   except Exception as e:
       logging.error(f"Error in update_probabilities: {e}")
       return 0.4, 0.4, 0.2  # Return default if error occurs

# ==============================================================
# ERROR HANDLING AND ADDITIONAL UTILITIES
# ==============================================================
def is_stable_hausdorff(R_t, R_t1, threshold):
   """
   Stabilization: if max difference between corresponding points < threshold.
   """
   try:
       if not R_t1 or not R_t:
           return False

       R_t_arr = np.array([(z.real, z.imag) for z in R_t])
       R_t1_arr = np.array([(z.real, z.imag) for z in R_t1])

       if R_t_arr.size == 0 or R_t1_arr.size == 0:
           return False

       dist1 = directed_hausdorff(R_t_arr, R_t1_arr)[0]
       dist2 = directed_hausdorff(R_t1_arr, R_t_arr)[0]
       hausdorff_distance = max(dist1, dist2)
       return hausdorff_distance < threshold
   except Exception as e:
       logging.error(f"Error in is_stable_hausdorff: {e}")
       return False

# ==============================================================
# INTERACTIVE VISUALIZATION WITH IPYWIDGETS
# ==============================================================
def create_interactive_widgets(params):
   """Creates interactive widgets for parameter adjustment."""
   iterations_slider = widgets.IntSlider(value=params.iterations, min=100, max=20000, step=100,
                                         description='Iterations:')
   lambda_slider = widgets.FloatSlider(value=params.lambda_linear, min=0.01, max=0.5, step=0.01,
                                        description='Lambda:')
   threshold_slider = widgets.FloatSlider(value=params.transition_threshold, min=0.0001, max=0.01,
                                          step=0.0001, description="Threshold")
   output_widget = widgets.Output()
   display(iterations_slider, lambda_slider, threshold_slider, output_widget)
   return iterations_slider, lambda_slider, threshold_slider, output_widget

# ==============================================================
# MAIN SYSTEM FUNCTIONS
# ==============================================================
def initialize_system(params):
   """Initializes the system with starting values."""
   R = {complex(0, 0)}
   all_points = set(R)
   linear_phase = True
   ml_data = []
   start_time = time.time()
   transition_time = None
   return R, all_points, linear_phase, ml_data, start_time, transition_time

def run_linear_phase(R, all_points, params):
   """Runs the linear phase transformations."""
   R_next = pick_linear_transform(R, params.P, params)
   all_points.update(R_next)

   params.alpha, params.beta, params.gamma = update_probabilities(R_next, params.P)
   logging.info(f"Updated probabilities: alpha={params.alpha:.2f}, beta={params.beta:.2f}, gamma={params.gamma:.2f}")

   return R_next, all_points

def run_fractal_phase(R, all_points, params):
   """Runs the fractal phase transformations."""
   R_next = pick_fractal_transform(R, params.P, params)
   all_points.update(R_next)
   return R_next, all_points

def check_stabilization(R, R_next, params):
   """Checks for stabilization using the Hausdorff distance."""
   if is_stable_hausdorff(R, R_next, params.transition_threshold):
       logging.info("Stabilization reached.")
       return True
   return False

def visualize_results(all_points):
   """Visualizes the results."""
   x_vals = [z.real for z in all_points]
   y_vals = [z.imag for z in all_points]
   plt.figure(figsize=(8, 8))
   plt.scatter(x_vals, y_vals, s=1, color="blue")
   plt.title("Hybrid D-ND Experiment: Linear and Fractal Phase")
   plt.xlabel("Re(z)")
   plt.ylabel("Im(z)")
   plt.grid(True)
   plt.show()

def run_simulation(params, iterations_slider, lambda_slider, threshold_slider, output_widget):
   """Runs the main simulation loop."""
   R, all_points, linear_phase, ml_data, start_time, transition_time = initialize_system(params)

   with output_widget:
       output_widget.clear_output(wait=True)

       for t in range(1, iterations_slider.value + 1):
           if linear_phase:
               R_next, all_points = run_linear_phase(R, all_points, params)
               if check_stabilization(R, R_next, params):
                   transition_time = time.time() - start_time
                   ml_data.append([params.iterations, params.lambda_linear, params.transition_threshold, transition_time])
                   linear_phase = False
                   R = R_next
               else:
                   R = R_next
           else:
               R_next, all_points = run_fractal_phase(R, all_points, params)
               R = R_next

       visualize_results(all_points)

# ==============================================================
# MAIN EXECUTION LOGIC
# ==============================================================
params = SystemParameters()
iterations_slider, lambda_slider, threshold_slider, output_widget = create_interactive_widgets(params)

# Attach callbacks
def on_slider_change(change):
   run_simulation(params, iterations_slider, lambda_slider, threshold_slider, output_widget)

iterations_slider.observe(on_slider_change, names='value')
lambda_slider.observe(on_slider_change, names='value')
threshold_slider.observe(on_slider_change, names='value')

# Run initial plot
run_simulation(params, iterations_slider, lambda_slider, threshold_slider, output_widget)