---
title: "Multi-Dimensional Walks"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Multi-Dimensional Walks}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.width = 7,
  fig.height = 5
)
```

```{r setup, echo=FALSE, message=FALSE}
library(RandomWalker)
library(dplyr)
library(ggplot2)
```

RandomWalker supports random walks in 1D, 2D, and 3D space. This guide covers everything you need to know about working with multi-dimensional random walks.

## Table of Contents

- [Overview](#overview)
- [Generating Multi-Dimensional Walks](#generating-multi-dimensional-walks)
- [Understanding the Data Structure](#understanding-the-data-structure)
- [Visualizing 2D Walks](#visualizing-2d-walks)
- [Visualizing 3D Walks](#visualizing-3d-walks)
- [Distance and Spatial Analysis](#distance-and-spatial-analysis)
- [Use Cases](#use-cases)
- [Best Practices](#best-practices)

## Overview

### What are Multi-Dimensional Random Walks?

A multi-dimensional random walk extends the concept of a 1D random walk into higher-dimensional spaces:

- **1D**: Movement along a line (left/right, up/down)
- **2D**: Movement on a plane (x and y coordinates)
- **3D**: Movement in space (x, y, and z coordinates)

### When to Use Multi-Dimensional Walks

**2D Walks:**
- Particle diffusion in a plane
- Animal movement patterns
- Robot navigation
- 2D cellular automata
- Currency exchange rates (two currencies vs reference)

**3D Walks:**
- Particle diffusion in space
- Molecular dynamics
- Drone or aircraft movement
- 3D cellular automata
- Financial modeling (multiple asset classes)

## Generating Multi-Dimensional Walks

### Basic Syntax

All random walk generator functions support the `.dimensions` parameter:

```{r basic_syntax}

# 1D walk (default)
walk_1d <- random_normal_walk(.num_walks = 5, .n = 100, .dimensions = 1)

# 2D walk
walk_2d <- random_normal_walk(.num_walks = 5, .n = 100, .dimensions = 2)

# 3D walk
walk_3d <- random_normal_walk(.num_walks = 5, .n = 100, .dimensions = 3)
```

### All Distributions Support Multi-Dimensions

Every continuous distribution generator supports 1D, 2D, and 3D:

```{r distribution_examples, eval=FALSE}
# 2D Brownian motion
brownian_motion(.num_walks = 10, .n = 500, .dimensions = 2)

# 3D geometric Brownian motion
geometric_brownian_motion(
  .num_walks = 10,
  .n = 500,
  .initial_value = 100,
  .dimensions = 3
)

# 2D Cauchy walk (heavy tails)
random_cauchy_walk(.num_walks = 10, .n = 200, .dimensions = 2)

# 3D exponential walk
random_exponential_walk(.num_walks = 5, .n = 300, .dimensions = 3)
```

## Understanding the Data Structure

### Column Naming Convention

**1D Walk Columns:**
```
walk_number, step_number, y, cum_sum_y, cum_prod_y, cum_min_y, cum_max_y, cum_mean_y
```

**2D Walk Columns:**
```
walk_number, step_number, x, y,
cum_sum_x, cum_sum_y,
cum_prod_x, cum_prod_y,
cum_min_x, cum_min_y,
cum_max_x, cum_max_y,
cum_mean_x, cum_mean_y
```

**3D Walk Columns:**
```
walk_number, step_number, x, y, z,
cum_sum_x, cum_sum_y, cum_sum_z,
cum_prod_x, cum_prod_y, cum_prod_z,
(and so on for each dimension)
```

### Inspecting Multi-Dimensional Data

```{r inspect_data}
# 2D walk
walk_2d <- random_normal_walk(.num_walks = 3, .n = 100, .dimensions = 2)

# View structure
head(walk_2d, 10)
names(walk_2d)

# 3D walk
walk_3d <- random_normal_walk(.num_walks = 3, .n = 100, .dimensions = 3)

# View structure
head(walk_3d, 10)
names(walk_3d)
```

## Visualizing 2D Walks

### Basic 2D Trajectory Plot

```{r basic_2d_plot, fig.alt="2D random walk trajectories showing multiple walks with start points marked as white circles and end points as red triangles"}

# Generate 2D walk
walk_2d <- random_normal_walk(.num_walks = 10, .n = 200, .dimensions = 2)

