Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 162 additions & 0 deletions dynamic_programming/kadane's_algo.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Kadane's Algorithm in R
#
# Finds the contiguous subarray with the largest sum.
# Time Complexity: O(n)
# Space Complexity: O(1) (not counting output subarray)
#
# Applications:
# - Financial time series (max profit window)
# - Signal processing (max energy segment)
# - Pattern detection in sequences
# - As a subroutine in more complex DP/optimization tasks

kadane <- function(arr) {
#' Kadane's algorithm to find maximum subarray sum and its indices
#' @param arr: Numeric vector (can include negatives and positives)
#' @return: A list with fields:
#' max_sum - numeric: maximum subarray sum
#' start - integer: start index of the subarray (1-based), NA if empty input
#' end - integer: end index of the subarray (1-based), NA if empty input
#' subarray- numeric vector: the subarray that gives max_sum (empty if input empty)

n <- length(arr)

# Edge cases
if (n == 0) {
return(list(
max_sum = -Inf,
start = NA_integer_,
end = NA_integer_,
subarray = numeric(0)
))
}

# Initialize with first element (handles all-negative arrays correctly)
max_ending_here <- arr[1]
max_so_far <- arr[1]
s <- 1
start <- 1
end <- 1

if (n >= 2) {
for (i in 2:n) {
# If adding arr[i] to current segment is worse than starting new at arr[i]
if (max_ending_here + arr[i] < arr[i]) {
max_ending_here <- arr[i]
s <- i
} else {
max_ending_here <- max_ending_here + arr[i]
}

# Update best segment if needed
if (max_ending_here > max_so_far) {
max_so_far <- max_ending_here
start <- s
end <- i
}
}
}

return(list(
max_sum = max_so_far,
start = as.integer(start),
end = as.integer(end),
subarray = arr[start:end]
))
}

# Variant: Kadane that returns also when you want first-occurrence vs. any occurrence
kadane_first_occurrence <- function(arr) {
# exactly like kadane() but ties favor earlier segment (current code already does)
kadane(arr)
}

# Helper to pretty-print results
print_kadane_result <- function(res, arr_name="Array") {
cat("Input:", arr_name, "\n")
if (is.na(res$start)) {
cat("Result: empty input\n\n")
return(invisible(NULL))
}
cat("Max Subarray Sum:", res$max_sum, "\n")
cat("Start Index:", res$start, " End Index:", res$end, "\n")
cat("Subarray:", paste(res$subarray, collapse = ", "), "\n\n")
}

# ===========================
# Example Usage & Testing
# ===========================
cat("=== Kadane's Algorithm Tests ===\n\n")

# Test 1: Mixed positive and negative
arr1 <- c(-2, 1, -3, 4, -1, 2, 1, -5, 4)
res1 <- kadane(arr1)
print_kadane_result(res1, "arr1 (mixed)")

# Test 2: All positive
arr2 <- c(2, 3, 1, 4)
res2 <- kadane(arr2)
print_kadane_result(res2, "arr2 (all positive)")

# Test 3: All negative
arr3 <- c(-8, -3, -6, -2, -5, -4)
res3 <- kadane(arr3)
print_kadane_result(res3, "arr3 (all negative)")

# Test 4: Single element
arr4 <- c(5)
res4 <- kadane(arr4)
print_kadane_result(res4, "arr4 (single element)")

# Test 5: Empty array
arr5 <- numeric(0)
res5 <- kadane(arr5)
print_kadane_result(res5, "arr5 (empty)")

# Test 6: Random large array - timing example
set.seed(123)
arr6 <- sample(-100:100, 100000, replace = TRUE)
start_time <- Sys.time()
res6 <- kadane(arr6)
end_time <- Sys.time()
print_kadane_result(res6, "arr6 (large random)")
cat("Elapsed time (seconds):", as.numeric(end_time - start_time, units = "secs"), "\n\n")

