Files
mcDandy-more_math/more_math/Parser/FloatEvalVisitor.py
T
mcDandy e44fd922d4 added map,conv and permute
map - maps points based on equations
conv - allows running convolution filter
permute - switches dimension position
2025-12-26 18:42:47 +01:00

213 lines
8.1 KiB
Python

import math
from .MathExprVisitor import MathExprVisitor
class FloatEvalVisitor(MathExprVisitor):
def __init__(self, variables):
self.variables = variables
def visitNumberExp(self, ctx):
print("Visiting number expression:", ctx.getText())
return float(ctx.getText())
def visitConstantExp(self, ctx):
name = ctx.getText().lower()
if name == "pi":
return 3.141592653589793
if name == "e":
return 2.718281828459045
raise ValueError(f"Unknown constant: {name}")
def visitVariableExp(self, ctx):
name = ctx.getText()
if name not in self.variables:
raise ValueError(f"Variable '{name}' not found")
return self.variables[name]
def visitParenExp(self, ctx):
return self.visit(ctx.expr())
def visitUnaryPlus(self, ctx):
return +self.visit(ctx.unaryExpr())
def visitUnaryMinus(self, ctx):
return -self.visit(ctx.unaryExpr())
def visitAddExp(self, ctx):
return self.visit(ctx.addExpr()) + self.visit(ctx.mulExpr())
def visitSubExp(self, ctx):
return self.visit(ctx.addExpr()) - self.visit(ctx.mulExpr())
def visitMulExp(self, ctx):
print("Visiting multiplication expression:", ctx.getText())
if ctx.mulExpr() is None or ctx.powExpr() is None:
raise ValueError("Invalid multiplication expression")
return self.visit(ctx.mulExpr()) * self.visit(ctx.powExpr())
def visitDivExp(self, ctx):
return self.visit(ctx.mulExpr()) / self.visit(ctx.powExpr())
def visitModExp(self, ctx):
return self.visit(ctx.mulExpr()) % self.visit(ctx.powExpr())
def visitPowExp(self, ctx):
return math.pow(self.visit(ctx.unaryExpr()), self.visit(ctx.powExpr()))
def visitNeExp(self, ctx):
return float(self.visit(ctx.compExpr()) != self.visit(ctx.addExpr()))
def visitEqExp(self, ctx):
return float(self.visit(ctx.compExpr()) == self.visit(ctx.addExpr()))
def visitGtExp(self, ctx):
return float(self.visit(ctx.compExpr()) > self.visit(ctx.addExpr()))
def visitLtExp(self, ctx):
return float(self.visit(ctx.compExpr()) < self.visit(ctx.addExpr()))
def visitGeExp(self, ctx):
return float(self.visit(ctx.compExpr()) >= self.visit(ctx.addExpr()))
def visitLeExp(self, ctx):
return float(self.visit(ctx.compExpr()) <= self.visit(ctx.addExpr()))
def visitToUnary(self, ctx):
return self.visit(ctx.unaryExpr())
def visitToPow(self, ctx):
return self.visit(ctx.powExpr())
def visitToMul(self, ctx):
return self.visit(ctx.mulExpr())
def visitToAdd(self, ctx):
return self.visit(ctx.addExpr())
def visitToGt(self, ctx):
return self.visit(ctx.gtExpr())
def visitToLt(self, ctx):
return self.visit(ctx.ltExpr())
def visitToEq(self, ctx):
return self.visit(ctx.eqExpr())
def visitToNeq(self, ctx):
return self.visit(ctx.neqExpr())
def visitToGe(self, ctx):
return self.visit(ctx.gteExpr())
def visitToLe(self, ctx):
return self.visit(ctx.lteExpr())
# Single-argument functions
def visitSinFunc(self, ctx): return math.sin(self.visit(ctx.expr()))
def visitCosFunc(self, ctx): return math.cos(self.visit(ctx.expr()))
def visitTanFunc(self, ctx): return math.tan(self.visit(ctx.expr()))
def visitAsinFunc(self, ctx): return math.asin(self.visit(ctx.expr()))
def visitAcosFunc(self, ctx): return math.acos(self.visit(ctx.expr()))
def visitAtanFunc(self, ctx): return math.atan(self.visit(ctx.expr()))
def visitSinhFunc(self, ctx): return math.sinh(self.visit(ctx.expr()))
def visitCoshFunc(self, ctx): return math.cosh(self.visit(ctx.expr()))
def visitTanhFunc(self, ctx): return math.tanh(self.visit(ctx.expr()))
def visitAsinhFunc(self, ctx): return math.asinh(self.visit(ctx.expr()))
def visitAcoshFunc(self, ctx): return math.acosh(self.visit(ctx.expr()))
def visitAtanhFunc(self, ctx): return math.atanh(self.visit(ctx.expr()))
def visitAbsFunc(self, ctx): return abs(self.visit(ctx.expr()))
def visitAbsExp(self, ctx): return abs(self.visit(ctx.expr()))
def visitListExp(self, ctx): return self.visit(ctx.expr(0))
def visitSqrtFunc(self, ctx): return math.sqrt(self.visit(ctx.expr()))
def visitLnFunc(self, ctx): return math.log(self.visit(ctx.expr()))
def visitLogFunc(self, ctx): return math.log10(self.visit(ctx.expr()))
def visitExpFunc(self, ctx): return math.exp(self.visit(ctx.expr()))
def visitNormFunc(self, ctx):
vals = self.visit(ctx.expr())
if isinstance(vals, (list, tuple)):
return math.sqrt(sum(x**2 for x in vals) / len(vals))
return abs(vals)
def visitFloorFunc(self, ctx): return math.floor(self.visit(ctx.expr()))
def visitFractFunc(self, ctx):
val = self.visit(ctx.expr())
return val - math.floor(val)
def visitSigmoidFunc(self, ctx): return 1/(1+math.exp(-self.visit(ctx.expr())))
def visitReluFunc(self, ctx): return max(0.0, self.visit(ctx.expr()))
def visitSoftplusFunc(self, ctx):
# log(1 + exp(x))
x = self.visit(ctx.expr())
# stability check? math.log1p(math.exp(x)) is better but might overflow for large x
if x > 20: return x
return math.log(1 + math.exp(x))
def visitGeluFunc(self, ctx):
# 0.5 * x * (1 + erf(x / sqrt(2)))
x = self.visit(ctx.expr())
return 0.5 * x * (1 + math.erf(x / 1.4142135623730951))
def visitSignFunc(self, ctx):
x = self.visit(ctx.expr())
return math.copysign(1.0, x) if x != 0 else 0.0
def visitCeilFunc(self, ctx): return math.ceil(self.visit(ctx.expr()))
def visitRoundFunc(self, ctx): return round(self.visit(ctx.expr()))
def visitGammaFunc(self, ctx): return math.gamma(self.visit(ctx.expr())).exp()
def visitPrintFunc(self, ctx):
val = self.visit(ctx.expr())
print(val,end="\n")
return val
# Two-argument functions
def visitPowFunc(self, ctx):
return math.pow(self.visit(ctx.expr(0)), self.visit(ctx.expr(1)))
def visitAtan2Func(self, ctx):
return math.atan2(self.visit(ctx.expr(0)), self.visit(ctx.expr(1)))
def visitStepFunc(self, ctx):
x = self.visit(ctx.expr(0))
edge = self.visit(ctx.expr(1))
return 1.0 if x >= edge else 0.0
# N-argument functions
def visitSMinFunc(self, ctx):
args = [self.visit(e) for e in ctx.expr()]
return min(args)
def visitSMaxFunc(self, ctx):
args = [self.visit(e) for e in ctx.expr()]
return max(args)
def visitClampFunc(self, ctx):
x = self.visit(ctx.expr(0))
min_val = self.visit(ctx.expr(1))
max_val = self.visit(ctx.expr(2))
return max(min(x, max_val), min_val)
def visitLerpFunc(self, ctx):
# a + (b - a) * w
a = self.visit(ctx.expr(0))
b = self.visit(ctx.expr(1))
w = self.visit(ctx.expr(2))
return a + (b - a) * w
def visitSmoothstepFunc(self, ctx):
x = self.visit(ctx.expr(0))
edge0 = self.visit(ctx.expr(1))
edge1 = self.visit(ctx.expr(2))
# Scale, bias and saturate x to 0..1 range
t = (x - edge0) / (edge1 - edge0)
t = max(0.0, min(1.0, t))
# Evaluate polynomial
return t * t * (3.0 - 2.0 * t)
def visitFunc1Exp(self, ctx):
return self.visitChildren(ctx)
def visitFunc2Exp(self, ctx):
return self.visitChildren(ctx)
def visitFunc3Exp(self, ctx):
return self.visitChildren(ctx)
def visitFunc4Exp(self, ctx):
return self.visitChildren(ctx)
def visitMapFunc(self, ctx):
return self.visit(ctx.expr(0))
def visitConvFunc(self, ctx):
return self.visit(ctx.expr(0))
def visitFuncNExp(self, ctx):
return self.visitChildren(ctx)
def visitAtomExp(self, ctx):
return self.visitChildren(ctx)
def visitFunc2Expr(self, ctx):
return self.visit(ctx.getChild(0)) # forward to Atan2Func, PowFunc, etc.
def visitExpr(self, ctx):
return self.visitChildren(ctx)