# Plot trajectories
ggplot(walk_2d, aes(x = cum_sum_x, y = cum_sum_y, color = walk_number)) +
  geom_path(alpha = 0.6, linewidth = 0.5) +
  geom_point(data = walk_2d %>% filter(step_number == 1),
             size = 3, shape = 21, fill = "white") +  # Start points
  geom_point(data = walk_2d %>% group_by(walk_number) %>% slice_max(step_number),
             size = 3, shape = 24, fill = "red") +  # End points
  coord_equal() +
  theme_minimal() +
  labs(
    title = "2D Random Walk Trajectories",
    x = "X Position",
    y = "Y Position",
    color = "Walk"
  )
```

### 2D Walk with Step Numbers

```{r step_numbers_2d, fig.alt="Single 2D random walk with step numbers labeled at intervals of 10 steps, colored by step progression"}
# Generate single walk
walk_2d <- random_normal_walk(.num_walks = 1, .n = 100, .dimensions = 2)

# Plot with step labels at intervals
walk_2d_labeled <- walk_2d %>%
  filter(step_number %% 10 == 0 | step_number == 1)

ggplot(walk_2d, aes(x = cum_sum_x, y = cum_sum_y)) +
  geom_path(color = "steelblue", linewidth = 1) +
  geom_point(data = walk_2d_labeled, aes(color = step_number), size = 3) +
  geom_text(data = walk_2d_labeled, aes(label = step_number),
            hjust = -0.3, vjust = -0.3, size = 3) +
  scale_color_viridis_c() +
  coord_equal() +
  theme_minimal() +
  labs(
    title = "2D Random Walk with Step Numbers",
    x = "X Position",
    y = "Y Position",
    color = "Step"
  )
```

### Heat Map of 2D Walk Density

```{r heatmap_2d, fig.alt="Heat map showing the density of 100 random walks with 500 steps each, using a plasma color scale to indicate visit frequency"}
library(ggplot2)

# Generate many walks
walk_2d <- random_normal_walk(.num_walks = 100, .n = 500, .dimensions = 2)

# Create density heat map
ggplot(walk_2d, aes(x = cum_sum_x, y = cum_sum_y)) +
  geom_bin2d(bins = 50) +
  scale_fill_viridis_c(option = "plasma") +
  coord_equal() +
  theme_minimal() +
  labs(
    title = "2D Random Walk Density Heat Map",
    subtitle = "100 walks, 500 steps each",
    x = "X Position",
    y = "Y Position",
    fill = "Count"
  )
```

### Animated 2D Walk

```{r animated_2d, eval=FALSE}
library(ggplot2)
library(gganimate)

# Generate walk
walk_2d <- random_normal_walk(.num_walks = 5, .n = 100, .dimensions = 2)

# Create animation
p <- ggplot(walk_2d, aes(x = cum_sum_x, y = cum_sum_y, color = walk_number)) +
  geom_path(aes(group = walk_number), alpha = 0.5) +
  geom_point(size = 3) +
  coord_equal() +
  theme_minimal() +
  labs(title = "Step: {frame_along}", x = "X", y = "Y") +
  transition_reveal(step_number)

# Render
animate(p, nframes = 100, fps = 10)
```

## Visualizing 3D Walks

### 3D Scatter Plot

```{r 3d_scatter, eval=FALSE}
library(plotly)

# Generate 3D walk
walk_3d <- random_normal_walk(.num_walks = 5, .n = 200, .dimensions = 3)

# Create 3D plot
plot_ly(
  data = walk_3d,
  x = ~cum_sum_x,
  y = ~cum_sum_y,
  z = ~cum_sum_z,
  color = ~walk_number,
  type = "scatter3d",
  mode = "lines",
  line = list(width = 2)
) %>%
  layout(
    title = "3D Random Walk Trajectories",
    scene = list(
      xaxis = list(title = "X Position"),
      yaxis = list(title = "Y Position"),
      zaxis = list(title = "Z Position")
    )
  )
```

### 3D Interactive with Markers

```{r 3d_markers, eval=FALSE}
library(plotly)
library(dplyr)

# Generate 3D walk
walk_3d <- random_normal_walk(.num_walks = 3, .n = 100, .dimensions = 3)

# Mark start and end points
walk_with_markers <- walk_3d %>%
  mutate(
    point_type = case_when(
      step_number == 1 ~ "Start",
      step_number == max(step_number) ~ "End",
      TRUE ~ "Path"
    )
  )

