diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 1b79ecf..0d1fe52 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,8 +5,9 @@
-
+
+
@@ -40,7 +41,7 @@
-
+
@@ -107,8 +108,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -130,6 +154,11 @@
+
+
+
+
+
@@ -138,7 +167,8 @@
-
+
+
\ No newline at end of file
diff --git a/ext_01/control.py b/ext_01/control.py
index b3e3036..b5d8db8 100644
--- a/ext_01/control.py
+++ b/ext_01/control.py
@@ -48,3 +48,25 @@ for n in numbers:
counter += 1
print(f"|F| = {counter}")
# Ausgabe: |F| = 30240
+
+def contains_twin_pair(combo):
+ """Check if the combination contains at least one twin pair."""
+ for x in range(len(combo)):
+ for y in range(len(combo)):
+ if abs(combo[x] % 49 - combo[y] % 49) == 1:
+ return True
+ return False
+
+# Generate all combinations of 6 numbers out of 49
+numbers = list(range(1, 50))
+all_combinations = list(itertools.combinations(numbers, 6))
+
+# Filter combinations with and without twin pairs
+combinations_with_twin = [combo for combo in all_combinations if contains_twin_pair(combo)]
+combinations_without_twin = [combo for combo in all_combinations if not contains_twin_pair(combo)]
+
+# Output the count of combinations
+print(len(all_combinations))
+print(f"Number of combinations with at least one twin pair: {len(combinations_with_twin)}")
+print(f"Number of combinations without any twin pairs: {len(combinations_without_twin)}")
+print(len(combinations_with_twin)/len(all_combinations))
\ No newline at end of file
diff --git a/ha_09/loosen_janniclas_1540907_10.py b/ha_09/loosen_janniclas_1540907_10.py
new file mode 100644
index 0000000..1f1f613
--- /dev/null
+++ b/ha_09/loosen_janniclas_1540907_10.py
@@ -0,0 +1,142 @@
+import random
+from io import BytesIO
+
+import numpy as np
+import multiprocessing
+
+import requests
+from mpi4py import MPI
+from PIL import Image
+
+
+def count_randomized_hits(iterations):
+ counter = 0
+ for i in range(iterations):
+ x = random.uniform(0, 1)
+ y = random.uniform(0, 1)
+ if ((x ** 2) + (y ** 2)) ** (1 / 2) <= 1:
+ counter += 1
+ return counter
+
+
+FLAG_default = 0
+FLAG_threaded = 1
+FLAG_network = 2
+
+
+def monte_carlo_methode(n, mode=0):
+ if mode == 1: # Multithreading mode
+ num_threads = 16
+ iterations_per_thread = n // num_threads
+ with multiprocessing.Pool(num_threads) as pool:
+ hits = pool.map(count_randomized_hits, [iterations_per_thread] * num_threads)
+ hit = sum(hits)
+
+ elif mode == 2: # MPI parallel mode
+ comm = MPI.COMM_WORLD
+ rank = comm.Get_rank()
+ size = comm.Get_size()
+ local_hit = count_randomized_hits(n // size)
+ hit = comm.reduce(local_hit, op=MPI.SUM, root=0)
+
+ else: # Default mode
+ hit = count_randomized_hits(n)
+
+ pi_approx = (hit / n) * 4
+ pi_diff = abs(np.pi - pi_approx)
+
+ return pi_approx, pi_diff
+
+
+def uniform_kernel(n):
+ if n % 2 == 0:
+ print("Size needs to be odd")
+ exit(1)
+ K = 1 / n / n * np.ones([n, n])
+ return K
+
+
+def gauss_kernel(s):
+ n = 3 * s
+ pos = np.arange(-n, n + 1)
+ x = np.meshgrid(pos, pos)
+ K = 1.0 / (2.0 * np.pi * s * s) * np.exp(-(x[0] ** 2 + x[1] ** 2) / (2.0 * s * s))
+ K = K / sum(sum(K))
+ return K
+
+
+FLAG_gauss = 0
+FLAG_uniform = 1
+
+
+def process_image_part(data_part, kernel):
+ y_part_size, x_part_size, _ = data_part.shape
+ data_part_new = np.zeros_like(data_part)
+ for i in range((kernel.shape[0] - 1) // 2, y_part_size - (kernel.shape[0] - 1) // 2):
+ for j in range((kernel.shape[1] - 1) // 2, x_part_size - (kernel.shape[1] - 1) // 2):
+ for k in range(3):
+ new_value = 0.0
+ for ii in range(kernel.shape[0]):
+ for jj in range(kernel.shape[1]):
+ iii = ii - (kernel.shape[0] - 1) // 2
+ jjj = jj - (kernel.shape[1] - 1) // 2
+ new_value += kernel[ii, jj] * data_part[i + iii, j + jjj, k]
+ data_part_new[i, j, k] = new_value
+ return data_part_new
+
+
+def process_image(img, func=0, mode=0):
+ if isinstance(img, str):
+ img = Image.open(img)
+
+ if img.mode == "P":
+ img = img.convert(mode="RGB")
+
+ data = np.asarray(img, dtype=np.float64) / 255.0
+
+ if func == 1:
+ kernel = uniform_kernel(3)
+ else:
+ kernel = gauss_kernel(3)
+
+ if mode == 1: # Multithreading mode
+ num_threads = 16
+ data_parts = np.array_split(data, num_threads, axis=0)
+ with multiprocessing.Pool(num_threads) as pool:
+ data_new_parts = pool.starmap(process_image_part, zip(data_parts, [kernel]*num_threads))
+ data_new = np.concatenate(data_new_parts, axis=0)
+
+ elif mode == 2: # MPI parallel mode
+ comm = MPI.COMM_WORLD
+ rank = comm.Get_rank()
+ size = comm.Get_size()
+ data_part = np.array_split(data, size, axis=0)[rank]
+ data_new_part = process_image_part(data_part, kernel)
+ data_new_parts = comm.gather(data_new_part, root=0)
+ if rank == 0:
+ data_new = np.concatenate(data_new_parts, axis=0)
+ else:
+ data_new = None
+ data_new = comm.bcast(data_new, root=0)
+
+ else: # Default mode
+ data_new = process_image_part(data, kernel)
+
+ data_new = data_new * 255.0
+ data_new = np.uint8(data_new)
+
+ return Image.fromarray(data_new, mode="RGB")
+
+
+if __name__ == '__main__':
+ print(monte_carlo_methode(1000, FLAG_default))
+ print(monte_carlo_methode(1000, FLAG_threaded))
+ print(monte_carlo_methode(1000, FLAG_network))
+
+ url = "https://i.wfcdn.de/teaser/660/27020.jpg"
+ response = requests.get(url)
+
+ if response.status_code == 200:
+ image = Image.open(BytesIO(response.content))
+ image = process_image(image, FLAG_uniform, FLAG_threaded)
+ image.show()