Commit stuff
This commit is contained in:
6
01017 - Discrete Mathematics/ipynb filer/README.md
Normal file
6
01017 - Discrete Mathematics/ipynb filer/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Diskret Matematik gode programmer at have
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
1706
01017 - Discrete Mathematics/ipynb filer/discMatSympy.ipynb
Normal file
1706
01017 - Discrete Mathematics/ipynb filer/discMatSympy.ipynb
Normal file
File diff suppressed because it is too large
Load Diff
370
01017 - Discrete Mathematics/ipynb filer/discrete.py
Normal file
370
01017 - Discrete Mathematics/ipynb filer/discrete.py
Normal file
@@ -0,0 +1,370 @@
|
||||
import math
|
||||
import re as regex
|
||||
from itertools import combinations, permutations
|
||||
|
||||
import pandas as pd
|
||||
from sympy import *
|
||||
from sympy.ntheory.modular import crt
|
||||
from math import comb
|
||||
init_printing()
|
||||
|
||||
def superscriptify(expr):
|
||||
"""Convert an expression's powers (**) into unicode superscripts and leave multiplication as is."""
|
||||
if expr is None:
|
||||
return "*"
|
||||
s = str(expr)
|
||||
|
||||
# Map digits and minus sign to superscripts
|
||||
superscript_map = {
|
||||
'0': '⁰', '1': '¹', '2': '²', '3': '³', '4': '⁴',
|
||||
'5': '⁵', '6': '⁶', '7': '⁷', '8': '⁸', '9': '⁹',
|
||||
'-': '⁻'
|
||||
}
|
||||
|
||||
def replace_power(match):
|
||||
exponent_str = match.group(1)
|
||||
# Convert each character of the exponent to its superscript equivalent
|
||||
return ''.join(superscript_map.get(ch, ch) for ch in exponent_str)
|
||||
|
||||
# Replace all occurrences of '**<integer>' with the corresponding superscript characters
|
||||
s = regex.sub(r'\*\*(-?\d+)', lambda m: replace_power(m), s)
|
||||
|
||||
return s
|
||||
|
||||
|
||||
'''
|
||||
EUCLIDEAN ALGORITHM FUNCTIONS
|
||||
'''
|
||||
|
||||
def extended_euclidean_algorithm_polys(N: Poly, M: Poly, x: Symbol, beatify: bool = true):
|
||||
# Initialize variables for the extended Euclidean algorithm
|
||||
r = [N, M] # Remainders
|
||||
s = [Poly(1, x), Poly(0, x)] # Coefficients of N(x)
|
||||
t = [Poly(0, x), Poly(1, x)] # Coefficients of M(x)
|
||||
|
||||
# Perform the extended Euclidean algorithm
|
||||
k = 0
|
||||
while r[k+1] != 0:
|
||||
quotient, remainder = div(r[k], r[k+1])
|
||||
r.append(remainder)
|
||||
if remainder == 0:
|
||||
s.append(None)
|
||||
t.append(None)
|
||||
else:
|
||||
s.append(s[k] - quotient * s[k+1])
|
||||
t.append(t[k] - quotient * t[k+1])
|
||||
k += 1
|
||||
|
||||
results = []
|
||||
for i in range(len(r)):
|
||||
if beatify:
|
||||
r_str = superscriptify(r[i].as_expr() if r[i] is not None else None)
|
||||
s_str = superscriptify(s[i].as_expr() if s[i] is not None else None)
|
||||
t_str = superscriptify(t[i].as_expr() if t[i] is not None else None)
|
||||
else:
|
||||
r_str = r[i].as_expr() if r[i] is not None else None
|
||||
s_str = s[i].as_expr() if s[i] is not None else None
|
||||
t_str = t[i].as_expr() if t[i] is not None else None
|
||||
results.append({
|
||||
"k": i,
|
||||
"r_k(x)": r_str,
|
||||
"s_k(x)": s_str,
|
||||
"t_k(x)": t_str
|
||||
})
|
||||
|
||||
df = pd.DataFrame(results)
|
||||
return df
|
||||
|
||||
def extended_euclidean_algorithm_integers(a, b, beautify: bool = True):
|
||||
"""
|
||||
Compute the Extended Euclidean Algorithm steps for two integers a and b.
|
||||
|
||||
Returns a DataFrame with columns:
|
||||
k, r_k, s_k, t_k
|
||||
such that r_k = s_k*a + t_k*b at each step.
|
||||
"""
|
||||
# Initializations
|
||||
r = [a, b]
|
||||
s = [1, 0]
|
||||
t = [0, 1]
|
||||
|
||||
k = 0
|
||||
while r[k+1] != 0:
|
||||
quotient = r[k] // r[k+1]
|
||||
remainder = r[k] % r[k+1]
|
||||
r.append(remainder)
|
||||
|
||||
if remainder == 0:
|
||||
s.append(None)
|
||||
t.append(None)
|
||||
else:
|
||||
s.append(s[k] - quotient * s[k+1])
|
||||
t.append(t[k] - quotient * t[k+1])
|
||||
k += 1
|
||||
|
||||
results = []
|
||||
for i in range(len(r)):
|
||||
if beautify:
|
||||
r_str = superscriptify(r[i]) if r[i] is not None else None
|
||||
s_str = superscriptify(s[i]) if s[i] is not None else None
|
||||
t_str = superscriptify(t[i]) if t[i] is not None else None
|
||||
else:
|
||||
r_str = r[i]
|
||||
s_str = s[i]
|
||||
t_str = t[i]
|
||||
results.append({
|
||||
"k": i,
|
||||
"r_k": r_str,
|
||||
"s_k": s_str,
|
||||
"t_k": t_str
|
||||
})
|
||||
|
||||
df = pd.DataFrame(results)
|
||||
return df
|
||||
|
||||
class PermutationFilter:
|
||||
def __init__(self, sequence):
|
||||
self.sequence = sequence
|
||||
# Generate all permutations of the given sequence as tuples
|
||||
self.all_permutations = list(permutations(self.sequence))
|
||||
|
||||
def filter_permutations(self, include_substrings=None, exclude_substrings=None):
|
||||
"""
|
||||
Filter permutations based on optional inclusion and exclusion criteria.
|
||||
|
||||
:param include_substrings: A list of substrings. A permutation must contain
|
||||
at least one of these substrings to pass.
|
||||
:param exclude_substrings: A list of substrings. A permutation must not contain
|
||||
any of these substrings to pass.
|
||||
|
||||
:return: A list of permutations (as tuples) that match the criteria.
|
||||
"""
|
||||
filtered = self.all_permutations
|
||||
|
||||
# Convert tuple permutations into strings for checking
|
||||
# We'll do this step once to avoid repeating it for each condition
|
||||
filtered_strings = [''.join(p) for p in filtered]
|
||||
|
||||
# If include_substrings is given, keep only those permutations that contain
|
||||
# at least one of the given substrings
|
||||
if include_substrings:
|
||||
new_filtered = []
|
||||
new_filtered_strings = []
|
||||
for perm_str, perm_tuple in zip(filtered_strings, filtered):
|
||||
if any(sub in perm_str for sub in include_substrings):
|
||||
new_filtered.append(perm_tuple)
|
||||
new_filtered_strings.append(perm_str)
|
||||
filtered = new_filtered
|
||||
filtered_strings = new_filtered_strings
|
||||
|
||||
# If exclude_substrings is given, remove any permutations that contain
|
||||
# any of the given substrings
|
||||
if exclude_substrings:
|
||||
new_filtered = []
|
||||
new_filtered_strings = []
|
||||
for perm_str, perm_tuple in zip(filtered_strings, filtered):
|
||||
if not any(sub in perm_str for sub in exclude_substrings):
|
||||
new_filtered.append(perm_tuple)
|
||||
new_filtered_strings.append(perm_str)
|
||||
filtered = new_filtered
|
||||
filtered_strings = new_filtered_strings
|
||||
|
||||
return filtered
|
||||
|
||||
def derangement_formula(n):
|
||||
""" Calculate the number of derangements using the direct formula. """
|
||||
derangements = math.factorial(n) * sum(((-1) ** k) / math.factorial(k) for k in range(n + 1))
|
||||
return int(derangements)
|
||||
|
||||
def count_edges_in_n_cube(n):
|
||||
# Number of edges in the n-cube graph
|
||||
return n * (2 ** (n - 1))
|
||||
|
||||
def guaranteed_selection_count(target, numbers):
|
||||
# Step 1: Find all subsets whose sum equals the target
|
||||
target_subsets = []
|
||||
for r in range(1, len(numbers) + 1):
|
||||
for subset in combinations(numbers, r):
|
||||
if sum(subset) == target:
|
||||
target_subsets.append(set(subset))
|
||||
|
||||
# If no subset sums to the target, no finite number will guarantee it.
|
||||
if not target_subsets:
|
||||
return float('inf') # or len(numbers) + 1, depending on your preference
|
||||
|
||||
# Step 2: Find the maximum subset of 'numbers' that does NOT contain any target-sum subset fully
|
||||
# We'll brute force all subsets of 'numbers' and check.
|
||||
# For each candidate subset, we must ensure it does not include any of the target_subsets fully.
|
||||
# i.e., For every target_subset T, candidate_subset should not be a superset of T.
|
||||
|
||||
max_safe_size = 0
|
||||
n = len(numbers)
|
||||
for r in range(n + 1):
|
||||
for candidate in combinations(numbers, r):
|
||||
candidate_set = set(candidate)
|
||||
# Check if candidate_set fully contains any target_subset
|
||||
if any(t_subset.issubset(candidate_set) for t_subset in target_subsets):
|
||||
# This candidate is not safe because it contains a full target-sum subset
|
||||
continue
|
||||
# If it passes all checks, update max_safe_size
|
||||
max_safe_size = max(max_safe_size, r)
|
||||
|
||||
# Step 3: Once you exceed max_safe_size by 1, you guarantee forming a target subset
|
||||
return max_safe_size + 1
|
||||
|
||||
def check_relation_properties(A, R):
|
||||
# Convert R to a set for faster membership testing if needed
|
||||
R_set = set(R)
|
||||
|
||||
# Check Reflexive: (a,a) in R for all a in A
|
||||
reflexive = all((a, a) in R_set for a in A)
|
||||
|
||||
# Check Symmetric: For every (a,b) in R, (b,a) must also be in R
|
||||
symmetric = all((b, a) in R_set for (a, b) in R_set)
|
||||
|
||||
# Check Antisymmetric: If (a,b) and (b,a) in R, then a must be b
|
||||
# If we ever find a != b with both (a,b) and (b,a), it's not antisymmetric.
|
||||
antisymmetric = True
|
||||
for (a, b) in R_set:
|
||||
if a != b and (b, a) in R_set:
|
||||
antisymmetric = False
|
||||
break
|
||||
|
||||
# Check Transitive: If (a,b) and (b,c) in R, then (a,c) must be in R
|
||||
# We'll use a nested loop approach.
|
||||
transitive = True
|
||||
for (a, b) in R_set:
|
||||
for (x, y) in R_set:
|
||||
if b == x and (a, y) not in R_set:
|
||||
transitive = False
|
||||
break
|
||||
if not transitive:
|
||||
break
|
||||
|
||||
# Return a dictionary or tuple of results
|
||||
return {
|
||||
"reflexive": reflexive,
|
||||
"symmetric": symmetric,
|
||||
"antisymmetric": antisymmetric,
|
||||
"transitive": transitive
|
||||
}
|
||||
|
||||
def test_formula(formula_func, reference_func, test_values=range(1, 11)):
|
||||
"""
|
||||
Test a given formula function against a given reference function for a range of test values.
|
||||
Returns True if formula_func(n) == reference_func(n) for all tested values of n, False otherwise.
|
||||
"""
|
||||
for n in test_values:
|
||||
lhs = formula_func(n)
|
||||
rhs = reference_func(n)
|
||||
if lhs != rhs:
|
||||
return False
|
||||
return True
|
||||
|
||||
def solve_linear_congruence(a, b, m):
|
||||
g = gcd(a, m)
|
||||
# Tjek om løsning eksisterer
|
||||
if b % g != 0:
|
||||
return None
|
||||
|
||||
# Reducer
|
||||
a_red = a // g
|
||||
b_red = b // g
|
||||
m_red = m // g
|
||||
|
||||
a_inv = mod_inverse(a_red, m_red)
|
||||
x0 = (b_red * a_inv) % m_red
|
||||
|
||||
return (x0, m_red, g)
|
||||
|
||||
def solve_system_congruences(equations):
|
||||
"""
|
||||
Solve a system of linear congruences given by:
|
||||
equations = [(A1, B1, M1), (A2, B2, M2), ...]
|
||||
meaning A_i * x ≡ B_i (mod M_i).
|
||||
|
||||
Returns: (solution, modulus) if a solution exists, otherwise None.
|
||||
"""
|
||||
moduli = []
|
||||
remainders = []
|
||||
|
||||
for (A, B, M) in equations:
|
||||
g = gcd(A, M)
|
||||
# Check if solution exists for this congruence
|
||||
if B % g != 0:
|
||||
return None # No solution
|
||||
|
||||
# Reduce the congruence
|
||||
A_red = A // g
|
||||
B_red = B // g
|
||||
M_red = M // g
|
||||
|
||||
# Compute the inverse of A_red mod M_red
|
||||
A_inv = mod_inverse(A_red, M_red)
|
||||
# Compute a particular solution x0
|
||||
x0 = (B_red * A_inv) % M_red
|
||||
|
||||
moduli.append(M_red)
|
||||
remainders.append(x0)
|
||||
|
||||
# Now solve the standard form system x ≡ remainders[i] (mod moduli[i])
|
||||
solution, modulus = crt(moduli, remainders)
|
||||
return (solution, modulus)
|
||||
|
||||
def graph_properties_all(n, m=None):
|
||||
"""
|
||||
Calculates the number of edges and vertices for multiple standard graph types.
|
||||
|
||||
Parameters:
|
||||
n (int): A parameter related to the graph type (e.g., vertices or dimension for cube).
|
||||
m (int, optional): For bipartite graphs, the size of the second partition.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary of all graph types with their properties or a message if not applicable.
|
||||
"""
|
||||
results = {}
|
||||
|
||||
# Cube graph (n-dimensional hypercube)
|
||||
try:
|
||||
vertices = 2**n
|
||||
edges = n * 2**(n-1)
|
||||
results["Cube Graph"] = {"Vertices": vertices, "Edges": edges}
|
||||
except Exception:
|
||||
results["Cube Graph"] = "Not defined for n = {}".format(n)
|
||||
|
||||
# Complete graph
|
||||
try:
|
||||
vertices = n
|
||||
edges = n * (n - 1) // 2
|
||||
results["Complete Graph"] = {"Vertices": vertices, "Edges": edges}
|
||||
except Exception:
|
||||
results["Complete Graph"] = "Not defined for n = {}".format(n)
|
||||
|
||||
# Bipartite graph K(m, n)
|
||||
try:
|
||||
if m is not None:
|
||||
vertices = n + m
|
||||
edges = n * m
|
||||
results["Bipartite Graph"] = {"Vertices": vertices, "Edges": edges}
|
||||
else:
|
||||
results["Bipartite Graph"] = "Requires both partitions (n and m)."
|
||||
except Exception:
|
||||
results["Bipartite Graph"] = "Not defined for n = {}, m = {}".format(n, m)
|
||||
|
||||
# Cycle graph
|
||||
try:
|
||||
vertices = n
|
||||
edges = n
|
||||
results["Cycle Graph"] = {"Vertices": vertices, "Edges": edges}
|
||||
except Exception:
|
||||
results["Cycle Graph"] = "Not defined for n = {}".format(n)
|
||||
|
||||
# Wheel graph
|
||||
try:
|
||||
vertices = n
|
||||
edges = 2 * (n - 1)
|
||||
results["Wheel Graph"] = {"Vertices": vertices, "Edges": edges}
|
||||
except Exception:
|
||||
results["Wheel Graph"] = "Not defined for n = {}".format(n)
|
||||
|
||||
return results
|
||||
113193
01017 - Discrete Mathematics/ipynb filer/samples.ipynb
Normal file
113193
01017 - Discrete Mathematics/ipynb filer/samples.ipynb
Normal file
File diff suppressed because one or more lines are too long
57
01017 - Discrete Mathematics/ipynb filer/test.py
Normal file
57
01017 - Discrete Mathematics/ipynb filer/test.py
Normal file
@@ -0,0 +1,57 @@
|
||||
from sympy import *
|
||||
|
||||
def check_injective_surjective(func, var, domain, codomain):
|
||||
x, y = symbols('x y')
|
||||
|
||||
# Check if the function is well-defined
|
||||
outputs = {}
|
||||
for val in domain:
|
||||
output = func.subs(var, val)
|
||||
if output in outputs:
|
||||
# If the same output occurs for different inputs, it's not well-defined
|
||||
if outputs[output] != val:
|
||||
return "The function is not well-defined."
|
||||
else:
|
||||
outputs[output] = val
|
||||
|
||||
# Check injectivity
|
||||
injective = True
|
||||
for val1 in domain:
|
||||
for val2 in domain:
|
||||
if val1 != val2:
|
||||
if func.subs(var, val1) == func.subs(var, val2):
|
||||
injective = False
|
||||
break
|
||||
|
||||
# Check surjectivity
|
||||
surjective = True
|
||||
for c_val in codomain:
|
||||
try:
|
||||
solutions = solve(Eq(func, c_val), var)
|
||||
if not any(s in domain for s in solutions):
|
||||
surjective = False
|
||||
break
|
||||
except:
|
||||
surjective = False
|
||||
break
|
||||
|
||||
# Results
|
||||
if injective and surjective:
|
||||
return "The function is bijective (both injective and surjective)."
|
||||
elif injective:
|
||||
return "The function is injective only."
|
||||
elif surjective:
|
||||
return "The function is surjective only."
|
||||
else:
|
||||
return "The function is neither injective nor surjective."
|
||||
|
||||
# Define the function and its domain/codomain
|
||||
x = symbols('x')
|
||||
func = Piecewise((2*x, x >= 0), (-2*x-1, x < 0))
|
||||
domain = range(-20, 20) # For example, integers from -20 to 20
|
||||
codomain = range(0, 40) # Adjusted codomain to include all possible outputs
|
||||
|
||||
result = check_injective_surjective(func, x, domain, codomain)
|
||||
print(result)
|
||||
|
||||
print("please double check it yourself")
|
||||
524
01017 - Discrete Mathematics/ipynb filer/tools.py
Normal file
524
01017 - Discrete Mathematics/ipynb filer/tools.py
Normal file
@@ -0,0 +1,524 @@
|
||||
import re
|
||||
from itertools import permutations, product, chain, combinations
|
||||
import math
|
||||
import numpy as np
|
||||
from sympy import mod_inverse
|
||||
#import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
|
||||
|
||||
def is_prime(n):
|
||||
if n <= 1:
|
||||
return False
|
||||
|
||||
for i in range(2, int(n**0.5) + 1):
|
||||
|
||||
if n % i == 0:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def primes_below(n):
|
||||
primes = [i for i in range(2, n) if is_prime(i)]
|
||||
return f"Number of primes below {n} is {len(primes)} and the list is {primes}"
|
||||
|
||||
def divide_with_remainder(a, b):
|
||||
if b == 0:
|
||||
return "Division by zero is undefined."
|
||||
|
||||
quotient = a // b
|
||||
remainder = a % b
|
||||
return f"The quotient of {a} divided by {b} is {quotient}, and the remainder is {remainder}."
|
||||
|
||||
|
||||
# sent by jesper TA<3
|
||||
def gcd(a, b):
|
||||
rlist = [a, b]
|
||||
qlist = []
|
||||
|
||||
while True:
|
||||
r1 = rlist[-2]
|
||||
r2 = rlist[-1]
|
||||
if r2 == 0:
|
||||
break
|
||||
new_r = r1 % r2
|
||||
qlist.append(r1 // r2)
|
||||
rlist.append(new_r)
|
||||
|
||||
slist = [1, 0]
|
||||
tlist = [0, 1]
|
||||
|
||||
for q in qlist:
|
||||
s1 = slist[-2]
|
||||
s2 = slist[-1]
|
||||
t1 = tlist[-2]
|
||||
t2 = tlist[-1]
|
||||
|
||||
slist.append(s1 - q * s2)
|
||||
tlist.append(t1 - q * t2)
|
||||
|
||||
i = 0
|
||||
print('i \t r_i \t r_i+1 \t q_i+1 \t r_i+2 \t s_i \t t_i')
|
||||
for r1, r2, r3, q, s, t in zip(rlist, rlist[1:], rlist[2:], qlist, slist, tlist):
|
||||
print(f'{i} \t {r1} \t {r2} \t {q} \t {r3} \t {s} \t {t}')
|
||||
i += 1
|
||||
print(f'\t\t\t\t\t {slist[-2]} \t {tlist[-2]}')
|
||||
|
||||
gcd_value = rlist[-2]
|
||||
s_coeff = slist[-2]
|
||||
t_coeff = tlist[-2]
|
||||
result_string = f"GCD({a}, {b}) = {gcd_value}, with coefficients {s_coeff} and {t_coeff} such that {gcd_value} = ({s_coeff})*{a} + ({t_coeff})*{b}"
|
||||
|
||||
print(f'{result_string}')
|
||||
#return gcd_value, s_coeff, t_coeff, result_string
|
||||
|
||||
def lcm(a, b):
|
||||
def gcd(a, b):
|
||||
while b:
|
||||
a, b = b, a % b
|
||||
return a
|
||||
|
||||
gcd_value = gcd(a, b)
|
||||
lcm_value = abs(a * b) // gcd_value
|
||||
|
||||
result_string = (
|
||||
f"LCM({a}, {b}) = {lcm_value}, Here, GCD({a}, {b}) = {gcd_value}."
|
||||
)
|
||||
|
||||
print(result_string)
|
||||
#return lcm_value, result_string
|
||||
|
||||
|
||||
|
||||
# Sent by Alexander Piepgrass <3
|
||||
def _min_gcd_congruences(a,b):
|
||||
rlist = [a,b]
|
||||
qlist = []
|
||||
|
||||
while True:
|
||||
r1 = rlist[-2]
|
||||
r2 = rlist[-1]
|
||||
if r2==0:
|
||||
break
|
||||
new_r = r1%r2
|
||||
qlist.append(r1//r2)
|
||||
rlist.append(new_r)
|
||||
|
||||
slist = [1,0]
|
||||
tlist = [0,1]
|
||||
|
||||
for q in qlist:
|
||||
s1 = slist[-2]
|
||||
s2 = slist[-1]
|
||||
t1 = tlist[-2]
|
||||
t2 = tlist[-1]
|
||||
|
||||
slist.append(s1-q*s2)
|
||||
tlist.append(t1-q*t2)
|
||||
|
||||
i = 0
|
||||
|
||||
return rlist[-2], slist[-2], tlist[-2]
|
||||
|
||||
# sent by alexander piepgrass <3
|
||||
def congruences_system_solver(system):
|
||||
m=1
|
||||
for cong in system:
|
||||
m*=cong[1]
|
||||
M_list = []
|
||||
for cong in system:
|
||||
M_list.append(m//cong[1])
|
||||
y_list=[]
|
||||
|
||||
for i in range(len(M_list)):
|
||||
r,s,t= _min_gcd_congruences(M_list[i],system[i][1])
|
||||
y_list.append(s)
|
||||
|
||||
x=0
|
||||
|
||||
for i in range(len(M_list)):
|
||||
x+=system[i][0]*M_list[i]*y_list[i]
|
||||
print(f'all solutions are {x % m} + {m}k')
|
||||
return x % m, m, M_list, y_list
|
||||
|
||||
def some_congruences_system_solver(system):
|
||||
normalized_system = []
|
||||
for b, a, n in system:
|
||||
g = math.gcd(b, n)
|
||||
if a % g != 0:
|
||||
raise ValueError(f"No solution exists for {b}*x ≡ {a} (mod {n})")
|
||||
# Reduce b*x ≡ a (mod n) to x ≡ c (mod m)
|
||||
b = b // g
|
||||
a = a // g
|
||||
n = n // g
|
||||
b_inv = mod_inverse(b, n)
|
||||
c = (b_inv * a) % n
|
||||
normalized_system.append((c, n))
|
||||
|
||||
# Solve the normalized system of congruences
|
||||
m = 1
|
||||
for _, n in normalized_system:
|
||||
m *= n
|
||||
M_list = []
|
||||
for _, n in normalized_system:
|
||||
M_list.append(m // n)
|
||||
y_list = []
|
||||
for i in range(len(M_list)):
|
||||
r, s, t = _min_gcd_congruences(M_list[i], normalized_system[i][1])
|
||||
y_list.append(s)
|
||||
|
||||
x = 0
|
||||
for i in range(len(M_list)):
|
||||
x += normalized_system[i][0] * M_list[i] * y_list[i]
|
||||
|
||||
print(f'All solutions are {x % m} + {m}k')
|
||||
return x % m, m, M_list, y_list
|
||||
|
||||
def solve_congruence_general(a, c, m):
|
||||
"""
|
||||
Solves the congruence ax ≡ c (mod m).
|
||||
Returns a general solution in the form x ≡ x0 + k*b (mod m),
|
||||
or 'No solution' if no solution exists.
|
||||
"""
|
||||
from math import gcd
|
||||
|
||||
# Step 1: Compute gcd(a, m)
|
||||
g = gcd(a, m)
|
||||
|
||||
# Step 2: Check if a solution exists
|
||||
if c % g != 0:
|
||||
return "No solution"
|
||||
|
||||
# Step 3: Simplify the congruence
|
||||
a, c, m = a // g, c // g, m // g
|
||||
|
||||
# Step 4: Find the modular inverse of a modulo m
|
||||
def extended_gcd(a, b):
|
||||
"""Helper function to compute the extended GCD."""
|
||||
if b == 0:
|
||||
return a, 1, 0
|
||||
g, x, y = extended_gcd(b, a % b)
|
||||
return g, y, x - (a // b) * y
|
||||
|
||||
g, x, _ = extended_gcd(a, m)
|
||||
if g != 1: # Sanity check for modular inverse
|
||||
return "No solution"
|
||||
|
||||
x = (x % m + m) % m # Ensure x is positive
|
||||
x0 = (c * x) % m # Particular solution
|
||||
|
||||
# General solution is x ≡ x0 + k * m
|
||||
return f"x ≡ {x0} + k * {m}"
|
||||
|
||||
|
||||
|
||||
def explain_quantifiers(logic_string):
|
||||
"""
|
||||
Converts a LaTeX-style logical string into a human-readable explanation.
|
||||
Supports various quantifiers, logical types, and biimplication.
|
||||
"""
|
||||
# Normalize LaTeX equivalents to symbols
|
||||
latex_to_symbol_map = {
|
||||
r"\\forall": "∀",
|
||||
r"\\exists": "∃",
|
||||
r"\\in": "∈",
|
||||
r"\\notin": "∉",
|
||||
r"\\mathbb\{R\}": "ℝ",
|
||||
r"\\neq": "≠",
|
||||
r"\\rightarrow": "→",
|
||||
r"\\leftrightarrow": "↔",
|
||||
r"\\lor": "∨",
|
||||
r"\\land": "∧",
|
||||
r"\\neg": "¬",
|
||||
r"\\leq": "≤",
|
||||
r"\\geq": "≥",
|
||||
r"\\subseteq": "⊆",
|
||||
r"\\supseteq": "⊇",
|
||||
r"\\subset": "⊂",
|
||||
r"\\supset": "⊃",
|
||||
r"\\emptyset": "∅",
|
||||
}
|
||||
|
||||
for latex, symbol in latex_to_symbol_map.items():
|
||||
logic_string = re.sub(latex, symbol, logic_string)
|
||||
|
||||
# Dictionary to map symbols to words
|
||||
symbol_map = {
|
||||
"∀": "For all",
|
||||
"∃": "There exists",
|
||||
"∈": "in",
|
||||
"∉": "not in",
|
||||
"ℝ": "the set of all real numbers",
|
||||
"→": "implies that",
|
||||
"↔": "if and only if",
|
||||
"∨": "or",
|
||||
"∧": "and",
|
||||
"¬": "not",
|
||||
"=": "is equal to",
|
||||
"≠": "is not equal to",
|
||||
"<": "is less than",
|
||||
">": "is greater than",
|
||||
"≤": "is less than or equal to",
|
||||
"≥": "is greater than or equal to",
|
||||
"⊆": "is a subset of",
|
||||
"⊇": "is a superset of",
|
||||
"⊂": "is a proper subset of",
|
||||
"⊃": "is a proper superset of",
|
||||
"∅": "the empty set",
|
||||
}
|
||||
|
||||
# Replace symbols with words
|
||||
for symbol, word in symbol_map.items():
|
||||
logic_string = logic_string.replace(symbol, word)
|
||||
|
||||
# Custom processing for specific patterns
|
||||
# Match quantifiers and variables
|
||||
logic_string = re.sub(r"For all (\w) in (.*?),", r"Given any \1 in \2,", logic_string)
|
||||
logic_string = re.sub(r"There exists (\w) in (.*?),", r"There is a \1 in \2,", logic_string)
|
||||
|
||||
# Handle logical groupings with parentheses
|
||||
logic_string = re.sub(r"\((.*?)\)", r"where \1", logic_string)
|
||||
|
||||
# Ensure precise formatting
|
||||
logic_string = logic_string.strip()
|
||||
return logic_string
|
||||
|
||||
|
||||
def get_permutations(input_string):
|
||||
"""
|
||||
Returns all permutations of the given string.
|
||||
"""
|
||||
# Generate permutations using itertools.permutations
|
||||
perm = permutations(input_string)
|
||||
# Convert to a list of strings
|
||||
perm_list = [''.join(p) for p in perm]
|
||||
return perm_list
|
||||
|
||||
def get_r_permutations(input_string, r):
|
||||
"""
|
||||
Returns all r-permutations of the given string.
|
||||
|
||||
Parameters:
|
||||
input_string (str): The string to generate permutations from.
|
||||
r (int): The length of the permutations.
|
||||
|
||||
Returns:
|
||||
list: A list of all r-permutations as strings.
|
||||
"""
|
||||
# Generate r-permutations using itertools.permutations
|
||||
r_perm = permutations(input_string, r)
|
||||
# Convert to a list of strings
|
||||
r_perm_list = [''.join(p) for p in r_perm]
|
||||
return r_perm_list
|
||||
|
||||
|
||||
|
||||
def get_binary_strings(n, as_strings=False):
|
||||
# Generate all possible bit strings of length n
|
||||
bit_combinations = product([0, 1], repeat=n)
|
||||
if as_strings:
|
||||
# Join bits as strings
|
||||
return ["".join(map(str, bits)) for bits in bit_combinations]
|
||||
else:
|
||||
# Return as lists of integers
|
||||
return [list(bits) for bits in bit_combinations]
|
||||
|
||||
def get_combinations(input_string):
|
||||
"""
|
||||
Returns all combinations of the given string (for all lengths).
|
||||
|
||||
Parameters:
|
||||
input_string (str): The string to generate combinations from.
|
||||
|
||||
Returns:
|
||||
list: A list of all combinations as strings.
|
||||
"""
|
||||
comb_list = []
|
||||
for r in range(1, len(input_string) + 1):
|
||||
comb_list.extend([''.join(c) for c in combinations(input_string, r)])
|
||||
return comb_list
|
||||
|
||||
def get_r_combinations(input_string, r):
|
||||
"""
|
||||
Returns all r-combinations of the given string.
|
||||
|
||||
Parameters:
|
||||
input_string (str): The string to generate combinations from.
|
||||
r (int): The length of the combinations.
|
||||
|
||||
Returns:
|
||||
list: A list of all r-combinations as strings.
|
||||
"""
|
||||
r_comb = combinations(input_string, r)
|
||||
r_comb_list = [''.join(c) for c in r_comb]
|
||||
return r_comb_list
|
||||
|
||||
|
||||
def calculate_number_of_derangements(n):
|
||||
|
||||
"""
|
||||
|
||||
Calculate the number of derangements (Dn) for n elements
|
||||
|
||||
using the formula:
|
||||
|
||||
Dn = n! * (1 - 1/1! + 1/2! - 1/3! + ... + (-1)^n/n!)
|
||||
|
||||
"""
|
||||
|
||||
result = 0
|
||||
|
||||
for i in range(n + 1):
|
||||
|
||||
result += ((-1)**i) / math.factorial(i)
|
||||
|
||||
return round(math.factorial(n) * result)
|
||||
|
||||
def is_derangement(original, perm):
|
||||
"""
|
||||
Checks if a permutation is a derangement of the original string.
|
||||
"""
|
||||
return all(original[i] != perm[i] for i in range(len(original)))
|
||||
|
||||
def get_derangements(input_string):
|
||||
"""
|
||||
Returns all derangements of a given string as an array of strings.
|
||||
"""
|
||||
original = list(input_string)
|
||||
all_permutations = permutations(original)
|
||||
derangements = ["".join(perm) for perm in all_permutations if is_derangement(original, perm)]
|
||||
return derangements
|
||||
|
||||
|
||||
def multiplicative_inverse(n, mod):
|
||||
def gcd_extended(a, b):
|
||||
if a == 0:
|
||||
return b, 0, 1
|
||||
gcd, x1, y1 = gcd_extended(b % a, a)
|
||||
x = y1 - (b // a) * x1
|
||||
y = x1
|
||||
return gcd, x, y
|
||||
|
||||
gcd, x, _ = gcd_extended(n, mod)
|
||||
|
||||
if gcd != 1: # If gcd of n and mod is not 1, inverse doesn't exist
|
||||
return "Does not exist"
|
||||
else:
|
||||
# Make the result positive
|
||||
return x % mod
|
||||
|
||||
|
||||
def minimum_selections_for_sum(numbers, target_sum):
|
||||
selected_numbers = set()
|
||||
|
||||
for num in numbers:
|
||||
if target_sum - num in selected_numbers:
|
||||
# Pair found
|
||||
return len(selected_numbers) + 1
|
||||
|
||||
selected_numbers.add(num)
|
||||
|
||||
# No pair found within the set
|
||||
return None
|
||||
|
||||
|
||||
def is_transitive(R):
|
||||
for a, b in R:
|
||||
for c, d in R:
|
||||
if b == c and ((a, d) not in R):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def is_reflexive(S, R):
|
||||
newSet = {(a, b) for a in S for b in S if a == b}
|
||||
if R >= newSet:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def is_symmetric(R):
|
||||
if all(tup[::-1] in R for tup in R):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def is_antisymmetric(R):
|
||||
return all((y, x) not in R for x, y in R if x != y)
|
||||
|
||||
|
||||
def is_equivalence_relation(S, R):
|
||||
return is_symmetric(R) and is_reflexive(S, R) and is_transitive(R)
|
||||
|
||||
|
||||
def is_partial_order(S, R):
|
||||
"""Check if the relation R on set S is a partial order."""
|
||||
return is_antisymmetric(R) and is_reflexive(S, R) and is_transitive(R)
|
||||
|
||||
|
||||
def check_func(func_to_check, domain, codomain):
|
||||
"""
|
||||
Check if a function is "well-defined" over a given domain and codomain constraint.
|
||||
|
||||
Parameters:
|
||||
func_to_check: callable
|
||||
The function to check. It should take one argument.
|
||||
domain: list
|
||||
A list of values to test the function with.
|
||||
codomain: callable
|
||||
A callable that takes the output of the function and returns True if it satisfies the codomain constraint.
|
||||
|
||||
Returns:
|
||||
bool
|
||||
True if the function is well-defined over the domain and codomain, otherwise False.
|
||||
"""
|
||||
well_defined = True
|
||||
|
||||
for x in domain:
|
||||
try:
|
||||
# Evaluate the function
|
||||
output = func_to_check(x)
|
||||
|
||||
# Check the codomain constraint
|
||||
if not codomain(output):
|
||||
print(f"Input {x}: Output {output} is INVALID.")
|
||||
well_defined = False
|
||||
except Exception as e:
|
||||
# Catch errors in evaluation
|
||||
print(f"Input {x}: Error occurred - {str(e)}.")
|
||||
well_defined = False
|
||||
|
||||
if well_defined:
|
||||
print("The function is well-defined over the given domain.")
|
||||
else:
|
||||
print("The function is NOT well-defined over the given domain.")
|
||||
|
||||
return well_defined
|
||||
|
||||
|
||||
|
||||
def plot_function(functions: list, plot_range: list):
|
||||
"""Takes a function and plots the graph using the plot_range.
|
||||
The plot_rage should be a list containing two elements: the minimum value to plot, up to the max value.
|
||||
function should be a list of functions to be drawn. The functions in the list should take one parameter and return a value.
|
||||
"""
|
||||
x_values = range(plot_range[0],plot_range[1])
|
||||
for func in functions:
|
||||
y_points = []
|
||||
x_points = []
|
||||
for i in range(plot_range[0], plot_range[1]):
|
||||
y_points.append(func(i))
|
||||
x_points.append(i)
|
||||
plt.plot(x_points, y_points, label=func.__name__)
|
||||
plt.xlabel('x')
|
||||
plt.ylabel('y')
|
||||
plt.title('Function Plots')
|
||||
plt.legend()
|
||||
plt.grid(True)
|
||||
plt.show()
|
||||
|
||||
print(lcm(82,21))
|
||||
print(lcm(42,123))
|
||||
Reference in New Issue
Block a user