# Create plot
plot_ly(data = walk_with_markers) %>%
  # Add paths
  add_trace(
    data = walk_with_markers %>% filter(point_type == "Path"),
    x = ~cum_sum_x, y = ~cum_sum_y, z = ~cum_sum_z,
    color = ~walk_number,
    type = "scatter3d",
    mode = "lines",
    line = list(width = 2),
    showlegend = FALSE
  ) %>%
  # Add start points
  add_trace(
    data = walk_with_markers %>% filter(point_type == "Start"),
    x = ~cum_sum_x, y = ~cum_sum_y, z = ~cum_sum_z,
    type = "scatter3d",
    mode = "markers",
    marker = list(size = 8, color = "green", symbol = "circle"),
    name = "Start"
  ) %>%
  # Add end points
  add_trace(
    data = walk_with_markers %>% filter(point_type == "End"),
    x = ~cum_sum_x, y = ~cum_sum_y, z = ~cum_sum_z,
    type = "scatter3d",
    mode = "markers",
    marker = list(size = 8, color = "red", symbol = "diamond"),
    name = "End"
  ) %>%
  layout(
    title = "3D Random Walk with Start/End Markers",
    scene = list(
      xaxis = list(title = "X"),
      yaxis = list(title = "Y"),
      zaxis = list(title = "Z")
    )
  )
```

### 3D Projections

```{r 3d_projections, fig.width=10, fig.height=8, fig.alt="Three projection plots showing X-Y, X-Z, and Y-Z views of 3D random walks, arranged with X-Y on top and X-Z and Y-Z side by side below"}
library(ggplot2)
library(patchwork)

# Generate 3D walk
walk_3d <- random_normal_walk(.num_walks = 5, .n = 200, .dimensions = 3)

# X-Y projection
p_xy <- ggplot(walk_3d, aes(x = cum_sum_x, y = cum_sum_y, color = walk_number)) +
  geom_path(alpha = 0.6) +
  coord_equal() +
  theme_minimal() +
  labs(title = "X-Y Projection")

# X-Z projection
p_xz <- ggplot(walk_3d, aes(x = cum_sum_x, y = cum_sum_z, color = walk_number)) +
  geom_path(alpha = 0.6) +
  coord_equal() +
  theme_minimal() +
  labs(title = "X-Z Projection")

# Y-Z projection
p_yz <- ggplot(walk_3d, aes(x = cum_sum_y, y = cum_sum_z, color = walk_number)) +
  geom_path(alpha = 0.6) +
  coord_equal() +
  theme_minimal() +
  labs(title = "Y-Z Projection")

# Combine
p_xy / (p_xz | p_yz) +
  plot_layout(guides = "collect") +
  plot_annotation(title = "3D Random Walk - All Projections")
```

## Distance and Spatial Analysis

### Euclidean Distance from Origin

```{r distance_2d, eval=FALSE, fig.alt="Line plot showing distance from origin over time for 10 random walks in 2D, with a dashed black line showing the theoretical expectation"}
library(dplyr)

# 2D walk
walk_2d <- random_normal_walk(.num_walks = 10, .n = 500, .dimensions = 2)

# Calculate distance
walk_with_distance <- walk_2d %>%
  euclidean_distance(.x = x, .y = y)

# Visualize distance over time
library(ggplot2)

ggplot(walk_with_distance, aes(x = step_number, y = distance, color = walk_number)) +
  geom_line(alpha = 0.7) +
  # Add theoretical expectation
  geom_line(aes(y = sqrt(2 * step_number)), color = "black", linetype = "dashed", linewidth = 1) +
  theme_minimal() +
  labs(
    title = "Distance from Origin in 2D Random Walk",
    subtitle = "Dashed line shows theoretical E[distance] = sqrt(2n)",
    x = "Step",
    y = "Euclidean Distance"
  )
```

### 3D Distance Analysis

```{r distance_3d, eval=FALSE}
# 3D walk
walk_3d <- random_normal_walk(.num_walks = 100, .n = 1000, .dimensions = 3)

# Calculate distance
walk_with_distance <- walk_3d %>%
  euclidean_distance(.x = x, .y = z)

# Analyze distance distribution at specific steps
library(dplyr)

