Files
2026-01-21 04:46:32 +00:00

380 lines
8.8 KiB
Python

import random
from .autonode import node_wrapper, get_node_names_mappings, validate, anytype
classes = []
node = node_wrapper(classes)
import math
@node
class MinNode:
"""
Returns the minimum of two values
"""
RETURN_TYPES = (anytype,)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": (anytype,),
"input2": (anytype,),
}
}
FUNCTION = "min"
CATEGORY = "Math"
custom_name = "Min"
def min(self, input1, input2):
return (min(input1, input2),)
@node
class MaxNode:
"""
Returns the maximum of two values
"""
RETURN_TYPES = (anytype,)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": (anytype,),
"input2": (anytype,),
}
}
FUNCTION = "max"
CATEGORY = "Math"
custom_name = "Max"
def max(self, input1, input2):
return (max(input1, input2),)
@node
class RoundNode:
"""
Rounds a value to the nearest integer
"""
RETURN_TYPES = ("INT",)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": (anytype,),
}
}
FUNCTION = "round"
CATEGORY = "Math"
custom_name = "Round"
def round(self, input1):
return (round(input1),)
@node
class AbsNode:
"""
Returns the absolute value of a number
"""
RETURN_TYPES = (anytype,)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": (anytype,),
}
}
FUNCTION = "abs"
CATEGORY = "Math"
custom_name = "Abs"
def abs(self, input1):
return (abs(input1),)
@node
class FloorNode:
"""
Returns the floor of a number
"""
RETURN_TYPES = ("INT",)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": (anytype,),
}
}
FUNCTION = "floor"
CATEGORY = "Math"
custom_name = "Floor"
def floor(self, input1):
return (math.floor(input1),)
@node
class CeilNode:
"""
Returns the ceiling of a number
"""
RETURN_TYPES = ("INT",)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": (anytype,),
}
}
FUNCTION = "ceil"
CATEGORY = "Math"
custom_name = "Ceil"
def ceil(self, input1):
return (math.ceil(input1),)
@node
class PowerNode:
"""
Returns the power of a number
"""
RETURN_TYPES = (anytype,)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": (anytype,),
"power": (anytype,),
}
}
FUNCTION = "power"
CATEGORY = "Math"
custom_name = "Power"
def power(self, input1, power):
abs_input = abs(input1)
# fast paths for values that won't overflow digit-wise
if abs_input == 0:
if power < 0:
raise ZeroDivisionError("0 cannot be raised to a negative power")
return (math.pow(input1, power),)
if abs_input == 1:
return (math.pow(input1, power),)
# validate power with log10 scale, prevent huge magnitudes
log10_abs = math.log10(abs_input)
if (log10_abs * power) > 100:
raise OverflowError("Power is too large, exceeds 100 digits")
return (math.pow(input1, power),)
@node
class SigmoidNode:
"""
Returns the sigmoid of a number
"""
RETURN_TYPES = ("FLOAT",)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": ("FLOAT",),
}
}
FUNCTION = "sigmoid"
CATEGORY = "Math"
custom_name = "Sigmoid"
def sigmoid(self, input1):
return (1 / (1 + math.exp(-input1)),)
def is_prime_small(n: int) -> bool:
"""
Deterministic check for primality for smaller n.
Skips multiples of 2 and 3, then checks i, i+2, i+4 up to sqrt(n).
"""
if n < 2:
return False
if n in (2, 3):
return True
if n % 2 == 0 or n % 3 == 0:
return n == 2 or n == 3
# 6k ± 1 optimization
limit = int(math.isqrt(n)) # integer sqrt
i = 5
while i <= limit:
if n % i == 0 or n % (i + 2) == 0:
return False
i += 6
return True
def miller_rabin_test(d: int, n: int) -> bool:
""" One round of the Miller-Rabin test with a random base 'a'. """
a = random.randrange(2, n - 1)
x = pow(a, d, n) # a^d % n
if x == 1 or x == n - 1:
return True
# Keep squaring x while d does not reach n-1
while d != n - 1:
x = (x * x) % n
d <<= 1 # d *= 2
if x == 1:
return False
if x == n - 1:
return True
return False
def is_prime_miller_rabin(n: int, k: int = 5) -> bool:
"""
Miller-Rabin primality test with k rounds (probabilistic).
Good enough for big integers in practice.
"""
# Handle small or trivial cases
if n < 2:
return False
# check small primes quickly
for small_prime in [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]:
if n == small_prime:
return True
if n % small_prime == 0 and n != small_prime:
return False
# Write n - 1 as d * 2^r
d = n - 1
while d % 2 == 0:
d //= 2
# Witness loop
for _ in range(k):
if not miller_rabin_test(d, n):
return False
return True
@node
class IsPrimeNode:
"""
Checks if an integer is prime.
- If the integer |value| < threshold, uses a deterministic small-check (trial division).
- Otherwise, uses a Miller-Rabin pseudoprime test for a faster check (probabilistic).
Returns a BOOLEAN (True if prime, False if composite).
"""
FUNCTION = "is_prime"
RETURN_TYPES = ("BOOLEAN",)
CATEGORY = "Math"
custom_name = "Is Prime?"
@staticmethod
def is_prime(value: int, threshold: int = 10_000_000, miller_rabin_rounds: int = 5):
# handle negative or zero
if value < 2:
return (False,)
if value < threshold:
# use small prime check
return (is_prime_small(value),)
else:
# use Miller-Rabin
return (is_prime_miller_rabin(value, k=miller_rabin_rounds),)
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("INT", {"default": 1, "min": -9999999999, "max": 9999999999, "step": 1}),
},
"optional": {
"threshold": ("INT", {"default": 10_000_000, "min": 1, "max": 9999999999, "step": 1}),
"miller_rabin_rounds": ("INT", {"default": 5, "min": 1, "max": 50, "step": 1}),
}
}
@node
class RAMPNode:
"""
Returns the ramp of a number
"""
RETURN_TYPES = ("FLOAT",)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": ("FLOAT",),
}
}
FUNCTION = "ramp"
CATEGORY = "Math"
custom_name = "RAMP"
def ramp(self, input1):
return (max(0, input1),)
@node
class ModuloNode:
"""
Returns the modulo of a number
"""
RETURN_TYPES = ("INT",)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": ("INT",),
"modulo": ("INT",),
}
}
FUNCTION = "modulo"
CATEGORY = "Math"
custom_name = "Modulo"
def modulo(self, input1, modulo):
return (input1 % modulo,)
@node
class LogNode:
"""
Returns the log of a number
"""
RETURN_TYPES = ("FLOAT",)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": ("FLOAT",),
"base": ("FLOAT",),
}
}
FUNCTION = "log"
CATEGORY = "Math"
custom_name = "Log"
def log(self, input1, base):
return (math.log(input1, base),)
@node
class MultiplyNode:
"""
Returns the product of two numbers
"""
RETURN_TYPES = (anytype,)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": (anytype,),
"input2": (anytype,),
}
}
FUNCTION = "multiply"
CATEGORY = "Math"
custom_name = "Multiply"
def multiply(self, input1, input2):
return (input1 * input2,)
@node
class DivideNode:
"""
Returns the quotient of two numbers
"""
RETURN_TYPES = ("FLOAT",)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"input1": (anytype,),
"input2": (anytype,),
}
}
FUNCTION = "divide"
CATEGORY = "Math"
custom_name = "Divide"
def divide(self, input1, input2):
if input2 == 0:
raise ZeroDivisionError("Cannot divide by zero")
return (input1 / input2,)
validate(classes)
CLASS_MAPPINGS, CLASS_NAMES = get_node_names_mappings(classes)