diff --git a/Code/.gitignore b/Code/.gitignore new file mode 100644 index 0000000..700853e --- /dev/null +++ b/Code/.gitignore @@ -0,0 +1,53 @@ +# Python byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +build/ +dist/ +*.egg-info/ +pip-wheel-metadata/ + +# Virtual environments +.env/ +.venv/ +venv/ +ENV/ +env.bak/ + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.coverage +.coverage.* +.cache +.pytest_cache/ +.tox/ + +# Mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre +.pyre/ + +# Django stuff: +*.log +local_settings.py + +# VSCode +.vscode/ + +# macOS +.DS_Store + +# Miscellaneous +Thumbs.db \ No newline at end of file diff --git a/Code/pyproject.toml b/Code/pyproject.toml new file mode 100644 index 0000000..651cd4b --- /dev/null +++ b/Code/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "efficient_algorithms" +version = "0.1.0" + +[build-system] +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +where = ["src"] \ No newline at end of file diff --git a/Code/src/3d_plot/__init__.py b/Code/src/3d_plot/__init__.py new file mode 100644 index 0000000..eaa6222 --- /dev/null +++ b/Code/src/3d_plot/__init__.py @@ -0,0 +1,24 @@ +import matplotlib.pyplot as plt + +import numpy as np + +def f(x): + return 4*np.sin(x) + +def g(x): + return x**2 + +def plot_3d_surface(): + fig = plt.figure() + ax = fig.add_subplot(111, projection='3d') + x = np.linspace(-5, 5, 100) + y = np.linspace(-5, 5, 100) + X, Y = np.meshgrid(x, y) + Z = f(X) + g(Y) + ax.plot_surface(X, Y, Z, cmap='viridis') + ax.set_xlabel('X-axis') + ax.set_ylabel('Y-axis') + ax.set_zlabel('Z-axis') + plt.show() +if __name__ == "__main__": + plot_3d_surface() diff --git a/Code/src/gradient/__init__.py b/Code/src/gradient/__init__.py new file mode 100644 index 0000000..5ba7b58 --- /dev/null +++ b/Code/src/gradient/__init__.py @@ -0,0 +1,132 @@ +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.colors as mcolors +import noise + + +def generate_noise(seed, scale=300.0, size=(512, 512)): + """ + Generates 2D Perlin noise using the noise library. + A higher scale means a lower frequency and smoother noise. + + :param seed: Random seed for noise generation. + :param scale: Scale factor for the noise (higher = smoother). + :param size: Size (width, height) of the generated noise map. + :return: 2D numpy array representing the noise. + """ + width, height = size + noise_map = np.zeros((width, height)) + frequency = 1.0 / scale # Lower frequency for smoother noise + + # Reduce octaves and persistence to smooth the surface + for i in range(width): + for j in range(height): + noise_map[i][j] = noise.pnoise2( + i * frequency, + j * frequency, + octaves=3, # Fewer octaves for less roughness + persistence=0.4, # Lower persistence for smoother transitions + lacunarity=2.0, + repeatx=1024, + repeaty=1024, + base=seed, + ) + return noise_map + + +def plot_surface(data, title="3D Surface Plot", cmap="viridis", gamma=1.0): + """ + Plots a 3D surface of the provided 2D noise map. + Applies a gamma correction to enhance contrast so that the global + minimum (-1) and maximum (1) are clearly visible as blue and red, respectively. + + :param data: 2D numpy array representing the heightmap. + :param title: Title of the plot. + :param cmap: Colormap for the surface plot. + :param gamma: Gamma value for non-linear contrast enhancement. + (Use a value less than 1 to boost mid-range values.) + """ + fig = plt.figure() + ax = fig.add_subplot(111, projection="3d") + + # Create grid coordinates matching the data dimensions. + x = np.arange(data.shape[0]) + y = np.arange(data.shape[1]) + x, y = np.meshgrid(x, y) + + # Apply gamma correction. + # Using gamma < 1 (e.g., 0.5) increases the contrast: + # mid-range values are boosted toward the extremes. + plot_data = np.sign(data.T) * np.power(np.abs(data.T), gamma) + + # Fix the color mapping to the global range (-1 to 1) + ax.plot_surface(x, y, plot_data, cmap=cmap, vmin=-1, vmax=1) + ax.set_title(title) + plt.show() + + +# Generate and plot the noise heightmap. +noise_map = generate_noise(seed=0, scale=500.0, size=(1024, 1024)) + +# Create a custom colormap with blue for the global minimum and red for the global maximum. +custom_colormap = mcolors.LinearSegmentedColormap.from_list("blue_red", ["blue", "red"]) + +# Use gamma=0.5 to boost the contrast in the desired direction. +plot_surface( + noise_map, title="3D Surface Plot of Noise", cmap=custom_colormap, gamma=0.5 +) + +def gradient_descent( + start, + target, + learning_rate=0.01, + max_iterations=1000, + tolerance=1e-6, +): + """ + Performs gradient descent to find the optimal path from start to target. + + :param start: Starting point (x, y). + :param target: Target point (x, y). + :param learning_rate: Step size for each iteration. + :param max_iterations: Maximum number of iterations. + :param tolerance: Convergence threshold. + :return: List of points representing the path from start to target. + """ + path = [start] + current_point = np.array(start) + + for _ in range(max_iterations): + gradient = np.array(target) - current_point + norm = np.linalg.norm(gradient) + + if norm < tolerance: + break + + gradient /= norm # Normalize the gradient + current_point += learning_rate * gradient + path.append(tuple(current_point)) + + return path +# Example usage of gradient descent with interactive plotting. +def interactive_gradient_descent(start, target): + """ + Interactive gradient descent visualization. + + :param start: Starting point (x, y). + :param target: Target point (x, y). + """ + path = gradient_descent(start, target) + + plt.figure() + plt.plot(*zip(*path), marker="o") + plt.title("Gradient Descent Path") + plt.xlabel("X") + plt.ylabel("Y") + plt.grid() + plt.show() +# Example usage of the gradient descent function. +start_point = (0, 0) +target_point = (10, 10) +interactive_gradient_descent(start_point, target_point) +# This code generates a 3D surface plot of Perlin noise and demonstrates gradient descent. diff --git a/Code/src/heap/__init__.py b/Code/src/heap/__init__.py new file mode 100644 index 0000000..68e3849 --- /dev/null +++ b/Code/src/heap/__init__.py @@ -0,0 +1,64 @@ +import numpy as np +import matplotlib.pyplot as plt + +def fix_heap(heap, idx, highest): + # Standard heapify: ensure the subtree rooted at idx is a max heap + largest = idx + left = 2 * idx + 1 + right = 2 * idx + 2 + # Check if left child exists and is greater than root + if left <= highest and heap[left] > heap[largest]: + largest = left + # Check if right child exists and is greater than largest so far + if right <= highest and heap[right] > heap[largest]: + largest = right + + # Swap and continue heapifying if root is not largest + if largest != idx: + heap[idx], heap[largest] = heap[largest], heap[idx] + fix_heap(heap, largest, highest) + +def linearize_heap_in_order(heap): + """ + Returns a copy of the heap as a linear list using in-order traversal. + """ + heap_copy = heap.copy() + n = len(heap_copy) + result = [] + def in_order_traversal(index): + if index < n: + # Traverse left subtree + in_order_traversal(2 * index + 1) + # Visit node + result.append(heap_copy[index]) + # Traverse right subtree + in_order_traversal(2 * index + 2) + in_order_traversal(0) + return result + +def heap_sort(A): + n = len(A) + heap = A.copy() + # Build max heap + for i in range(n // 2 - 1, -1, -1): + fix_heap(heap, i, n - 1) + + # Extract elements one by one + for i in range(n - 1, 0, -1): + heap[0], heap[i] = heap[i], heap[0] + fix_heap(heap, 0, i - 1) + return heap + +amount = 10 +Y = np.linspace(0, 100, amount) +Y = np.random.permutation(Y) +X = np.linspace(0, 100, amount) + +plt.scatter(X, Y) + + +Y = heap_sort(Y) + +plt.scatter(X, Y) + +plt.show() diff --git a/Code/src/heap_gauss/__init__.py b/Code/src/heap_gauss/__init__.py new file mode 100644 index 0000000..a8b608c --- /dev/null +++ b/Code/src/heap_gauss/__init__.py @@ -0,0 +1,36 @@ +import numpy as np +import matplotlib.pyplot as plt + +def gaussian_order(arr): + """ + Reorders the array so that the highest element is in the middle, + and the remaining elements descend alternating to the left and right. + """ + n = len(arr) + s = sorted(arr, reverse=True) + result = [None] * n + mid = n // 2 + result[mid] = s[0] + left_offset = 1 + right_offset = 1 + for i in range(1, n): + if i % 2 == 1: + result[mid - left_offset] = s[i] + left_offset += 1 + else: + result[mid + right_offset] = s[i] + right_offset += 1 + return result + +amount = 20 +X = np.linspace(0, 50, amount) +# Generate random non linspace values +A = np.random.rand(amount) * 50 +ordered_A = gaussian_order(A) + +# Plot as bar chart +plt.bar(X, ordered_A, color='blue', alpha=0.5) +plt.xlabel('X-axis') +plt.ylabel('Value') +plt.title('Gaussian-like Distribution') +plt.show() diff --git a/Code/src/lambda/__init__.py b/Code/src/lambda/__init__.py new file mode 100644 index 0000000..d7fb9cc --- /dev/null +++ b/Code/src/lambda/__init__.py @@ -0,0 +1,7 @@ +# factorial = lambda x: 1 if x < 1 else x * factorial(x - 1) + +factorial = (lambda f: lambda x: 1 if x == 0 else x * f(f)(x - 1))( + lambda f: lambda x: 1 if x == 0 else x * f(f)(x - 1) +) + +print(factorial(5)) # 120 diff --git a/Code/src/shell/__init__.py b/Code/src/shell/__init__.py new file mode 100644 index 0000000..d1b8045 --- /dev/null +++ b/Code/src/shell/__init__.py @@ -0,0 +1,110 @@ +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.widgets import Slider + +# Für reproduzierbare Ergebnisse +np.random.seed(42) + +# Parameter: Länge der Liste und initiale Schrittweite +n = 50 +init_gap = 7 + +# Erzeuge eine bijektive Liste mittels linspace (sortiert) und shuffele sie dann +sorted_function = np.linspace(0, 100, n) # Die ideale Funktion (sortierte Liste) +indices = np.arange(n) +np.random.shuffle(indices) +arr = sorted_function[indices] # Geshuffelte Version + + +def gap_sort(arr, gap): + """ + Führt die Vorsortierung (gapped insertion sort) mit gegebener Schrittweite (gap) durch. + """ + n = len(arr) + sorted_arr = arr.copy() + for start in range(gap): + # Bestimme die Indizes der Teilsequenz + indices = list(range(start, n, gap)) + sublist = sorted_arr[indices] + sublist.sort() + # Setze die sortierte Teilsequenz wieder ein + for i, idx in enumerate(indices): + sorted_arr[idx] = sublist[i] + return sorted_arr + + +# Berechne die vorsortierte Liste für den initialen gap-Wert +vorsprung = gap_sort(arr, init_gap) + +# Erstelle die Figure mit zwei Subplots und passe den unteren Rand für den Slider an +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6)) +plt.subplots_adjust(bottom=0.25) + +# ---- Linker Subplot: Shuffled Liste und Abweichungen zur sortierten Funktion ---- +ax1.scatter(np.arange(n), arr, c="tab:blue", label="Geshuffelt") +ax1.plot(np.arange(n), sorted_function, "r--", label="Sortierte Funktion") +for i in range(n): + ax1.plot( + [i, i], + [arr[i], sorted_function[i]], + color="gray", + linestyle="--", + linewidth=0.5, + ) +ax1.set_title("Geshuffelte Liste\nmit Abweichungen zur sortierten Funktion") +ax1.set_xlabel("Index") +ax1.set_ylabel("Wert") +ax1.legend() +ax1.grid(True) + +# ---- Rechter Subplot: Ergebnis der Vorsortierung (gapped insertion sort) ---- +deviation = vorsprung - sorted_function +dmax = np.max(deviation) +dmin = np.min(deviation) + +sc2 = ax2.scatter(np.arange(n), vorsprung, c="tab:orange") +ax2.plot(np.arange(n), sorted_function + dmax, "g--", label="Obere Fehlergrenze") +ax2.plot(np.arange(n), sorted_function + dmin, "r--", label="Untere Fehlergrenze") +# Setze feste Achsenlimits für ein stimmiges Seitenverhältnis +ax2.set_xlim(0, n - 1) +ax2.set_ylim(min(sorted_function) - 10, max(sorted_function) + 10) +ax2.set_title(f"Vorsortierung (Gap = {init_gap})") +ax2.set_xlabel("Index") +ax2.set_ylabel("Wert") +ax2.legend() +ax2.grid(True) + +# ---- Slider zur Anpassung der Schrittweite ---- +ax_gap = plt.axes([0.25, 0.1, 0.5, 0.03]) +slider_gap = Slider(ax_gap, "Gap", 1, n, valinit=init_gap, valstep=1) + + +def update(val): + gap_val = int(slider_gap.val) + new_vorsprung = gap_sort(arr, gap_val) + + ax2.cla() # Lösche den aktuellen Inhalt von ax2 + # Scatterplot der vorsortierten Liste + ax2.scatter(np.arange(n), new_vorsprung, c="tab:orange") + ax2.set_title(f"Vorsortierung (Gap = {gap_val})") + ax2.set_xlabel("Index") + ax2.set_ylabel("Wert") + ax2.grid(True) + + # Berechne die Abweichungen zur idealen Funktion + deviation = new_vorsprung - sorted_function + dmax = np.max(deviation) + dmin = np.min(deviation) + # Zeichne die Fehlergrenzen als parallele Linien zur idealen Funktion + ax2.plot(np.arange(n), sorted_function + dmax, "g--", label="Obere Fehlergrenze") + ax2.plot(np.arange(n), sorted_function + dmin, "r--", label="Untere Fehlergrenze") + ax2.set_xlim(0, n - 1) + ax2.set_ylim(min(sorted_function) - 10, max(sorted_function) + 10) + ax2.legend() + + fig.canvas.draw_idle() + + +slider_gap.on_changed(update) + +plt.show() diff --git a/Code/uv.lock b/Code/uv.lock new file mode 100644 index 0000000..319752b --- /dev/null +++ b/Code/uv.lock @@ -0,0 +1,8 @@ +version = 1 +revision = 1 +requires-python = ">=3.13" + +[[package]] +name = "efficient-algorithms" +version = "0.1.0" +source = { editable = "." }