distance_at_steps <- walk_with_distance %>%
  filter(step_number %in% c(100, 250, 500, 1000)) %>%
  group_by(step_number) %>%
  reframe(
    mean_dist = mean(distance),
    sd_dist = sd(distance),
    theoretical_mean = sqrt(3 * step_number)
  )

print(distance_at_steps)
```

### Radial Distribution Function

```{r radial_dist, eval=FALSE, fig.alt="Histogram with density overlay showing the radial distribution of final positions for 500 random walks"}
library(dplyr)
library(ggplot2)

# Generate many 2D walks
walk_2d <- random_normal_walk(.num_walks = 500, .n = 200, .dimensions = 2)

# Get final positions
final_positions <- walk_2d %>%
  group_by(walk_number) %>%
  slice_max(step_number) %>%
  euclidean_distance(.x = x, .y = y)

# Plot radial distribution
ggplot(final_positions, aes(x = distance)) +
  geom_histogram(aes(y = after_stat(density)), bins = 50, fill = "steelblue", alpha = 0.7) +
  geom_density(color = "darkblue", linewidth = 1) +
  theme_minimal() +
  labs(
    title = "Radial Distribution of Final Positions (2D)",
    subtitle = "500 walks, 200 steps each",
    x = "Distance from Origin",
    y = "Density"
  )
```

### Convex Hull (2D)

```{r convex_hull, eval=FALSE, fig.alt="2D random walk paths with a black polygon showing the convex hull of all final positions"}
library(dplyr)
library(ggplot2)

# Generate 2D walks
walk_2d <- random_normal_walk(.num_walks = 20, .n = 200, .dimensions = 2)

# Get final positions
final_positions <- walk_2d %>%
  group_by(walk_number) %>%
  slice_max(step_number)

# Calculate convex hull
hull <- chull(final_positions$cum_sum_x, final_positions$cum_sum_y)
hull_points <- final_positions[c(hull, hull[1]), ]  # Close the polygon

# Plot
ggplot(walk_2d, aes(x = cum_sum_x, y = cum_sum_y, color = walk_number)) +
  geom_path(alpha = 0.3) +
  geom_point(data = final_positions, size = 3) +
  geom_polygon(data = hull_points, aes(x = cum_sum_x, y = cum_sum_y),
               fill = NA, color = "black", linewidth = 1) +
  coord_equal() +
  theme_minimal() +
  labs(
    title = "2D Random Walks with Convex Hull",
    subtitle = "Black polygon shows convex hull of final positions",
    x = "X Position",
    y = "Y Position"
  )
```

## Use Cases

### Case 1: Particle Diffusion (2D)

```{r particle_diffusion, eval=FALSE, fig.alt="Line plot showing particle diffusion distance from origin over time, with individual particle paths in light colors and mean distance in bold red"}
# Simulate particle diffusion in a petri dish
particles <- brownian_motion(
  .num_walks = 50,
  .n = 1000,
  .delta_time = 0.1,
  .dimensions = 2
)

# Visualize
particles %>%
  euclidean_distance(.x = x, .y = y) %>%
  ggplot(aes(x = step_number, y = distance, color = walk_number)) +
  geom_line(alpha = 0.3) +
  stat_summary(aes(group = 1), fun = mean, geom = "line",
               color = "red", linewidth = 1.5) +
  theme_minimal() +
  labs(
    title = "Particle Diffusion in 2D",
    subtitle = "Red line shows mean distance",
    x = "Time Step",
    y = "Distance from Origin"
  )
```

### Case 2: Drone Flight Path (3D)

```{r drone_path, eval=FALSE}
# Simulate drone wandering in 3D space
drone_path <- brownian_motion(
  .num_walks = 1,
  .n = 500,
  .delta_time = 0.5,
  .initial_value = 100,  # Start at 100m altitude
  .dimensions = 3
)

# 3D visualization
library(plotly)

plot_ly(
  data = drone_path,
  x = ~cum_sum_x,
  y = ~cum_sum_y,
  z = ~cum_sum_z,
  type = "scatter3d",
  mode = "lines+markers",
  marker = list(
    size = 2,
    color = ~step_number,
    colorscale = "Viridis",
    showscale = TRUE
  ),
  line = list(width = 2, color = "steelblue")
) %>%
  layout(
    title = "Drone Flight Path (3D Random Walk)",
    scene = list(
      xaxis = list(title = "X (meters)"),
      yaxis = list(title = "Y (meters)"),
      zaxis = list(title = "Altitude (meters)")
    )
  )
