Fix map function + add common variables

should have added them from beginning instead of giving custom names to them. Will not be deleting that.
This commit is contained in:
mcDandy
2025-12-27 17:58:13 +01:00
parent e44fd922d4
commit 458901bb2a
18 changed files with 860 additions and 743 deletions
+25 -5
View File
@@ -22,6 +22,7 @@ You can also get the node from comfy manager under the name of More math.
- Math: `+`, `-`, `*`, `/`, `%`, `^`, `||`
- Boolean: `<`, `<=`, `>`, `>=`, `==`, `!=`
(`false = 0.0`, `true = 1.0`)
- Lists: `[v1, v2, ...]` (Vector math supported, only usefull in `conv`)
## Functions
@@ -69,12 +70,22 @@ You can also get the node from comfy manager under the name of More math.
- `tmin(x, y)`: Element-wise minimum of x and y.
- `tmax(x, y)`: Element-wise maximum of x and y.
- `smin(x, y, ...)`: **Scalar** minimum. Returns the single smallest value across all input tensors/values.
- `smax(x, y, ...)`: **Scalar** maximum. Returns the single largest value across all input tensors/values.
- `smin(x, ...)`: **Scalar** minimum. Returns the single smallest value across all input tensors/values.
- `smax(x, ...)`: **Scalar** maximum. Returns the single largest value across all input tensors/values.
- `tnorm(x)`: **Tensor** Normalizes x (L2 norm along last dimension).
- `snorm(x)`: **Scalar** L2 norm of the entire tensor.
- `swap(tensor, dim, index1, index2)`: Swaps two slices of a tensor along a specified dimension. (Tensor only)
### Advanced Tensor Operations (Tensor Only)
- `map(tensor, c1, ...)`: Remaps `tensor` using source coordinates.
- Up to 3 coordinate mapping functions can be provided which map to the last (up to 3) dimensions of the tensor.
- If less than 3 functions are provided and shape of tensor > 3, the remaining dimensions are assumed to be identity functions.
- `conv(tensor, kw, [kh], [kd], k_expr)`: Applies a convolution to `tensor`.
- `k_expr` can be a math expression (using `kX`, `kY`, `kZ`) or a list literal.
- `permute(tensor, [dims])`: Rearranges the dimensions of the tensor. (e.g., `permute(a, [2, 3, 0, 1])`)
### FFT (Tensor Only)
- `fft(x)`: Fast Fourier Transform (Time to Frequency).
@@ -84,9 +95,13 @@ You can also get the node from comfy manager under the name of More math.
### Utility
- `print(x)`: Prints the value of x to the console and returns x.
- `print_shape(x)` or `pshp`: Prints the shape of x to the console and returns x.
## Variables
- **Common variables (except FLOAT, MODEL, VAE and CLIP)**:
- `D{N}` - position in n-th dimension of tensor (for example D0, D1, D2, ...)
- `S{N}` - size of n-th dimension of tensor (for example S0, S1, S2, ...)
- **common inputs** (matches node input type):
- `a`, `b`, `c`, `d`
- **Extra floats**:
@@ -103,8 +118,13 @@ You can also get the node from comfy manager under the name of More math.
- `W` or `width` - width of image. y/width = 1
- `H` or `height`- height of image. x/height = 1
- `B` or 'batch' - position in batch
- 'T' or 'batch_count` - number of batches
- `T` or `batch_count` - number of batches
- `N` or `channel_count` - count of channels
- **IMAGE KERNEL**:
- `kX`, `kY` - position in kernel. Centered at 0.0.
- `kW`, `kernel_width` - width of kernel.
- `kH`, `kernel_height` - height of kernel.
- `kD`, `kernel_depth` - depth of kernel.
- **AUDIO**:
- `B` or 'batch' - position in batch
@@ -124,6 +144,6 @@ You can also get the node from comfy manager under the name of More math.
- no additional variables
- `F` or `frequency_count` – frequency count (freq domain, iFFT only)
- `K` or `frequency` – isotropic frequency (Euclidean norm of indices, iFFT only)
- `Kx`, `Ky`, `K_dimN` - frequency index for specific dimension
- `Fx`, `Fy`, `F_dimN` - frequency count for specific dimension
- `Kx`, `Ky`, `Kz`, `Kw`,`Kv`, `Ku`, `K_dimN` - frequency index for specific dimension
- `Fx`, `Fy`, `Fz`, `Fw`,`Fv`,`Fu`, `F_dimN` - frequency count for specific dimension
- Constants: `e`, `pi`
+21 -20
View File
@@ -1,5 +1,5 @@
import torch
from .helper_functions import getIndexTensorAlongDim, comonLazy, eval_tensor_expr, make_zero_like
from .helper_functions import generate_dim_variables, getIndexTensorAlongDim, comonLazy, eval_tensor_expr, make_zero_like
from comfy_api.latest import io
@@ -9,12 +9,12 @@ from .MathNodeBase import MathNodeBase
class AudioMathNode(MathNodeBase):
"""
Enables math expressions on Audio tensors.
Inputs:
a, b, c, d: Audio inputs (b, c, d default to zero if not provided)
w, x, y, z: Float variables for expressions
AudioExpr: Expression to apply on audio tensors
Outputs:
AUDIO: Result of applying expression to input audio
"""
@@ -42,8 +42,8 @@ class AudioMathNode(MathNodeBase):
)
@classmethod
def execute(cls, a, AudioExpr, b=None, c=None, d=None, w=0.0, x=0.0, y=0.0, z=0.0):
waveform = a['waveform']
def execute(cls, AudioExpr, a, b=None, c=None, d=None, w=0.0, x=0.0, y=0.0, z=0.0):
av = a['waveform']
sample_rate = a['sample_rate']
a, b, c, d = cls.prepare_inputs(a, b, c, d)
@@ -51,22 +51,23 @@ class AudioMathNode(MathNodeBase):
bv, cv, dv = b['waveform'], c['waveform'], d['waveform']
variables = {
'a': waveform, 'b': bv, 'c': cv, 'd': dv,
'a': av, 'b': bv, 'c': cv, 'd': dv,
'w': w, 'x': x, 'y': y, 'z': z,
'B': getIndexTensorAlongDim(waveform, 0),
'C': getIndexTensorAlongDim(waveform, 1),
'S': getIndexTensorAlongDim(waveform, 2),
'R': torch.full_like(waveform, sample_rate, dtype=torch.float32),
'T': torch.full_like(waveform, waveform.shape[2], dtype=torch.float32),
'N': waveform.shape[1],
'batch': getIndexTensorAlongDim(waveform, 0),
'channel': getIndexTensorAlongDim(waveform, 1),
'sample': getIndexTensorAlongDim(waveform, 2),
'sample_rate': torch.full_like(waveform, sample_rate, dtype=torch.float32),
'sample_count': torch.full_like(waveform, waveform.shape[2], dtype=torch.float32),
'channel_count': waveform.shape[1],
}
'B': getIndexTensorAlongDim(av, 0),
'C': getIndexTensorAlongDim(av, 1),
'S': getIndexTensorAlongDim(av, 2),
'R': torch.full_like(av, sample_rate, dtype=torch.float32),
'T': torch.full_like(av, av.shape[2], dtype=torch.float32),
'N': av.shape[1],
'batch': getIndexTensorAlongDim(av, 0),
'channel': getIndexTensorAlongDim(av, 1),
'sample': getIndexTensorAlongDim(av, 2),
'sample_rate': torch.full_like(av, sample_rate, dtype=torch.float32),
'sample_count': torch.full_like(av, av.shape[2], dtype=torch.float32),
'channel_count': av.shape[1],
} | generate_dim_variables(av)
result_tensor = eval_tensor_expr(AudioExpr, variables, waveform.shape)
result_tensor = eval_tensor_expr(AudioExpr, variables, av.shape)
return ({'waveform': result_tensor, 'sample_rate': sample_rate},)
+7 -7
View File
@@ -1,7 +1,7 @@
from inspect import cleandoc
import torch
from .helper_functions import comonLazy, eval_tensor_expr, make_zero_like
from .helper_functions import comonLazy, eval_tensor_expr, generate_dim_variables, make_zero_like
from comfy_api.latest import io
@@ -11,17 +11,17 @@ from .MathNodeBase import MathNodeBase
class ConditioningMathNode(MathNodeBase):
"""
Enables math operations on conditionings.
Inputs:
a, b, c, d: Conditioning inputs (b, c, d default to zero if not provided)
w, x, y, z: Float variables for expressions
Tensor: Expression for the tensor part (describes image composition)
pooled_output: Expression for the pooled output (condensed representation)
Outputs:
CONDITIONING: Result of applying expressions to input conditionings
"""
@classmethod
def define_schema(cls) -> io.Schema:
return io.Schema(
@@ -60,9 +60,9 @@ class ConditioningMathNode(MathNodeBase):
# Extract tensors
ta, tb, tc, td = a[0][0], b[0][0], c[0][0], d[0][0]
# Evaluate tensor expression
variables = {'a': ta, 'b': tb, 'c': tc, 'd': td, 'w': w, 'x': x, 'y': y, 'z': z}
variables = {'a': ta, 'b': tb, 'c': tc, 'd': td, 'w': w, 'x': x, 'y': y, 'z': z} | generate_dim_variables(ta)
result_tensor = eval_tensor_expr(Tensor, variables, ta.shape)
# Evaluate pooled_output expression if available
@@ -71,7 +71,7 @@ class ConditioningMathNode(MathNodeBase):
pb = b[0][1].get("pooled_output")
pc = c[0][1].get("pooled_output")
pd = d[0][1].get("pooled_output")
variables = {'a': pa, 'b': pb, 'c': pc, 'd': pd, 'w': w, 'x': x, 'y': y, 'z': z}
variables = {'a': pa, 'b': pb, 'c': pc, 'd': pd, 'w': w, 'x': x, 'y': y, 'z': z} | generate_dim_variables(pa)
result_pooled = eval_tensor_expr(pooled_output, variables, pa.shape)
else:
result_pooled = None
+4 -11
View File
@@ -1,5 +1,5 @@
import torch
from .helper_functions import getIndexTensorAlongDim, comonLazy, eval_tensor_expr, make_zero_like
from .helper_functions import generate_dim_variables, getIndexTensorAlongDim, comonLazy, eval_tensor_expr, make_zero_like
from comfy_api.latest import io
@@ -9,12 +9,12 @@ from .MathNodeBase import MathNodeBase
class ImageMathNode(MathNodeBase):
"""
Enables math expressions on Images.
Inputs:
a, b, c, d: Image inputs (b, c, d default to zero if not provided)
w, x, y, z: Float variables for expressions
Image: Expression to apply on input images
Outputs:
IMAGE: Result of applying expression to input images
"""
@@ -45,11 +45,6 @@ class ImageMathNode(MathNodeBase):
def execute(cls, Image, a, b=None, c=None, d=None, w=0.0, x=0.0, y=0.0, z=0.0):
a, b, c, d = cls.prepare_inputs(a, b, c, d)
# Permute to B, C, H, W for processing
a = a.permute(0, 3, 1, 2)
b = b.permute(0, 3, 1, 2)
c = c.permute(0, 3, 1, 2)
d = d.permute(0, 3, 1, 2)
variables = {
'a': a, 'b': b, 'c': c, 'd': d,
@@ -62,10 +57,8 @@ class ImageMathNode(MathNodeBase):
'H': a.shape[2], 'height': a.shape[2],
'T': a.shape[0], 'batch_count': a.shape[0],
'N': a.shape[1], 'channel_count': a.shape[1],
}
} | generate_dim_variables(a)
result = eval_tensor_expr(Image, variables, a.shape)
# Permute back to B, H, W, C
result = result.permute(0, 2, 3, 1)
return (result,)
+2 -2
View File
@@ -4,7 +4,7 @@ from comfy_api.latest import io
import torch
from .helper_functions import getIndexTensorAlongDim, comonLazy, parse_expr, eval_tensor_expr_with_tree, make_zero_like
from .helper_functions import generate_dim_variables, getIndexTensorAlongDim, comonLazy, parse_expr, eval_tensor_expr_with_tree, make_zero_like
from .MathNodeBase import MathNodeBase
@@ -114,7 +114,7 @@ class LatentMathNode(MathNodeBase):
'H': height_val, 'height': height_val,
'T': frame_count, 'batch_count': batch_count,
'N': channel_count, 'channel_count': channel_count,
}
} | generate_dim_variables(a_t)
# expose time/frame if present
if time_dim is not None:
+2 -2
View File
@@ -2,7 +2,7 @@ from inspect import cleandoc
import torch
from .helper_functions import getIndexTensorAlongDim, comonLazy, parse_expr, eval_tensor_expr_with_tree, make_zero_like
from .helper_functions import generate_dim_variables, getIndexTensorAlongDim, comonLazy, parse_expr, eval_tensor_expr_with_tree, make_zero_like
from comfy_api.latest import io
@@ -183,7 +183,7 @@ class NoiseExecutor():
'I': merged_samples, 'T': frame_count, 'N': merged_samples.shape[channel_dim],
'batch': B, 'width': merged_samples.shape[width_dim], 'height': merged_samples.shape[height_dim], 'channel': C,
'batch_count': merged_samples.shape[0], 'channel_count': merged_samples.shape[1], 'input_latent': merged_samples,
}
} | generate_dim_variables(merged_samples)
if time_dim is not None:
F = getIndexTensorAlongDim(merged_samples, time_dim)
variables.update({'frame': F, 'frame_count': frame_count})
+4
View File
@@ -89,6 +89,8 @@ func1
| SOFTPLUS '(' expr ')' # SoftplusFunc
| GELU '(' expr ')' # GeluFunc
| SIGN '(' expr ')' # SignFunc
| PRINT_SHAPE_L '(' expr ')' # PrintShapeFunc
| PRINT_SHAPE '(' expr ')' # PrintShapeFunc
;
// Two-argument functions
@@ -156,6 +158,8 @@ SFFT : 'fft';
SIFFT : 'ifft';
ANGL : 'angle';
PRNT : 'print';
PRINT_SHAPE_L : 'print_shape';
PRINT_SHAPE : 'pshp';
LERP : 'lerp';
STEP : 'step';
SMOOTHSTEP : 'smoothstep';
File diff suppressed because one or more lines are too long
+58 -54
View File
@@ -38,35 +38,37 @@ SFFT=37
SIFFT=38
ANGL=39
PRNT=40
LERP=41
STEP=42
SMOOTHSTEP=43
FRACT=44
RELU=45
SOFTPLUS=46
GELU=47
SIGN=48
MAP=49
CONV=50
SWAP=51
PERM=52
PLUS=53
MINUS=54
MULT=55
DIV=56
MOD=57
POW=58
GE=59
GT=60
LE=61
LT=62
EQ=63
NE=64
PIPE=65
CONSTANT=66
NUMBER=67
VARIABLE=68
WS=69
PRINT_SHAPE_L=41
PRINT_SHAPE=42
LERP=43
STEP=44
SMOOTHSTEP=45
FRACT=46
RELU=47
SOFTPLUS=48
GELU=49
SIGN=50
MAP=51
CONV=52
SWAP=53
PERM=54
PLUS=55
MINUS=56
MULT=57
DIV=58
MOD=59
POW=60
GE=61
GT=62
LE=63
LT=64
EQ=65
NE=66
PIPE=67
CONSTANT=68
NUMBER=69
VARIABLE=70
WS=71
'('=1
')'=2
'['=3
@@ -107,28 +109,30 @@ WS=69
'ifft'=38
'angle'=39
'print'=40
'lerp'=41
'step'=42
'smoothstep'=43
'fract'=44
'relu'=45
'softplus'=46
'gelu'=47
'sign'=48
'map'=49
'conv'=50
'swap'=51
'permute'=52
'+'=53
'-'=54
'*'=55
'/'=56
'%'=57
'^'=58
'>='=59
'>'=60
'<='=61
'<'=62
'=='=63
'!='=64
'|'=65
'print_shape'=41
'pshp'=42
'lerp'=43
'step'=44
'smoothstep'=45
'fract'=46
'relu'=47
'softplus'=48
'gelu'=49
'sign'=50
'map'=51
'conv'=52
'swap'=53
'permute'=54
'+'=55
'-'=56
'*'=57
'/'=58
'%'=59
'^'=60
'>='=61
'>'=62
'<='=63
'<'=64
'=='=65
'!='=66
'|'=67
File diff suppressed because one or more lines are too long
+208 -196
View File
@@ -10,7 +10,7 @@ else:
def serializedATN():
return [
4,0,69,463,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,
4,0,71,484,6,-1,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,
2,6,7,6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,
13,7,13,2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,
19,2,20,7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,
@@ -20,158 +20,166 @@ def serializedATN():
45,2,46,7,46,2,47,7,47,2,48,7,48,2,49,7,49,2,50,7,50,2,51,7,51,2,
52,7,52,2,53,7,53,2,54,7,54,2,55,7,55,2,56,7,56,2,57,7,57,2,58,7,
58,2,59,7,59,2,60,7,60,2,61,7,61,2,62,7,62,2,63,7,63,2,64,7,64,2,
65,7,65,2,66,7,66,2,67,7,67,2,68,7,68,1,0,1,0,1,1,1,1,1,2,1,2,1,
3,1,3,1,4,1,4,1,5,1,5,1,5,1,5,1,6,1,6,1,6,1,6,1,7,1,7,1,7,1,7,1,
8,1,8,1,8,1,8,1,8,1,9,1,9,1,9,1,9,1,9,1,10,1,10,1,10,1,10,1,10,1,
11,1,11,1,11,1,11,1,11,1,11,1,12,1,12,1,12,1,12,1,12,1,13,1,13,1,
13,1,13,1,13,1,14,1,14,1,14,1,14,1,14,1,15,1,15,1,15,1,15,1,15,1,
15,1,16,1,16,1,16,1,16,1,16,1,16,1,17,1,17,1,17,1,17,1,17,1,17,1,
18,1,18,1,18,1,18,1,19,1,19,1,19,1,19,1,19,1,20,1,20,1,20,1,21,1,
21,1,21,1,21,1,22,1,22,1,22,1,22,1,23,1,23,1,23,1,23,1,23,1,24,1,
24,1,24,1,24,1,24,1,25,1,25,1,25,1,25,1,25,1,26,1,26,1,26,1,26,1,
26,1,27,1,27,1,27,1,27,1,27,1,27,1,28,1,28,1,28,1,28,1,28,1,28,1,
29,1,29,1,29,1,29,1,29,1,29,1,30,1,30,1,30,1,30,1,30,1,31,1,31,1,
31,1,31,1,31,1,31,1,32,1,32,1,32,1,32,1,32,1,32,1,33,1,33,1,33,1,
33,1,34,1,34,1,34,1,34,1,34,1,35,1,35,1,35,1,35,1,35,1,35,1,36,1,
36,1,36,1,36,1,37,1,37,1,37,1,37,1,37,1,38,1,38,1,38,1,38,1,38,1,
38,1,39,1,39,1,39,1,39,1,39,1,39,1,40,1,40,1,40,1,40,1,40,1,41,1,
41,1,41,1,41,1,41,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,42,1,
42,1,42,1,43,1,43,1,43,1,43,1,43,1,43,1,44,1,44,1,44,1,44,1,44,1,
45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,45,1,46,1,46,1,46,1,46,1,
46,1,47,1,47,1,47,1,47,1,47,1,48,1,48,1,48,1,48,1,49,1,49,1,49,1,
49,1,49,1,50,1,50,1,50,1,50,1,50,1,51,1,51,1,51,1,51,1,51,1,51,1,
51,1,51,1,52,1,52,1,53,1,53,1,54,1,54,1,55,1,55,1,56,1,56,1,57,1,
57,1,58,1,58,1,58,1,59,1,59,1,60,1,60,1,60,1,61,1,61,1,62,1,62,1,
62,1,63,1,63,1,63,1,64,1,64,1,65,1,65,1,65,1,65,1,65,3,65,435,8,
65,1,66,4,66,438,8,66,11,66,12,66,439,1,66,1,66,4,66,444,8,66,11,
66,12,66,445,3,66,448,8,66,1,67,1,67,5,67,452,8,67,10,67,12,67,455,
9,67,1,68,4,68,458,8,68,11,68,12,68,459,1,68,1,68,0,0,69,1,1,3,2,
5,3,7,4,9,5,11,6,13,7,15,8,17,9,19,10,21,11,23,12,25,13,27,14,29,
15,31,16,33,17,35,18,37,19,39,20,41,21,43,22,45,23,47,24,49,25,51,
26,53,27,55,28,57,29,59,30,61,31,63,32,65,33,67,34,69,35,71,36,73,
37,75,38,77,39,79,40,81,41,83,42,85,43,87,44,89,45,91,46,93,47,95,
48,97,49,99,50,101,51,103,52,105,53,107,54,109,55,111,56,113,57,
115,58,117,59,119,60,121,61,123,62,125,63,127,64,129,65,131,66,133,
67,135,68,137,69,1,0,5,2,0,69,69,101,101,1,0,48,57,3,0,65,90,95,
95,97,122,4,0,48,57,65,90,95,95,97,122,3,0,9,10,13,13,32,32,469,
0,1,1,0,0,0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,
1,0,0,0,0,13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,21,
1,0,0,0,0,23,1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31,
1,0,0,0,0,33,1,0,0,0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,
1,0,0,0,0,43,1,0,0,0,0,45,1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,0,0,51,
1,0,0,0,0,53,1,0,0,0,0,55,1,0,0,0,0,57,1,0,0,0,0,59,1,0,0,0,0,61,
1,0,0,0,0,63,1,0,0,0,0,65,1,0,0,0,0,67,1,0,0,0,0,69,1,0,0,0,0,71,
1,0,0,0,0,73,1,0,0,0,0,75,1,0,0,0,0,77,1,0,0,0,0,79,1,0,0,0,0,81,
1,0,0,0,0,83,1,0,0,0,0,85,1,0,0,0,0,87,1,0,0,0,0,89,1,0,0,0,0,91,
1,0,0,0,0,93,1,0,0,0,0,95,1,0,0,0,0,97,1,0,0,0,0,99,1,0,0,0,0,101,
1,0,0,0,0,103,1,0,0,0,0,105,1,0,0,0,0,107,1,0,0,0,0,109,1,0,0,0,
0,111,1,0,0,0,0,113,1,0,0,0,0,115,1,0,0,0,0,117,1,0,0,0,0,119,1,
0,0,0,0,121,1,0,0,0,0,123,1,0,0,0,0,125,1,0,0,0,0,127,1,0,0,0,0,
129,1,0,0,0,0,131,1,0,0,0,0,133,1,0,0,0,0,135,1,0,0,0,0,137,1,0,
0,0,1,139,1,0,0,0,3,141,1,0,0,0,5,143,1,0,0,0,7,145,1,0,0,0,9,147,
1,0,0,0,11,149,1,0,0,0,13,153,1,0,0,0,15,157,1,0,0,0,17,161,1,0,
0,0,19,166,1,0,0,0,21,171,1,0,0,0,23,176,1,0,0,0,25,182,1,0,0,0,
27,187,1,0,0,0,29,192,1,0,0,0,31,197,1,0,0,0,33,203,1,0,0,0,35,209,
1,0,0,0,37,215,1,0,0,0,39,219,1,0,0,0,41,224,1,0,0,0,43,227,1,0,
0,0,45,231,1,0,0,0,47,235,1,0,0,0,49,240,1,0,0,0,51,245,1,0,0,0,
53,250,1,0,0,0,55,255,1,0,0,0,57,261,1,0,0,0,59,267,1,0,0,0,61,273,
1,0,0,0,63,278,1,0,0,0,65,284,1,0,0,0,67,290,1,0,0,0,69,294,1,0,
0,0,71,299,1,0,0,0,73,305,1,0,0,0,75,309,1,0,0,0,77,314,1,0,0,0,
79,320,1,0,0,0,81,326,1,0,0,0,83,331,1,0,0,0,85,336,1,0,0,0,87,347,
1,0,0,0,89,353,1,0,0,0,91,358,1,0,0,0,93,367,1,0,0,0,95,372,1,0,
0,0,97,377,1,0,0,0,99,381,1,0,0,0,101,386,1,0,0,0,103,391,1,0,0,
0,105,399,1,0,0,0,107,401,1,0,0,0,109,403,1,0,0,0,111,405,1,0,0,
0,113,407,1,0,0,0,115,409,1,0,0,0,117,411,1,0,0,0,119,414,1,0,0,
0,121,416,1,0,0,0,123,419,1,0,0,0,125,421,1,0,0,0,127,424,1,0,0,
0,129,427,1,0,0,0,131,434,1,0,0,0,133,437,1,0,0,0,135,449,1,0,0,
0,137,457,1,0,0,0,139,140,5,40,0,0,140,2,1,0,0,0,141,142,5,41,0,
0,142,4,1,0,0,0,143,144,5,91,0,0,144,6,1,0,0,0,145,146,5,44,0,0,
146,8,1,0,0,0,147,148,5,93,0,0,148,10,1,0,0,0,149,150,5,115,0,0,
150,151,5,105,0,0,151,152,5,110,0,0,152,12,1,0,0,0,153,154,5,99,
0,0,154,155,5,111,0,0,155,156,5,115,0,0,156,14,1,0,0,0,157,158,5,
116,0,0,158,159,5,97,0,0,159,160,5,110,0,0,160,16,1,0,0,0,161,162,
5,97,0,0,162,163,5,115,0,0,163,164,5,105,0,0,164,165,5,110,0,0,165,
18,1,0,0,0,166,167,5,97,0,0,167,168,5,99,0,0,168,169,5,111,0,0,169,
170,5,115,0,0,170,20,1,0,0,0,171,172,5,97,0,0,172,173,5,116,0,0,
173,174,5,97,0,0,174,175,5,110,0,0,175,22,1,0,0,0,176,177,5,97,0,
0,177,178,5,116,0,0,178,179,5,97,0,0,179,180,5,110,0,0,180,181,5,
50,0,0,181,24,1,0,0,0,182,183,5,115,0,0,183,184,5,105,0,0,184,185,
5,110,0,0,185,186,5,104,0,0,186,26,1,0,0,0,187,188,5,99,0,0,188,
189,5,111,0,0,189,190,5,115,0,0,190,191,5,104,0,0,191,28,1,0,0,0,
192,193,5,116,0,0,193,194,5,97,0,0,194,195,5,110,0,0,195,196,5,104,
0,0,196,30,1,0,0,0,197,198,5,97,0,0,198,199,5,115,0,0,199,200,5,
105,0,0,200,201,5,110,0,0,201,202,5,104,0,0,202,32,1,0,0,0,203,204,
5,97,0,0,204,205,5,99,0,0,205,206,5,111,0,0,206,207,5,115,0,0,207,
208,5,104,0,0,208,34,1,0,0,0,209,210,5,97,0,0,210,211,5,116,0,0,
211,212,5,97,0,0,212,213,5,110,0,0,213,214,5,104,0,0,214,36,1,0,
0,0,215,216,5,97,0,0,216,217,5,98,0,0,217,218,5,115,0,0,218,38,1,
0,0,0,219,220,5,115,0,0,220,221,5,113,0,0,221,222,5,114,0,0,222,
223,5,116,0,0,223,40,1,0,0,0,224,225,5,108,0,0,225,226,5,110,0,0,
226,42,1,0,0,0,227,228,5,108,0,0,228,229,5,111,0,0,229,230,5,103,
0,0,230,44,1,0,0,0,231,232,5,101,0,0,232,233,5,120,0,0,233,234,5,
112,0,0,234,46,1,0,0,0,235,236,5,115,0,0,236,237,5,109,0,0,237,238,
5,105,0,0,238,239,5,110,0,0,239,48,1,0,0,0,240,241,5,115,0,0,241,
242,5,109,0,0,242,243,5,97,0,0,243,244,5,120,0,0,244,50,1,0,0,0,
245,246,5,116,0,0,246,247,5,109,0,0,247,248,5,105,0,0,248,249,5,
110,0,0,249,52,1,0,0,0,250,251,5,116,0,0,251,252,5,109,0,0,252,253,
5,97,0,0,253,254,5,120,0,0,254,54,1,0,0,0,255,256,5,116,0,0,256,
257,5,110,0,0,257,258,5,111,0,0,258,259,5,114,0,0,259,260,5,109,
0,0,260,56,1,0,0,0,261,262,5,115,0,0,262,263,5,110,0,0,263,264,5,
111,0,0,264,265,5,114,0,0,265,266,5,109,0,0,266,58,1,0,0,0,267,268,
5,102,0,0,268,269,5,108,0,0,269,270,5,111,0,0,270,271,5,111,0,0,
271,272,5,114,0,0,272,60,1,0,0,0,273,274,5,99,0,0,274,275,5,101,
0,0,275,276,5,105,0,0,276,277,5,108,0,0,277,62,1,0,0,0,278,279,5,
114,0,0,279,280,5,111,0,0,280,281,5,117,0,0,281,282,5,110,0,0,282,
283,5,100,0,0,283,64,1,0,0,0,284,285,5,103,0,0,285,286,5,97,0,0,
286,287,5,109,0,0,287,288,5,109,0,0,288,289,5,97,0,0,289,66,1,0,
0,0,290,291,5,112,0,0,291,292,5,111,0,0,292,293,5,119,0,0,293,68,
1,0,0,0,294,295,5,115,0,0,295,296,5,105,0,0,296,297,5,103,0,0,297,
298,5,109,0,0,298,70,1,0,0,0,299,300,5,99,0,0,300,301,5,108,0,0,
301,302,5,97,0,0,302,303,5,109,0,0,303,304,5,112,0,0,304,72,1,0,
0,0,305,306,5,102,0,0,306,307,5,102,0,0,307,308,5,116,0,0,308,74,
1,0,0,0,309,310,5,105,0,0,310,311,5,102,0,0,311,312,5,102,0,0,312,
313,5,116,0,0,313,76,1,0,0,0,314,315,5,97,0,0,315,316,5,110,0,0,
316,317,5,103,0,0,317,318,5,108,0,0,318,319,5,101,0,0,319,78,1,0,
0,0,320,321,5,112,0,0,321,322,5,114,0,0,322,323,5,105,0,0,323,324,
5,110,0,0,324,325,5,116,0,0,325,80,1,0,0,0,326,327,5,108,0,0,327,
328,5,101,0,0,328,329,5,114,0,0,329,330,5,112,0,0,330,82,1,0,0,0,
331,332,5,115,0,0,332,333,5,116,0,0,333,334,5,101,0,0,334,335,5,
112,0,0,335,84,1,0,0,0,336,337,5,115,0,0,337,338,5,109,0,0,338,339,
5,111,0,0,339,340,5,111,0,0,340,341,5,116,0,0,341,342,5,104,0,0,
342,343,5,115,0,0,343,344,5,116,0,0,344,345,5,101,0,0,345,346,5,
112,0,0,346,86,1,0,0,0,347,348,5,102,0,0,348,349,5,114,0,0,349,350,
5,97,0,0,350,351,5,99,0,0,351,352,5,116,0,0,352,88,1,0,0,0,353,354,
5,114,0,0,354,355,5,101,0,0,355,356,5,108,0,0,356,357,5,117,0,0,
357,90,1,0,0,0,358,359,5,115,0,0,359,360,5,111,0,0,360,361,5,102,
0,0,361,362,5,116,0,0,362,363,5,112,0,0,363,364,5,108,0,0,364,365,
5,117,0,0,365,366,5,115,0,0,366,92,1,0,0,0,367,368,5,103,0,0,368,
369,5,101,0,0,369,370,5,108,0,0,370,371,5,117,0,0,371,94,1,0,0,0,
372,373,5,115,0,0,373,374,5,105,0,0,374,375,5,103,0,0,375,376,5,
110,0,0,376,96,1,0,0,0,377,378,5,109,0,0,378,379,5,97,0,0,379,380,
5,112,0,0,380,98,1,0,0,0,381,382,5,99,0,0,382,383,5,111,0,0,383,
384,5,110,0,0,384,385,5,118,0,0,385,100,1,0,0,0,386,387,5,115,0,
0,387,388,5,119,0,0,388,389,5,97,0,0,389,390,5,112,0,0,390,102,1,
0,0,0,391,392,5,112,0,0,392,393,5,101,0,0,393,394,5,114,0,0,394,
395,5,109,0,0,395,396,5,117,0,0,396,397,5,116,0,0,397,398,5,101,
0,0,398,104,1,0,0,0,399,400,5,43,0,0,400,106,1,0,0,0,401,402,5,45,
0,0,402,108,1,0,0,0,403,404,5,42,0,0,404,110,1,0,0,0,405,406,5,47,
0,0,406,112,1,0,0,0,407,408,5,37,0,0,408,114,1,0,0,0,409,410,5,94,
0,0,410,116,1,0,0,0,411,412,5,62,0,0,412,413,5,61,0,0,413,118,1,
0,0,0,414,415,5,62,0,0,415,120,1,0,0,0,416,417,5,60,0,0,417,418,
5,61,0,0,418,122,1,0,0,0,419,420,5,60,0,0,420,124,1,0,0,0,421,422,
5,61,0,0,422,423,5,61,0,0,423,126,1,0,0,0,424,425,5,33,0,0,425,426,
5,61,0,0,426,128,1,0,0,0,427,428,5,124,0,0,428,130,1,0,0,0,429,430,
5,112,0,0,430,435,5,105,0,0,431,432,5,80,0,0,432,435,5,73,0,0,433,
435,7,0,0,0,434,429,1,0,0,0,434,431,1,0,0,0,434,433,1,0,0,0,435,
132,1,0,0,0,436,438,7,1,0,0,437,436,1,0,0,0,438,439,1,0,0,0,439,
437,1,0,0,0,439,440,1,0,0,0,440,447,1,0,0,0,441,443,5,46,0,0,442,
444,7,1,0,0,443,442,1,0,0,0,444,445,1,0,0,0,445,443,1,0,0,0,445,
446,1,0,0,0,446,448,1,0,0,0,447,441,1,0,0,0,447,448,1,0,0,0,448,
134,1,0,0,0,449,453,7,2,0,0,450,452,7,3,0,0,451,450,1,0,0,0,452,
455,1,0,0,0,453,451,1,0,0,0,453,454,1,0,0,0,454,136,1,0,0,0,455,
453,1,0,0,0,456,458,7,4,0,0,457,456,1,0,0,0,458,459,1,0,0,0,459,
457,1,0,0,0,459,460,1,0,0,0,460,461,1,0,0,0,461,462,6,68,0,0,462,
138,1,0,0,0,7,0,434,439,445,447,453,459,1,6,0,0
65,7,65,2,66,7,66,2,67,7,67,2,68,7,68,2,69,7,69,2,70,7,70,1,0,1,
0,1,1,1,1,1,2,1,2,1,3,1,3,1,4,1,4,1,5,1,5,1,5,1,5,1,6,1,6,1,6,1,
6,1,7,1,7,1,7,1,7,1,8,1,8,1,8,1,8,1,8,1,9,1,9,1,9,1,9,1,9,1,10,1,
10,1,10,1,10,1,10,1,11,1,11,1,11,1,11,1,11,1,11,1,12,1,12,1,12,1,
12,1,12,1,13,1,13,1,13,1,13,1,13,1,14,1,14,1,14,1,14,1,14,1,15,1,
15,1,15,1,15,1,15,1,15,1,16,1,16,1,16,1,16,1,16,1,16,1,17,1,17,1,
17,1,17,1,17,1,17,1,18,1,18,1,18,1,18,1,19,1,19,1,19,1,19,1,19,1,
20,1,20,1,20,1,21,1,21,1,21,1,21,1,22,1,22,1,22,1,22,1,23,1,23,1,
23,1,23,1,23,1,24,1,24,1,24,1,24,1,24,1,25,1,25,1,25,1,25,1,25,1,
26,1,26,1,26,1,26,1,26,1,27,1,27,1,27,1,27,1,27,1,27,1,28,1,28,1,
28,1,28,1,28,1,28,1,29,1,29,1,29,1,29,1,29,1,29,1,30,1,30,1,30,1,
30,1,30,1,31,1,31,1,31,1,31,1,31,1,31,1,32,1,32,1,32,1,32,1,32,1,
32,1,33,1,33,1,33,1,33,1,34,1,34,1,34,1,34,1,34,1,35,1,35,1,35,1,
35,1,35,1,35,1,36,1,36,1,36,1,36,1,37,1,37,1,37,1,37,1,37,1,38,1,
38,1,38,1,38,1,38,1,38,1,39,1,39,1,39,1,39,1,39,1,39,1,40,1,40,1,
40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,40,1,41,1,41,1,41,1,
41,1,41,1,42,1,42,1,42,1,42,1,42,1,43,1,43,1,43,1,43,1,43,1,44,1,
44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,44,1,45,1,45,1,45,1,
45,1,45,1,45,1,46,1,46,1,46,1,46,1,46,1,47,1,47,1,47,1,47,1,47,1,
47,1,47,1,47,1,47,1,48,1,48,1,48,1,48,1,48,1,49,1,49,1,49,1,49,1,
49,1,50,1,50,1,50,1,50,1,51,1,51,1,51,1,51,1,51,1,52,1,52,1,52,1,
52,1,52,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,53,1,54,1,54,1,55,1,
55,1,56,1,56,1,57,1,57,1,58,1,58,1,59,1,59,1,60,1,60,1,60,1,61,1,
61,1,62,1,62,1,62,1,63,1,63,1,64,1,64,1,64,1,65,1,65,1,65,1,66,1,
66,1,67,1,67,1,67,1,67,1,67,3,67,456,8,67,1,68,4,68,459,8,68,11,
68,12,68,460,1,68,1,68,4,68,465,8,68,11,68,12,68,466,3,68,469,8,
68,1,69,1,69,5,69,473,8,69,10,69,12,69,476,9,69,1,70,4,70,479,8,
70,11,70,12,70,480,1,70,1,70,0,0,71,1,1,3,2,5,3,7,4,9,5,11,6,13,
7,15,8,17,9,19,10,21,11,23,12,25,13,27,14,29,15,31,16,33,17,35,18,
37,19,39,20,41,21,43,22,45,23,47,24,49,25,51,26,53,27,55,28,57,29,
59,30,61,31,63,32,65,33,67,34,69,35,71,36,73,37,75,38,77,39,79,40,
81,41,83,42,85,43,87,44,89,45,91,46,93,47,95,48,97,49,99,50,101,
51,103,52,105,53,107,54,109,55,111,56,113,57,115,58,117,59,119,60,
121,61,123,62,125,63,127,64,129,65,131,66,133,67,135,68,137,69,139,
70,141,71,1,0,5,2,0,69,69,101,101,1,0,48,57,3,0,65,90,95,95,97,122,
4,0,48,57,65,90,95,95,97,122,3,0,9,10,13,13,32,32,490,0,1,1,0,0,
0,0,3,1,0,0,0,0,5,1,0,0,0,0,7,1,0,0,0,0,9,1,0,0,0,0,11,1,0,0,0,0,
13,1,0,0,0,0,15,1,0,0,0,0,17,1,0,0,0,0,19,1,0,0,0,0,21,1,0,0,0,0,
23,1,0,0,0,0,25,1,0,0,0,0,27,1,0,0,0,0,29,1,0,0,0,0,31,1,0,0,0,0,
33,1,0,0,0,0,35,1,0,0,0,0,37,1,0,0,0,0,39,1,0,0,0,0,41,1,0,0,0,0,
43,1,0,0,0,0,45,1,0,0,0,0,47,1,0,0,0,0,49,1,0,0,0,0,51,1,0,0,0,0,
53,1,0,0,0,0,55,1,0,0,0,0,57,1,0,0,0,0,59,1,0,0,0,0,61,1,0,0,0,0,
63,1,0,0,0,0,65,1,0,0,0,0,67,1,0,0,0,0,69,1,0,0,0,0,71,1,0,0,0,0,
73,1,0,0,0,0,75,1,0,0,0,0,77,1,0,0,0,0,79,1,0,0,0,0,81,1,0,0,0,0,
83,1,0,0,0,0,85,1,0,0,0,0,87,1,0,0,0,0,89,1,0,0,0,0,91,1,0,0,0,0,
93,1,0,0,0,0,95,1,0,0,0,0,97,1,0,0,0,0,99,1,0,0,0,0,101,1,0,0,0,
0,103,1,0,0,0,0,105,1,0,0,0,0,107,1,0,0,0,0,109,1,0,0,0,0,111,1,
0,0,0,0,113,1,0,0,0,0,115,1,0,0,0,0,117,1,0,0,0,0,119,1,0,0,0,0,
121,1,0,0,0,0,123,1,0,0,0,0,125,1,0,0,0,0,127,1,0,0,0,0,129,1,0,
0,0,0,131,1,0,0,0,0,133,1,0,0,0,0,135,1,0,0,0,0,137,1,0,0,0,0,139,
1,0,0,0,0,141,1,0,0,0,1,143,1,0,0,0,3,145,1,0,0,0,5,147,1,0,0,0,
7,149,1,0,0,0,9,151,1,0,0,0,11,153,1,0,0,0,13,157,1,0,0,0,15,161,
1,0,0,0,17,165,1,0,0,0,19,170,1,0,0,0,21,175,1,0,0,0,23,180,1,0,
0,0,25,186,1,0,0,0,27,191,1,0,0,0,29,196,1,0,0,0,31,201,1,0,0,0,
33,207,1,0,0,0,35,213,1,0,0,0,37,219,1,0,0,0,39,223,1,0,0,0,41,228,
1,0,0,0,43,231,1,0,0,0,45,235,1,0,0,0,47,239,1,0,0,0,49,244,1,0,
0,0,51,249,1,0,0,0,53,254,1,0,0,0,55,259,1,0,0,0,57,265,1,0,0,0,
59,271,1,0,0,0,61,277,1,0,0,0,63,282,1,0,0,0,65,288,1,0,0,0,67,294,
1,0,0,0,69,298,1,0,0,0,71,303,1,0,0,0,73,309,1,0,0,0,75,313,1,0,
0,0,77,318,1,0,0,0,79,324,1,0,0,0,81,330,1,0,0,0,83,342,1,0,0,0,
85,347,1,0,0,0,87,352,1,0,0,0,89,357,1,0,0,0,91,368,1,0,0,0,93,374,
1,0,0,0,95,379,1,0,0,0,97,388,1,0,0,0,99,393,1,0,0,0,101,398,1,0,
0,0,103,402,1,0,0,0,105,407,1,0,0,0,107,412,1,0,0,0,109,420,1,0,
0,0,111,422,1,0,0,0,113,424,1,0,0,0,115,426,1,0,0,0,117,428,1,0,
0,0,119,430,1,0,0,0,121,432,1,0,0,0,123,435,1,0,0,0,125,437,1,0,
0,0,127,440,1,0,0,0,129,442,1,0,0,0,131,445,1,0,0,0,133,448,1,0,
0,0,135,455,1,0,0,0,137,458,1,0,0,0,139,470,1,0,0,0,141,478,1,0,
0,0,143,144,5,40,0,0,144,2,1,0,0,0,145,146,5,41,0,0,146,4,1,0,0,
0,147,148,5,91,0,0,148,6,1,0,0,0,149,150,5,44,0,0,150,8,1,0,0,0,
151,152,5,93,0,0,152,10,1,0,0,0,153,154,5,115,0,0,154,155,5,105,
0,0,155,156,5,110,0,0,156,12,1,0,0,0,157,158,5,99,0,0,158,159,5,
111,0,0,159,160,5,115,0,0,160,14,1,0,0,0,161,162,5,116,0,0,162,163,
5,97,0,0,163,164,5,110,0,0,164,16,1,0,0,0,165,166,5,97,0,0,166,167,
5,115,0,0,167,168,5,105,0,0,168,169,5,110,0,0,169,18,1,0,0,0,170,
171,5,97,0,0,171,172,5,99,0,0,172,173,5,111,0,0,173,174,5,115,0,
0,174,20,1,0,0,0,175,176,5,97,0,0,176,177,5,116,0,0,177,178,5,97,
0,0,178,179,5,110,0,0,179,22,1,0,0,0,180,181,5,97,0,0,181,182,5,
116,0,0,182,183,5,97,0,0,183,184,5,110,0,0,184,185,5,50,0,0,185,
24,1,0,0,0,186,187,5,115,0,0,187,188,5,105,0,0,188,189,5,110,0,0,
189,190,5,104,0,0,190,26,1,0,0,0,191,192,5,99,0,0,192,193,5,111,
0,0,193,194,5,115,0,0,194,195,5,104,0,0,195,28,1,0,0,0,196,197,5,
116,0,0,197,198,5,97,0,0,198,199,5,110,0,0,199,200,5,104,0,0,200,
30,1,0,0,0,201,202,5,97,0,0,202,203,5,115,0,0,203,204,5,105,0,0,
204,205,5,110,0,0,205,206,5,104,0,0,206,32,1,0,0,0,207,208,5,97,
0,0,208,209,5,99,0,0,209,210,5,111,0,0,210,211,5,115,0,0,211,212,
5,104,0,0,212,34,1,0,0,0,213,214,5,97,0,0,214,215,5,116,0,0,215,
216,5,97,0,0,216,217,5,110,0,0,217,218,5,104,0,0,218,36,1,0,0,0,
219,220,5,97,0,0,220,221,5,98,0,0,221,222,5,115,0,0,222,38,1,0,0,
0,223,224,5,115,0,0,224,225,5,113,0,0,225,226,5,114,0,0,226,227,
5,116,0,0,227,40,1,0,0,0,228,229,5,108,0,0,229,230,5,110,0,0,230,
42,1,0,0,0,231,232,5,108,0,0,232,233,5,111,0,0,233,234,5,103,0,0,
234,44,1,0,0,0,235,236,5,101,0,0,236,237,5,120,0,0,237,238,5,112,
0,0,238,46,1,0,0,0,239,240,5,115,0,0,240,241,5,109,0,0,241,242,5,
105,0,0,242,243,5,110,0,0,243,48,1,0,0,0,244,245,5,115,0,0,245,246,
5,109,0,0,246,247,5,97,0,0,247,248,5,120,0,0,248,50,1,0,0,0,249,
250,5,116,0,0,250,251,5,109,0,0,251,252,5,105,0,0,252,253,5,110,
0,0,253,52,1,0,0,0,254,255,5,116,0,0,255,256,5,109,0,0,256,257,5,
97,0,0,257,258,5,120,0,0,258,54,1,0,0,0,259,260,5,116,0,0,260,261,
5,110,0,0,261,262,5,111,0,0,262,263,5,114,0,0,263,264,5,109,0,0,
264,56,1,0,0,0,265,266,5,115,0,0,266,267,5,110,0,0,267,268,5,111,
0,0,268,269,5,114,0,0,269,270,5,109,0,0,270,58,1,0,0,0,271,272,5,
102,0,0,272,273,5,108,0,0,273,274,5,111,0,0,274,275,5,111,0,0,275,
276,5,114,0,0,276,60,1,0,0,0,277,278,5,99,0,0,278,279,5,101,0,0,
279,280,5,105,0,0,280,281,5,108,0,0,281,62,1,0,0,0,282,283,5,114,
0,0,283,284,5,111,0,0,284,285,5,117,0,0,285,286,5,110,0,0,286,287,
5,100,0,0,287,64,1,0,0,0,288,289,5,103,0,0,289,290,5,97,0,0,290,
291,5,109,0,0,291,292,5,109,0,0,292,293,5,97,0,0,293,66,1,0,0,0,
294,295,5,112,0,0,295,296,5,111,0,0,296,297,5,119,0,0,297,68,1,0,
0,0,298,299,5,115,0,0,299,300,5,105,0,0,300,301,5,103,0,0,301,302,
5,109,0,0,302,70,1,0,0,0,303,304,5,99,0,0,304,305,5,108,0,0,305,
306,5,97,0,0,306,307,5,109,0,0,307,308,5,112,0,0,308,72,1,0,0,0,
309,310,5,102,0,0,310,311,5,102,0,0,311,312,5,116,0,0,312,74,1,0,
0,0,313,314,5,105,0,0,314,315,5,102,0,0,315,316,5,102,0,0,316,317,
5,116,0,0,317,76,1,0,0,0,318,319,5,97,0,0,319,320,5,110,0,0,320,
321,5,103,0,0,321,322,5,108,0,0,322,323,5,101,0,0,323,78,1,0,0,0,
324,325,5,112,0,0,325,326,5,114,0,0,326,327,5,105,0,0,327,328,5,
110,0,0,328,329,5,116,0,0,329,80,1,0,0,0,330,331,5,112,0,0,331,332,
5,114,0,0,332,333,5,105,0,0,333,334,5,110,0,0,334,335,5,116,0,0,
335,336,5,95,0,0,336,337,5,115,0,0,337,338,5,104,0,0,338,339,5,97,
0,0,339,340,5,112,0,0,340,341,5,101,0,0,341,82,1,0,0,0,342,343,5,
112,0,0,343,344,5,115,0,0,344,345,5,104,0,0,345,346,5,112,0,0,346,
84,1,0,0,0,347,348,5,108,0,0,348,349,5,101,0,0,349,350,5,114,0,0,
350,351,5,112,0,0,351,86,1,0,0,0,352,353,5,115,0,0,353,354,5,116,
0,0,354,355,5,101,0,0,355,356,5,112,0,0,356,88,1,0,0,0,357,358,5,
115,0,0,358,359,5,109,0,0,359,360,5,111,0,0,360,361,5,111,0,0,361,
362,5,116,0,0,362,363,5,104,0,0,363,364,5,115,0,0,364,365,5,116,
0,0,365,366,5,101,0,0,366,367,5,112,0,0,367,90,1,0,0,0,368,369,5,
102,0,0,369,370,5,114,0,0,370,371,5,97,0,0,371,372,5,99,0,0,372,
373,5,116,0,0,373,92,1,0,0,0,374,375,5,114,0,0,375,376,5,101,0,0,
376,377,5,108,0,0,377,378,5,117,0,0,378,94,1,0,0,0,379,380,5,115,
0,0,380,381,5,111,0,0,381,382,5,102,0,0,382,383,5,116,0,0,383,384,
5,112,0,0,384,385,5,108,0,0,385,386,5,117,0,0,386,387,5,115,0,0,
387,96,1,0,0,0,388,389,5,103,0,0,389,390,5,101,0,0,390,391,5,108,
0,0,391,392,5,117,0,0,392,98,1,0,0,0,393,394,5,115,0,0,394,395,5,
105,0,0,395,396,5,103,0,0,396,397,5,110,0,0,397,100,1,0,0,0,398,
399,5,109,0,0,399,400,5,97,0,0,400,401,5,112,0,0,401,102,1,0,0,0,
402,403,5,99,0,0,403,404,5,111,0,0,404,405,5,110,0,0,405,406,5,118,
0,0,406,104,1,0,0,0,407,408,5,115,0,0,408,409,5,119,0,0,409,410,
5,97,0,0,410,411,5,112,0,0,411,106,1,0,0,0,412,413,5,112,0,0,413,
414,5,101,0,0,414,415,5,114,0,0,415,416,5,109,0,0,416,417,5,117,
0,0,417,418,5,116,0,0,418,419,5,101,0,0,419,108,1,0,0,0,420,421,
5,43,0,0,421,110,1,0,0,0,422,423,5,45,0,0,423,112,1,0,0,0,424,425,
5,42,0,0,425,114,1,0,0,0,426,427,5,47,0,0,427,116,1,0,0,0,428,429,
5,37,0,0,429,118,1,0,0,0,430,431,5,94,0,0,431,120,1,0,0,0,432,433,
5,62,0,0,433,434,5,61,0,0,434,122,1,0,0,0,435,436,5,62,0,0,436,124,
1,0,0,0,437,438,5,60,0,0,438,439,5,61,0,0,439,126,1,0,0,0,440,441,
5,60,0,0,441,128,1,0,0,0,442,443,5,61,0,0,443,444,5,61,0,0,444,130,
1,0,0,0,445,446,5,33,0,0,446,447,5,61,0,0,447,132,1,0,0,0,448,449,
5,124,0,0,449,134,1,0,0,0,450,451,5,112,0,0,451,456,5,105,0,0,452,
453,5,80,0,0,453,456,5,73,0,0,454,456,7,0,0,0,455,450,1,0,0,0,455,
452,1,0,0,0,455,454,1,0,0,0,456,136,1,0,0,0,457,459,7,1,0,0,458,
457,1,0,0,0,459,460,1,0,0,0,460,458,1,0,0,0,460,461,1,0,0,0,461,
468,1,0,0,0,462,464,5,46,0,0,463,465,7,1,0,0,464,463,1,0,0,0,465,
466,1,0,0,0,466,464,1,0,0,0,466,467,1,0,0,0,467,469,1,0,0,0,468,
462,1,0,0,0,468,469,1,0,0,0,469,138,1,0,0,0,470,474,7,2,0,0,471,
473,7,3,0,0,472,471,1,0,0,0,473,476,1,0,0,0,474,472,1,0,0,0,474,
475,1,0,0,0,475,140,1,0,0,0,476,474,1,0,0,0,477,479,7,4,0,0,478,
477,1,0,0,0,479,480,1,0,0,0,480,478,1,0,0,0,480,481,1,0,0,0,481,
482,1,0,0,0,482,483,6,70,0,0,483,142,1,0,0,0,7,0,455,460,466,468,
474,480,1,6,0,0
]
class MathExprLexer(Lexer):
@@ -220,35 +228,37 @@ class MathExprLexer(Lexer):
SIFFT = 38
ANGL = 39
PRNT = 40
LERP = 41
STEP = 42
SMOOTHSTEP = 43
FRACT = 44
RELU = 45
SOFTPLUS = 46
GELU = 47
SIGN = 48
MAP = 49
CONV = 50
SWAP = 51
PERM = 52
PLUS = 53
MINUS = 54
MULT = 55
DIV = 56
MOD = 57
POW = 58
GE = 59
GT = 60
LE = 61
LT = 62
EQ = 63
NE = 64
PIPE = 65
CONSTANT = 66
NUMBER = 67
VARIABLE = 68
WS = 69
PRINT_SHAPE_L = 41
PRINT_SHAPE = 42
LERP = 43
STEP = 44
SMOOTHSTEP = 45
FRACT = 46
RELU = 47
SOFTPLUS = 48
GELU = 49
SIGN = 50
MAP = 51
CONV = 52
SWAP = 53
PERM = 54
PLUS = 55
MINUS = 56
MULT = 57
DIV = 58
MOD = 59
POW = 60
GE = 61
GT = 62
LE = 63
LT = 64
EQ = 65
NE = 66
PIPE = 67
CONSTANT = 68
NUMBER = 69
VARIABLE = 70
WS = 71
channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ]
@@ -261,32 +271,34 @@ class MathExprLexer(Lexer):
"'ln'", "'log'", "'exp'", "'smin'", "'smax'", "'tmin'", "'tmax'",
"'tnorm'", "'snorm'", "'floor'", "'ceil'", "'round'", "'gamma'",
"'pow'", "'sigm'", "'clamp'", "'fft'", "'ifft'", "'angle'",
"'print'", "'lerp'", "'step'", "'smoothstep'", "'fract'", "'relu'",
"'softplus'", "'gelu'", "'sign'", "'map'", "'conv'", "'swap'",
"'permute'", "'+'", "'-'", "'*'", "'/'", "'%'", "'^'", "'>='",
"'>'", "'<='", "'<'", "'=='", "'!='", "'|'" ]
"'print'", "'print_shape'", "'pshp'", "'lerp'", "'step'", "'smoothstep'",
"'fract'", "'relu'", "'softplus'", "'gelu'", "'sign'", "'map'",
"'conv'", "'swap'", "'permute'", "'+'", "'-'", "'*'", "'/'",
"'%'", "'^'", "'>='", "'>'", "'<='", "'<'", "'=='", "'!='",
"'|'" ]
symbolicNames = [ "<INVALID>",
"SIN", "COS", "TAN", "ASIN", "ACOS", "ATAN", "ATAN2", "SINH",
"COSH", "TANH", "ASINH", "ACOSH", "ATANH", "ABS", "SQRT", "LN",
"LOG", "EXP", "SMIN", "SMAX", "TMIN", "TMAX", "TNORM", "SNORM",
"FLOOR", "CEIL", "ROUND", "GAMMA", "POWE", "SIGM", "CLAMP",
"SFFT", "SIFFT", "ANGL", "PRNT", "LERP", "STEP", "SMOOTHSTEP",
"FRACT", "RELU", "SOFTPLUS", "GELU", "SIGN", "MAP", "CONV",
"SWAP", "PERM", "PLUS", "MINUS", "MULT", "DIV", "MOD", "POW",
"GE", "GT", "LE", "LT", "EQ", "NE", "PIPE", "CONSTANT", "NUMBER",
"VARIABLE", "WS" ]
"SFFT", "SIFFT", "ANGL", "PRNT", "PRINT_SHAPE_L", "PRINT_SHAPE",
"LERP", "STEP", "SMOOTHSTEP", "FRACT", "RELU", "SOFTPLUS", "GELU",
"SIGN", "MAP", "CONV", "SWAP", "PERM", "PLUS", "MINUS", "MULT",
"DIV", "MOD", "POW", "GE", "GT", "LE", "LT", "EQ", "NE", "PIPE",
"CONSTANT", "NUMBER", "VARIABLE", "WS" ]
ruleNames = [ "T__0", "T__1", "T__2", "T__3", "T__4", "SIN", "COS",
"TAN", "ASIN", "ACOS", "ATAN", "ATAN2", "SINH", "COSH",
"TANH", "ASINH", "ACOSH", "ATANH", "ABS", "SQRT", "LN",
"LOG", "EXP", "SMIN", "SMAX", "TMIN", "TMAX", "TNORM",
"SNORM", "FLOOR", "CEIL", "ROUND", "GAMMA", "POWE", "SIGM",
"CLAMP", "SFFT", "SIFFT", "ANGL", "PRNT", "LERP", "STEP",
"SMOOTHSTEP", "FRACT", "RELU", "SOFTPLUS", "GELU", "SIGN",
"MAP", "CONV", "SWAP", "PERM", "PLUS", "MINUS", "MULT",
"DIV", "MOD", "POW", "GE", "GT", "LE", "LT", "EQ", "NE",
"PIPE", "CONSTANT", "NUMBER", "VARIABLE", "WS" ]
"CLAMP", "SFFT", "SIFFT", "ANGL", "PRNT", "PRINT_SHAPE_L",
"PRINT_SHAPE", "LERP", "STEP", "SMOOTHSTEP", "FRACT",
"RELU", "SOFTPLUS", "GELU", "SIGN", "MAP", "CONV", "SWAP",
"PERM", "PLUS", "MINUS", "MULT", "DIV", "MOD", "POW",
"GE", "GT", "LE", "LT", "EQ", "NE", "PIPE", "CONSTANT",
"NUMBER", "VARIABLE", "WS" ]
grammarFileName = "MathExpr.g4"
+58 -54
View File
@@ -38,35 +38,37 @@ SFFT=37
SIFFT=38
ANGL=39
PRNT=40
LERP=41
STEP=42
SMOOTHSTEP=43
FRACT=44
RELU=45
SOFTPLUS=46
GELU=47
SIGN=48
MAP=49
CONV=50
SWAP=51
PERM=52
PLUS=53
MINUS=54
MULT=55
DIV=56
MOD=57
POW=58
GE=59
GT=60
LE=61
LT=62
EQ=63
NE=64
PIPE=65
CONSTANT=66
NUMBER=67
VARIABLE=68
WS=69
PRINT_SHAPE_L=41
PRINT_SHAPE=42
LERP=43
STEP=44
SMOOTHSTEP=45
FRACT=46
RELU=47
SOFTPLUS=48
GELU=49
SIGN=50
MAP=51
CONV=52
SWAP=53
PERM=54
PLUS=55
MINUS=56
MULT=57
DIV=58
MOD=59
POW=60
GE=61
GT=62
LE=63
LT=64
EQ=65
NE=66
PIPE=67
CONSTANT=68
NUMBER=69
VARIABLE=70
WS=71
'('=1
')'=2
'['=3
@@ -107,28 +109,30 @@ WS=69
'ifft'=38
'angle'=39
'print'=40
'lerp'=41
'step'=42
'smoothstep'=43
'fract'=44
'relu'=45
'softplus'=46
'gelu'=47
'sign'=48
'map'=49
'conv'=50
'swap'=51
'permute'=52
'+'=53
'-'=54
'*'=55
'/'=56
'%'=57
'^'=58
'>='=59
'>'=60
'<='=61
'<'=62
'=='=63
'!='=64
'|'=65
'print_shape'=41
'pshp'=42
'lerp'=43
'step'=44
'smoothstep'=45
'fract'=46
'relu'=47
'softplus'=48
'gelu'=49
'sign'=50
'map'=51
'conv'=52
'swap'=53
'permute'=54
'+'=55
'-'=56
'*'=57
'/'=58
'%'=59
'^'=60
'>='=61
'>'=62
'<='=63
'<'=64
'=='=65
'!='=66
'|'=67
+9
View File
@@ -584,6 +584,15 @@ class MathExprListener(ParseTreeListener):
pass
# Enter a parse tree produced by MathExprParser#PrintShapeFunc.
def enterPrintShapeFunc(self, ctx:MathExprParser.PrintShapeFuncContext):
pass
# Exit a parse tree produced by MathExprParser#PrintShapeFunc.
def exitPrintShapeFunc(self, ctx:MathExprParser.PrintShapeFuncContext):
pass
# Enter a parse tree produced by MathExprParser#PowFunc.
def enterPowFunc(self, ctx:MathExprParser.PowFuncContext):
pass
File diff suppressed because it is too large Load Diff
+5
View File
@@ -329,6 +329,11 @@ class MathExprVisitor(ParseTreeVisitor):
return self.visitChildren(ctx)
# Visit a parse tree produced by MathExprParser#PrintShapeFunc.
def visitPrintShapeFunc(self, ctx:MathExprParser.PrintShapeFuncContext):
return self.visitChildren(ctx)
# Visit a parse tree produced by MathExprParser#PowFunc.
def visitPowFunc(self, ctx:MathExprParser.PowFuncContext):
return self.visitChildren(ctx)
+45 -59
View File
@@ -2,6 +2,7 @@ import torch
import torch.special
from .MathExprVisitor import MathExprVisitor
from ..helper_functions import generate_dim_variables
class TensorEvalVisitor(MathExprVisitor):
def __init__(self, variables, shape, device=None):
@@ -290,7 +291,6 @@ class TensorEvalVisitor(MathExprVisitor):
self.variables[f'F_dim{dim_idx}'] = float(size_d)
k_components.append(values)
# Calculate isotropic K (Euclidean distance from DC)
k_sq_sum = torch.zeros(self.shape, device=device)
for k_val in k_components:
@@ -302,6 +302,7 @@ class TensorEvalVisitor(MathExprVisitor):
# Legacy aliases
if 'Kx' in self.variables:
self.variables['frequency_count'] = self.variables.get('Fx', 1.0)
self.variables = self.variables | generate_dim_variables(values)
try:
val = self.visit(ctx.expr())
@@ -377,78 +378,57 @@ class TensorEvalVisitor(MathExprVisitor):
coords = [self.visit(ctx.expr(i)) for i in range(1, len(ctx.expr()))]
num_coords = len(coords)
if num_coords == 0:
return tensor
if num_coords == 0: return tensor
if num_coords > 3:
raise ValueError("map() supports max 3 mapping functions.")
is_1d = (num_coords == 1)
if is_1d:
tensor = tensor.unsqueeze(-2)
zeros = torch.zeros_like(coords[0])
coords.append(zeros)
working_num_coords = len(coords)
spatial_in_shape = tensor.shape[-working_num_coords:]
leading_shape = tensor.shape[:-working_num_coords]
spatial_in_shape = tensor.shape[-num_coords:]
leading_shape = tensor.shape[:-num_coords]
batch_size = 1
for s in leading_shape:
batch_size *= s
for s in leading_shape: batch_size *= s
if len(leading_shape) == 0:
input_view = tensor.view(1, 1, *spatial_in_shape)
else:
input_view = tensor.view(batch_size, 1, *spatial_in_shape)
input_view = tensor.reshape(batch_size, 1, *spatial_in_shape)
norm_coords_list = []
for i, coord in enumerate(coords):
for i in range(num_coords):
dim_size = spatial_in_shape[-(i+1)]
norm = self._normalize_coord(coord, dim_size)
norm = self._normalize_coord(coords[i], dim_size)
norm_coords_list.append(norm)
try:
broadcasted_coords = torch.broadcast_tensors(*norm_coords_list)
except RuntimeError:
raise ValueError(f"map(): Coordinate shapes {[c.shape for c in coords]} cannot be broadcast together.")
grid = torch.stack(broadcasted_coords, dim=-1)
broadcasted = torch.broadcast_tensors(*norm_coords_list)
grid = torch.stack(broadcasted, dim=-1)
grid_spatial_shape = grid.shape[:-1]
is_batched = False
if len(leading_shape) > 0 and len(grid_spatial_shape) >= len(leading_shape):
if grid_spatial_shape[:len(leading_shape)] == leading_shape:
is_batched = True
if batch_size > 1 and not is_batched:
grid = grid.expand(batch_size, *grid.shape)
grid_spatial_shape = grid.shape[1:-1]
elif is_batched:
flatten_shape = (batch_size,) + grid_spatial_shape[len(leading_shape):] + (grid.shape[-1],)
grid = grid.reshape(flatten_shape)
grid_spatial_shape = flatten_shape[1:-1]
total_output_elements = grid.numel() // working_num_coords // batch_size
if working_num_coords == 2:
grid_view = grid.reshape(batch_size, 1, total_output_elements, 2)
output = torch.nn.functional.grid_sample(
input_view, grid_view, mode='bilinear', padding_mode='zeros', align_corners=True
)
elif working_num_coords == 3:
grid_view = grid.reshape(batch_size, 1, 1, total_output_elements, 3)
output = torch.nn.functional.grid_sample(
input_view, grid_view, mode='bilinear', padding_mode='zeros', align_corners=True
)
if grid.numel() // max(2, num_coords) >= batch_size and \
grid.shape[:len(leading_shape)] == leading_shape:
grid_view = grid.reshape(batch_size, -1, num_coords)
else:
raise ValueError(f"map() supports up to 3 coordinate dimensions, got {num_coords} original coords.")
grid_view = grid.expand(batch_size, *([-1] * len(grid_spatial_shape)), -1)
grid_view = grid_view.reshape(batch_size, -1, num_coords)
output = output.view(batch_size, total_output_elements)
if num_coords == 1:
y_zeros = torch.zeros_like(grid_view[..., :1])
grid_final = torch.cat([grid_view, y_zeros], dim=-1).reshape(batch_size, 1, -1, 2)
input_final = input_view.reshape(batch_size, 1, 1, -1)
output = torch.nn.functional.grid_sample(input_final, grid_final, align_corners=True)
elif num_coords == 2:
grid_final = grid_view.reshape(batch_size, 1, -1, 2)
output = torch.nn.functional.grid_sample(input_view, grid_final, align_corners=True)
else: # 3D
grid_final = grid_view.reshape(batch_size, 1, 1, -1, 3)
output = torch.nn.functional.grid_sample(input_view, grid_final, align_corners=True)
actual_spatial = grid_spatial_shape
if len(grid_spatial_shape) >= len(leading_shape) and \
grid_spatial_shape[:len(leading_shape)] == leading_shape:
actual_spatial = grid_spatial_shape[len(leading_shape):]
final_shape = list(leading_shape) + list(actual_spatial)
return output.reshape(final_shape)
final_shape = list(leading_shape) + list(grid_spatial_shape)
output = output.view(final_shape)
return output
def _kernel_coords(self, size, device):
half = size // 2
@@ -499,7 +479,8 @@ class TensorEvalVisitor(MathExprVisitor):
k_variables = self.variables.copy()
k_variables.update({
'kX': kx, 'kY': ky, 'kZ': kz,
'kW': float(kw), 'kH': float(kh), 'kD': float(kd)
'kW': float(kw), 'kH': float(kh), 'kD': float(kd),
'kernel_width': float(kw), 'kernel_height': float(kh), 'kernel_depth': float(kd)
})
k_visitor = TensorEvalVisitor(k_variables, (kd, kh, kw), device=self.device)
@@ -555,3 +536,8 @@ class TensorEvalVisitor(MathExprVisitor):
def visitExpr(self, ctx):
return self.visitChildren(ctx)
def visitPrintShapeFunc(self, ctx):
tsr = self.visit(ctx.expr())
print(tsr.shape)
return tsr
+3 -3
View File
@@ -6,7 +6,7 @@ from comfy_api.util import VideoComponents
import torch
from .helper_functions import getIndexTensorAlongDim, eval_tensor_expr, make_zero_like
from .helper_functions import generate_dim_variables, getIndexTensorAlongDim, eval_tensor_expr, make_zero_like
from .MathNodeBase import MathNodeBase
@@ -76,7 +76,7 @@ class VideoMathNode(MathNodeBase):
'R': float(ac.frame_rate), 'frame_rate': float(ac.frame_rate),
'T': imgs_a.shape[0], 'frame_count': imgs_a.shape[0],
'N': imgs_a.shape[1], 'channel_count': imgs_a.shape[1],
}
} | generate_dim_variables(imgs_a)
result_imgs = eval_tensor_expr(Images, img_vars, imgs_a.shape)
result_imgs = result_imgs.permute(0, 2, 3, 1) # Back to B, H, W, C
@@ -96,7 +96,7 @@ class VideoMathNode(MathNodeBase):
'R': ac.audio['sample_rate'], 'sample_rate': ac.audio['sample_rate'],
'T': audio_a.shape[2], 'sample_count': audio_a.shape[2],
'N': audio_a.shape[1], 'channel_count': audio_a.shape[1],
}
} | generate_dim_variables(audio_a)
result_audio = eval_tensor_expr(Audio, audio_vars, audio_a.shape)
+14 -3
View File
@@ -26,13 +26,13 @@ def parse_expr(expr: str):
def eval_tensor_expr(expr: str, variables: dict, shape: tuple, device=None):
"""Parse and evaluate a tensor math expression.
Args:
expr: Math expression string
variables: Dict of variable names to tensor/scalar values
shape: Shape tuple for the TensorEvalVisitor
device: Optional device override
Returns:
Result tensor from evaluating the expression
"""
@@ -56,7 +56,6 @@ def eval_float_expr(expr: str, variables: dict):
visitor = FloatEvalVisitor(variables)
return visitor.visit(tree)
def eval_float_expr_with_tree(tree, variables: dict):
"""Evaluate a pre-parsed expression tree with FloatEvalVisitor."""
from .Parser.FloatEvalVisitor import FloatEvalVisitor
@@ -87,6 +86,18 @@ def comonLazy(expr, a, b=None, c=None, d=None, w=0.0, x=0.0, y=0.0, z=0.0):
need_eval.append(token.text)
return need_eval
def generate_dim_variables(tensor):
"""Generate index and size tensors for each dimension of the input tensor."""
variables = {}
for dim, size in enumerate(tensor.shape):
variables[f'D{dim}'] = getIndexTensorAlongDim(tensor, dim)
print(tensor)
print(tensor.shape)
print(variables[f'D{dim}'])
print(dim)
print(size)
variables[f'S{dim}'] = torch.full(tensor.shape, fill_value=size, dtype=torch.float32, device=tensor.device)
return variables
def make_zero_like(ref):
"""