# Optional: function to get maximum circular subarray (Kadane + total sum trick)
kadane_circular <- function(arr) {
#' Finds max subarray sum for circular arrays (wrap-around allowed)
#' If all elements are negative, returns max element (non-wrap).
n <- length(arr)
if (n == 0) return(list(max_sum = -Inf, start = NA, end = NA, subarray = numeric(0)))

# Standard Kadane for non-circular max
normal <- kadane(arr)$max_sum

# If all negative, normal already is max element; circular logic would fail
if (all(arr <= 0)) {
return(list(max_sum = normal, start = which.max(arr), end = which.max(arr), subarray = arr[which.max(arr)]))
}

# Max wrap = total_sum - min_subarray_sum
total_sum <- sum(arr)

# Find minimum subarray using Kadane on inverted array
inverted <- -arr
min_sub_sum <- kadane(inverted)$max_sum # this is -min_subarray_sum
max_wrap <- total_sum + min_sub_sum # because min_sub_sum is negative of min subarray

if (max_wrap > normal) {
return(list(max_sum = max_wrap, start = NA, end = NA, subarray = NA)) # indices for wrap-around not computed here
} else {
return(list(max_sum = normal, start = kadane(arr)$start, end = kadane(arr)$end, subarray = kadane(arr)$subarray))
}
}

# Example for circular
cat("=== Circular Kadane Example ===\n")
arrc <- c(8, -1, 3, 4)
res_circ <- kadane_circular(arrc)
cat("Input:", paste(arrc, collapse = ", "), "\n")
cat("Max circular subarray sum:", res_circ$max_sum, "\n\n")

# End of script
52 changes: 52 additions & 0 deletions graph_algorithms/edmonds_blossom.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# ==============================================
# Edmonds’ Blossom Algorithm
# ==============================================
# Algorithm: Maximum matching in general (non-bipartite) graphs.
# Framework: R (using igraph package)
#
# Purpose:
# - Compute the maximum matching in a general (non-bipartite) graph.
# - Finds the largest set of edges without common vertices.
#
# Core Idea:
# - Uses the Blossom algorithm to handle odd-length cycles (blossoms) in non-bipartite graphs.
# - Iteratively augments paths to find the maximum matching.
#
# Complexity:
# - Time: O(V^3) in general (V = number of vertices)
# - Space: O(V + E) for graph representation
#
# Edge Cases / Notes:
# - Works for both bipartite and non-bipartite graphs.
# - Handles odd-length cycles using the blossom contraction technique.
#
# Typical Applications:
# - Network pairing/matching problems
# - Job assignment and scheduling
# - Stable pairings in tournaments or projects
#
# Reference:
# Edmonds, J. (1965). Paths, trees, and flowers. Canadian Journal of Mathematics.
# ==============================================

# Load required library
suppressPackageStartupMessages(library(igraph))

# Example Graph: Non-bipartite
edges <- c(1,2, 1,3, 2,4, 3,4, 4,5)
g <- graph(edges, directed = FALSE)

# Compute Maximum Matching
matching <- max_matching(g) # Use max_matching for general (non-bipartite) graphs
max_match_edges <- matching$matching

# Display Result
cat("Maximum matching edges:\n")
print(max_match_edges)

# ==============================================
# Note:
# - This script defines the Edmonds’ Blossom Algorithm in R using igraph.
# - Suitable for small to medium non-bipartite graphs.
# - For large graphs, performance may degrade due to cubic complexity.
# ==============================================
84 changes: 84 additions & 0 deletions graph_algorithms/stoer_wagner.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# ==============================================
# Stoer-Wagner Algorithm
# ==============================================
# Algorithm: Global minimum cut in undirected weighted graphs.
# Framework: R (base R)
#
# Purpose:
# - Find the minimum cut in an undirected weighted graph.
# - Identifies the smallest set of edges whose removal disconnects the graph.
#
# Core Idea:
# - Repeatedly merge vertices while keeping track of the minimum cut value.
# - Uses a greedy approach to find minimum cuts iteratively.
#
# Complexity:
# - Time: O(V^3) for dense graphs (V = number of vertices)
# - Space: O(V^2) for adjacency/weight matrix
#
# Edge Cases / Notes:
# - Works for connected undirected weighted graphs.
# - Graph must be undirected; weights must be non-negative.
# - Returns the minimum cut weight and optionally the vertex partition.
#
# Typical Applications:
# - Network reliability analysis
# - Graph clustering and partitioning
# - Identifying critical edges in networks
#
# Reference:
# Stoer, M., & Wagner, F. (1997). A simple min-cut algorithm. Journal of the ACM.
# ==============================================