```

### Case 3: Animal Movement (2D)

```{r animal_movement, eval=FALSE, fig.alt="2D random walk showing animal foraging behavior with path colored by distance from home, and a red triangle marking the home location"}
# Simulate animal foraging behavior
# Using Cauchy walk for heavy tails (occasional long jumps)
animal_movement <- random_cauchy_walk(
  .num_walks = 1,
  .n = 200,
  .scale = 1,
  .dimensions = 2
)

# Add "home" location
animal_movement <- animal_movement %>%
  mutate(
    distance_from_home = sqrt(cum_sum_x^2 + cum_sum_y^2)
  )

# Plot
ggplot(animal_movement, aes(x = cum_sum_x, y = cum_sum_y)) +
  geom_path(color = "darkgreen", linewidth = 0.8, alpha = 0.6) +
  geom_point(aes(color = distance_from_home), size = 2) +
  geom_point(x = 0, y = 0, size = 5, color = "red", shape = 17) +  # Home
  scale_color_viridis_c(option = "magma") +
  coord_equal() +
  theme_minimal() +
  labs(
    title = "Animal Foraging Path (2D Cauchy Walk)",
    subtitle = "Red triangle marks home location",
    x = "X Position",
    y = "Y Position",
    color = "Distance\nfrom Home"
  )
```

## Best Practices

### Performance Considerations

**For many walks or long walks in 3D:**
```{r performance, eval=FALSE}
# Reduce number of dimensions if not needed
walk_2d <- random_normal_walk(.num_walks = 100, .n = 1000, .dimensions = 2)

# Instead of
# walk_3d <- random_normal_walk(.num_walks = 100, .n = 1000, .dimensions = 3)
```

**For visualization:**
```{r viz_perf, eval=FALSE}
# Sample walks or steps for large datasets
walk_large <- random_normal_walk(.num_walks = 1000, .n = 1000, .dimensions = 2)

# Sample walks
walk_sample <- walk_large %>%
  filter(walk_number %in% sample(levels(walk_number), 50))

# Or downsample steps
walk_downsample <- walk_large %>%
  filter(step_number %% 10 == 0)
```

### Coordinate Systems

**Ensure equal aspect ratios for spatial plots:**
```{r coord_systems, eval=FALSE}
# Good - maintains true spatial relationships
ggplot(walk_2d, aes(x = cum_sum_x, y = cum_sum_y)) +
  geom_path() +
  coord_equal()  # Important!

# Bad - distorts spatial relationships
ggplot(walk_2d, aes(x = cum_sum_x, y = cum_sum_y)) +
  geom_path()  # No coord_equal()
```

### Boundary Conditions

Implement reflecting or absorbing boundaries:

```{r boundaries, eval=FALSE, fig.alt="2D random walk with reflecting boundaries shown by a black rectangle, demonstrating how walks bounce back when reaching the boundary"}
# Reflecting boundary (bounce back)
walk_2d <- random_normal_walk(.num_walks = 10, .n = 500, .dimensions = 2)

walk_bounded <- walk_2d %>%
  mutate(
    cum_sum_x = pmin(pmax(cum_sum_x, -50), 50),  # Bound between -50 and 50
    cum_sum_y = pmin(pmax(cum_sum_y, -50), 50)
  )

# Visualize
ggplot(walk_bounded, aes(x = cum_sum_x, y = cum_sum_y, color = walk_number)) +
  geom_path(alpha = 0.6) +
  geom_rect(xmin = -50, xmax = 50, ymin = -50, ymax = 50,
            fill = NA, color = "black", linewidth = 1) +
  coord_equal() +
  theme_minimal() +
  labs(title = "2D Walk with Reflecting Boundaries")
```

## Next Steps

For more information on RandomWalker, explore these resources:

- **Getting Started** - Introduction to random walks
- **Basic Concepts** - Core ideas and terminology
- **Continuous Distribution Generators** - Walks based on continuous distributions
- **Discrete Distribution Generators** - Walks based on discrete distributions
- **FAQ** - Frequently asked questions
- **API Reference** - Complete function documentation
**Need more examples?** Check out the package documentation and vignettes for additional use cases and applications!