# Example Graph: Adjacency Matrix (Weighted Undirected Graph)
graph <- matrix(c(
0, 3, 1, 3,
3, 0, 2, 2,
1, 2, 0, 4,
3, 2, 4, 0
), nrow = 4, byrow = TRUE)

# Stoer-Wagner Minimum Cut Function
stoer_wagner <- function(graph) {
n <- nrow(graph)
vertices <- 1:n
min_cut <- Inf

while (length(vertices) > 1) {
used <- rep(FALSE, n)
weights <- rep(0, n)
prev <- NULL

for (i in 1:length(vertices)) {
sel <- which.max(weights * (!used))
used[sel] <- TRUE
if (i == length(vertices)) {
cut_weight <- weights[sel]
if (cut_weight < min_cut) {
min_cut <- cut_weight
}
# Merge last two vertices
if (!is.null(prev)) {
graph[prev, ] <- graph[prev, ] + graph[sel, ]
graph[, prev] <- graph[prev, ]
vertices <- vertices[vertices != sel]
}
}
prev <- sel
# Update weights
weights <- weights + graph[sel, ]
}
}
return(min_cut)
}

# Compute Minimum Cut
min_cut_value <- stoer_wagner(graph)
cat("Minimum cut weight of the graph:", min_cut_value, "\n")

# ==============================================
# Note:
# - This script defines the Stoer-Wagner minimum cut algorithm in R.
# - Works with small to medium weighted undirected graphs.
# - Can be extended to return the vertex partition corresponding to the cut.
# ==============================================
56 changes: 56 additions & 0 deletions machine_learning/cnn.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# ==============================================
# Convolutional Neural Network (CNN)
# ==============================================
# Algorithm: Deep learning model using convolutional, pooling, and dense layers.
# Framework: Keras (TensorFlow backend)
#
# Purpose:
# - Automatically extract spatial and hierarchical features from image data.
# - Commonly used for image classification, object detection, and visual recognition.
#
# Architecture Steps:
# 1. Convolution Layer: Extracts local spatial patterns using learnable filters.
# 2. Activation (ReLU): Adds non-linearity by thresholding at zero.
# 3. Pooling Layer: Reduces spatial dimensions (downsampling) while preserving features.
# 4. Flatten Layer: Converts 2D feature maps into 1D vector.
# 5. Dense Layers: Combines extracted features for classification.
# 6. Output Layer: Uses Softmax activation for class probabilities.
#
# Complexity:
# - Time: O(E × N × F × K²) where E=epochs, N=samples, F=filters, K=kernel size
# - Space: O(parameters + feature maps)
#
# Reference:
# LeCun et al., "Gradient-based learning applied to document recognition" (1998)
# https://yann.lecun.com/exdb/lenet/
#
# ==============================================

# Load Required Library
suppressPackageStartupMessages(library(keras))

# Define CNN Architecture (Algorithm Only)
cnn_model <- keras_model_sequential() %>%
layer_conv_2d(
filters = 32, kernel_size = c(3, 3), activation = "relu",
input_shape = c(28, 28, 1), padding = "same"
) %>%
layer_max_pooling_2d(pool_size = c(2, 2)) %>%
layer_conv_2d(
filters = 64, kernel_size = c(3, 3),
activation = "relu", padding = "same"
) %>%
layer_max_pooling_2d(pool_size = c(2, 2)) %>%
layer_flatten() %>%
layer_dense(units = 128, activation = "relu") %>%
layer_dense(units = 10, activation = "softmax")

# Display Model Summary
summary(cnn_model)

# ==============================================
# Note:
# - This script defines the CNN algorithm structure only.
# - You can compile and train it using model %>% compile() and model %>% fit()
# with any dataset (e.g., MNIST, CIFAR-10).
# ==============================================
Loading