@@ -1,212 +0,0 @@
|
||||
# Function Consistency Check: README.md vs MathExpr.g4
|
||||
|
||||
## Executive Summary
|
||||
✅ **All documented functions have grammar rules defined**
|
||||
✅ **All grammar functions have documentation**
|
||||
⚠️ **Minor discrepancies in aliases and function naming**
|
||||
|
||||
## Functions in README but Need Verification in Grammar
|
||||
|
||||
### ✅ Verified - All Present
|
||||
|
||||
#### Basic Math (All Present)
|
||||
- ✅ abs (AbsFunc)
|
||||
- ✅ sqrt (SqrtFunc)
|
||||
- ✅ ln (LnFunc)
|
||||
- ✅ log (LogFunc)
|
||||
- ✅ exp (ExpFunc)
|
||||
- ✅ pow (PowFunc as POWE)
|
||||
- ✅ floor (FloorFunc)
|
||||
- ✅ ceil (CeilFunc)
|
||||
- ✅ round (RoundFunc)
|
||||
- ✅ fract (FractFunc)
|
||||
- ✅ sign (SignFunc)
|
||||
- ✅ gamma (GammaFunc)
|
||||
- ✅ dist/distance (DistFunc)
|
||||
- ✅ clamp (ClampFunc)
|
||||
- ✅ step (StepFunc)
|
||||
|
||||
#### Trigonometric (All Present)
|
||||
- ✅ sin, cos, tan, asin, acos, atan, atan2 (all present)
|
||||
|
||||
#### Hyperbolic (All Present)
|
||||
- ✅ sinh, cosh, tanh, asinh, acosh, atanh (all present)
|
||||
|
||||
#### Machine Learning / Activation (All Present)
|
||||
- ✅ relu (ReluFunc)
|
||||
- ✅ gelu (GeluFunc)
|
||||
- ✅ softplus (SoftplusFunc)
|
||||
- ✅ sigm (SigmoidFunc as SIGM)
|
||||
- ✅ softmax (SoftmaxFunc)
|
||||
- ✅ softmin (SoftminFunc)
|
||||
|
||||
#### Interpolation (All Present)
|
||||
- ✅ smoothstep (SmoothstepFunc)
|
||||
- ✅ smootherstep (SmootherstepFunc)
|
||||
- ✅ cubic_ease/cubic (CubicEaseFunc)
|
||||
- ✅ sine_ease/sine (SineEaseFunc)
|
||||
- ✅ elastic_ease/elastic (ElasticEaseFunc)
|
||||
- ✅ lerp (LerpFunc)
|
||||
|
||||
#### Aggregates & Tensor Operations (All Present)
|
||||
- ✅ tmin (TMinFunc)
|
||||
- ✅ tmax (TMaxFunc)
|
||||
- ✅ smin (SMinFunc)
|
||||
- ✅ smax (SMaxFunc)
|
||||
- ✅ sum (SumFunc)
|
||||
- ✅ mean (MeanFunc)
|
||||
- ✅ std (StdFunc)
|
||||
- ✅ var (VarFunc)
|
||||
- ✅ median (MedianFunc)
|
||||
- ✅ mode (ModeFunc)
|
||||
- ✅ quartile (QuartileFunc)
|
||||
- ✅ percentile (PercentileFunc)
|
||||
- ✅ quantile (QuantileFunc)
|
||||
- ✅ dot (DotFunc)
|
||||
- ✅ moment (MomentFunc)
|
||||
- ✅ topk (TopkFunc)
|
||||
- ✅ botk (BotkFunc)
|
||||
- ✅ topk_ind/topk_indices (TopkIndFunc)
|
||||
- ✅ botk_ind/botk_indices (BotkIndFunc)
|
||||
- ✅ sort (SortFunc)
|
||||
- ✅ argsort (ArgsortFunc)
|
||||
- ✅ argmin (ArgminFunc)
|
||||
- ✅ argmax (ArgmaxFunc)
|
||||
- ✅ unique (UniqueFunc)
|
||||
- ✅ tnorm (TNormFunc)
|
||||
- ✅ snorm (SNormFunc)
|
||||
- ✅ swap (SwapFunc)
|
||||
- ✅ cossim (CossimFunc)
|
||||
- ✅ flip (FlipFunc)
|
||||
- ✅ cov (CovFunc)
|
||||
- ✅ append (AppendFunc)
|
||||
- ✅ any (AnyFunc)
|
||||
- ✅ all (AllFunc)
|
||||
- ✅ cumsum (CumsumFunc)
|
||||
- ✅ cumprod (CumprodFunc)
|
||||
- ✅ tensor (EmptyTensorFunc)
|
||||
- ✅ flatten (FlattenFunc)
|
||||
|
||||
#### Advanced Tensor Operations (All Present)
|
||||
- ✅ map (MapFunc)
|
||||
- ✅ ezconvolution/ezconv (EzConvFunc)
|
||||
- ✅ convolution/conv (ConvFunc)
|
||||
- ✅ get_value (GetValueFunc)
|
||||
- ✅ crop (CropFunc)
|
||||
- ✅ permute/perm (PermuteFunc)
|
||||
- ✅ reshape/rshp (ReshapeFunc)
|
||||
- ✅ blur/gaussian (GaussianFunc)
|
||||
- ✅ edge (EdgeFunc)
|
||||
- ✅ batch_shuffle/shuffle/select (BatchShuffleFunc)
|
||||
- ✅ matmul (MatmulFunc)
|
||||
- ✅ cross (CrossFunc)
|
||||
|
||||
#### Optical Flow (All Present)
|
||||
- ✅ rife (RifeFunc)
|
||||
- ✅ motion_mask (MotionMaskFunc)
|
||||
- ✅ flow_to_image (FlowToImageFunc)
|
||||
- ✅ flow_apply (FlowApplyFunc)
|
||||
|
||||
#### FFT (All Present)
|
||||
- ✅ fft (SFFT)
|
||||
- ✅ ifft (SIFFT)
|
||||
- ✅ angle (ANGL)
|
||||
|
||||
#### Utility (All Present)
|
||||
- ✅ print (PrintFunc as PRNT)
|
||||
- ✅ print_shape/pshp (PrintShapeFunc)
|
||||
- ✅ pinv (PinvFunc)
|
||||
- ✅ range (RangeFunc)
|
||||
- ✅ nan_to_num/nvl (NvlFunc)
|
||||
- ✅ remap (RemapFunc)
|
||||
- ✅ timestamp (TimestampFunc as TIMESTAMP)
|
||||
- ✅ count/length/cnt (CountFunc)
|
||||
|
||||
#### Random Distributions (All Present)
|
||||
- ✅ random_normal/randn/noise (NoiseFunc)
|
||||
- ✅ random_uniform/rand (RandFunc)
|
||||
- ✅ random_exponential/rande (ExponentialFunc)
|
||||
- ✅ random_cauchy/randc (CauchyFunc)
|
||||
- ✅ random_log_normal/randln (LogNormalFunc)
|
||||
- ✅ random_bernoulli/randb (BernoulliFunc)
|
||||
- ✅ random_poisson/randp (PoissonFunc)
|
||||
- ✅ random_gamma/randg (GammaDistFunc)
|
||||
- ✅ random_beta/randbeta (BetaDistFunc)
|
||||
- ✅ random_laplace/randl (LaplaceDistFunc)
|
||||
- ✅ random_gumbel/randgumbel (GumbelDistFunc)
|
||||
- ✅ random_weibull/randw (WeibullDistFunc)
|
||||
- ✅ random_chi2/randchi2 (Chi2DistFunc)
|
||||
- ✅ random_studentt/randt (StudentTDistFunc)
|
||||
|
||||
#### Bitwise Operations (All Present)
|
||||
- ✅ band/bitwise_and (BitAndFunc)
|
||||
- ✅ bor/bitwise_or (BitOrFunc)
|
||||
- ✅ xor/bitwise_xor (BitXorFunc)
|
||||
- ✅ bnot/bitwise_not (BitNotFunc)
|
||||
- ✅ bitcount/popcount/popcnt (BitCountFunc)
|
||||
- ✅ << (LSHIFT)
|
||||
- ✅ >> (RSHIFT)
|
||||
|
||||
#### Stack (All Present)
|
||||
- ✅ stack_push (PushFunc)
|
||||
- ✅ stack_pop (PopFunc)
|
||||
- ✅ stack_get (GetFunc)
|
||||
- ✅ stack_clear (ClearFunc)
|
||||
- ✅ stack_has (HasFunc)
|
||||
|
||||
## Minor Naming Discrepancies
|
||||
|
||||
### README Mentions These Aliases Not Explicitly in Grammar Lexer
|
||||
1. `now` - README mentions as alias for `timestamp`, but only TIMESTAMP: 'timestamp' is in grammar
|
||||
- **Fix Needed**: Add `TIMESTAMP: 'timestamp' | 'now';`
|
||||
|
||||
2. `flow_view` - README mentions as alias for `flow_to_image`
|
||||
- **Fix Needed**: Add to `FLOW_TO_IMAGE: 'flow_to_image' | 'flow_view';`
|
||||
|
||||
3. `apply_flow` - README mentions as alias for `flow_apply`
|
||||
- **Fix Needed**: Add to `FLOW_APPLY: 'flow_apply' | 'apply_flow';`
|
||||
|
||||
4. Bitwise aliases - Should update for consistency:
|
||||
- `BAND: 'band' | 'bitwise_and' | 'bitand';` (currently has 'bitand' as alias)
|
||||
- `BOR: 'bor' | 'bitwise_or' | 'bitor';` (currently has 'bitor' as alias)
|
||||
- `XOR: 'xor' | 'bitwise_xor' | 'xor';` (should add 'bitwise_xor')
|
||||
- `BNOT: 'bnot' | 'bitnot' | 'bitwise_not';` (should add 'bitwise_not')
|
||||
|
||||
## Summary of Issues
|
||||
|
||||
### Critical (Must Fix)
|
||||
None - all documented functions work
|
||||
|
||||
### High Priority (Should Fix)
|
||||
1. Add missing aliases for consistency:
|
||||
- `now` for `timestamp`
|
||||
- `flow_view` for `flow_to_image`
|
||||
- `apply_flow` for `flow_apply`
|
||||
- `bitwise_*` names for bitwise operators
|
||||
|
||||
### Low Priority (Nice to Have)
|
||||
- Documentation in README could list all aliases explicitly
|
||||
|
||||
## Recommended Grammar Updates
|
||||
|
||||
```antlr
|
||||
// Update these lexer rules:
|
||||
TIMESTAMP: 'timestamp' | 'now';
|
||||
FLOW_APPLY: 'flow_apply' | 'apply_flow';
|
||||
FLOW_TO_IMAGE: 'flow_to_image' | 'flow_view';
|
||||
BAND: 'band' | 'bitand' | 'bitwise_and';
|
||||
BOR: 'bor' | 'bitor' | 'bitwise_or';
|
||||
XOR: 'xor' | 'bitwise_xor';
|
||||
BNOT: 'bnot' | 'bitnot' | 'bitwise_not';
|
||||
BITCOUNT: 'bitcount' | 'popcount' | 'popcnt' | 'bitcount';
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
✅ **Status: EXCELLENT CONSISTENCY**
|
||||
- 100% of documented functions have grammar rules
|
||||
- 100% of grammar functions have documentation
|
||||
- Only minor alias discrepancies that don't affect functionality
|
||||
- All core functionality is properly defined and documented
|
||||
|
||||
**Recommendation**: Regenerate parser after applying the minor grammar updates above to ensure all documented aliases work correctly.
|
||||
+2
-8
@@ -1,10 +1,4 @@
|
||||
import traceback
|
||||
|
||||
try:
|
||||
from .more_math.nodes import comfy_entrypoint as comfy_entrypoint
|
||||
except ImportError:
|
||||
print("Something is seriously wrong")
|
||||
traceback.print_exc()
|
||||
from .more_math.nodes import comfy_entrypoint as comfy_entrypoint
|
||||
|
||||
WEB_DIRECTORY = "./web"
|
||||
__all__ = ["comfy_entrypoint", "WEB_DIRECTORY"]
|
||||
__all__ = ["comfy_entrypoint", "WEB_DIRECTORY"]
|
||||
|
||||
@@ -135,7 +135,7 @@ class AudioMathNode(io.ComfyNode):
|
||||
"batch_count": float(a_w.shape[0]),
|
||||
} | generate_dim_variables(a_w) | V_norm_waveforms | sample_rates
|
||||
|
||||
v_stacked, v_cnt = get_v_variable(V_norm_waveforms, length_mismatch=length_mismatch)
|
||||
v_stacked, v_cnt = get_v_variable(V_norm_waveforms)
|
||||
if v_stacked is not None:
|
||||
variables["V"] = v_stacked
|
||||
variables["Vcnt"] = float(v_cnt)
|
||||
@@ -167,6 +167,5 @@ class AudioMathNode(io.ComfyNode):
|
||||
res_list.append({"waveform": result_chunk, "sample_rate": sample_rate})
|
||||
return (res_list, stack)
|
||||
else:
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
|
||||
return ([{"waveform": result, "sample_rate": sample_rate}], stack)
|
||||
|
||||
@@ -147,7 +147,7 @@ class ConditioningMathNode(io.ComfyNode):
|
||||
"batch_count": a.shape[0],
|
||||
} | generate_dim_variables(a) | V_norm_tensors
|
||||
|
||||
v_stacked, v_cnt = get_v_variable(V_norm_tensors, length_mismatch=length_mismatch)
|
||||
v_stacked, v_cnt = get_v_variable(V_norm_tensors)
|
||||
if v_stacked is not None:
|
||||
variables["V"] = v_stacked
|
||||
variables["Vcnt"] = float(v_cnt)
|
||||
@@ -193,7 +193,7 @@ class ConditioningMathNode(io.ComfyNode):
|
||||
"batch_count": a_p.shape[0] if a_p.numel() > 0 else 0,
|
||||
} | generate_dim_variables(a_p) | V_norm_pooled
|
||||
|
||||
v_stacked, v_cnt = get_v_variable(V_norm_pooled, length_mismatch=length_mismatch)
|
||||
v_stacked, v_cnt = get_v_variable(V_norm_pooled)
|
||||
if v_stacked is not None:
|
||||
variables_pi["V"] = v_stacked
|
||||
variables_pi["Vcnt"] = float(v_cnt)
|
||||
@@ -251,5 +251,4 @@ class ConditioningMathNode(io.ComfyNode):
|
||||
base[0] = (rtensor, new_dict)
|
||||
res_list = [base]
|
||||
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return (move_to_device(res_list, original_device),stack)
|
||||
|
||||
@@ -92,7 +92,6 @@ class MathGuider:
|
||||
self.tree1 = expression1
|
||||
self.inner_model = None # Will be set during sample
|
||||
self.sigmas = None
|
||||
self.current_step = 0
|
||||
self.steps = 0
|
||||
self.stck = stack
|
||||
|
||||
@@ -142,7 +141,6 @@ class MathGuider:
|
||||
eval_samples, variables = self.setVars(x, sigma, seed, lazy_g_results)
|
||||
visitor = UnifiedMathVisitor(variables, eval_samples.shape,eval_samples.device,state_storage=self.stck)
|
||||
result_tensor = visitor.visit(self.tree)
|
||||
self.current_step = self.current_step + 1;
|
||||
return as_tensor(result_tensor, eval_samples.shape).to(x.device)
|
||||
|
||||
|
||||
@@ -164,6 +162,13 @@ class MathGuider:
|
||||
|
||||
frame_count = eval_samples.shape[time_dim] if time_dim is not None else 1
|
||||
|
||||
# sigma has one entry per batch item, all equal
|
||||
sigma = float(sigma.flatten()[0]) if isinstance(sigma, torch.Tensor) else sigma
|
||||
current_step = 0
|
||||
if self.sigmas is not None:
|
||||
# Index of the step whose interval contains sigma, so extra model calls within a step (heun, dpmpp_2s, ...) keep the same index
|
||||
current_step = max((i for i, s in enumerate(self.sigmas.tolist()) if s >= sigma), default=0)
|
||||
|
||||
def make_lazy_var(value_fn):
|
||||
value_fn.is_lazy_var = True
|
||||
return value_fn
|
||||
@@ -184,10 +189,10 @@ class MathGuider:
|
||||
"batch_count": float(eval_samples.shape[0]),
|
||||
"N": float(eval_samples.shape[channel_dim]) if channel_dim < ndim else 0.0,
|
||||
"channel_count": float(eval_samples.shape[channel_dim]) if channel_dim < ndim else 0.0,
|
||||
"sigma": sigma.item() if isinstance(sigma,torch.Tensor) else sigma,
|
||||
"sigma": sigma,
|
||||
"seed": seed if seed is not None else 0,
|
||||
"steps": self.steps,
|
||||
"current_step": self.current_step,
|
||||
"current_step": current_step,
|
||||
"sample": x
|
||||
})
|
||||
if g_results is not None:
|
||||
@@ -226,7 +231,7 @@ class MathGuider:
|
||||
|
||||
def sample(self, noise, latent_image, sampler, sigmas, denoise_mask=None, callback=None, disable_pbar=False, seed=None):
|
||||
self.sigmas = sigmas
|
||||
self.steps = len(sigmas)
|
||||
self.steps = len(sigmas) - 1
|
||||
if sigmas.shape[-1] == 0:
|
||||
return latent_image
|
||||
active_guiders = [g for g in self.V.values() if g is not None]
|
||||
|
||||
@@ -129,7 +129,7 @@ class ImageMathNode(io.ComfyNode):
|
||||
# Add all dynamic inputs
|
||||
variables.update(V_norm)
|
||||
|
||||
v_stacked, v_cnt = get_v_variable(V_norm, length_mismatch=length_mismatch)
|
||||
v_stacked, v_cnt = get_v_variable(V_norm)
|
||||
if v_stacked is not None:
|
||||
variables["V"] = v_stacked
|
||||
variables["Vcnt"] = float(v_cnt)
|
||||
@@ -159,8 +159,6 @@ class ImageMathNode(io.ComfyNode):
|
||||
res_list = []
|
||||
for result_chunk in res:
|
||||
res_list.append(result_chunk)
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return (res_list, stack)
|
||||
else:
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return ([result], stack)
|
||||
|
||||
@@ -215,7 +215,7 @@ class LatentMathNode(io.ComfyNode):
|
||||
# Add all dynamic inputs
|
||||
variables.update(V_norm_samples)
|
||||
|
||||
v_stacked, v_cnt = get_v_variable(V_norm_samples, length_mismatch=length_mismatch)
|
||||
v_stacked, v_cnt = get_v_variable(V_norm_samples)
|
||||
if v_stacked is not None:
|
||||
variables["V"] = v_stacked
|
||||
variables["Vcnt"] = float(v_cnt)
|
||||
@@ -242,7 +242,6 @@ class LatentMathNode(io.ComfyNode):
|
||||
if getattr(result_t, "is_nested", False):
|
||||
rl = result_latent.copy()
|
||||
rl["samples"] = result_t
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return (move_to_device([rl], original_device), stack)
|
||||
|
||||
# If the visitor produced a list/tuple, emit each element as a separate latent.
|
||||
@@ -252,7 +251,6 @@ class LatentMathNode(io.ComfyNode):
|
||||
rl = result_latent.copy()
|
||||
rl["samples"] = comp
|
||||
results.append(rl)
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return (move_to_device(results, original_device), stack)
|
||||
|
||||
if batching > 0:
|
||||
@@ -262,9 +260,7 @@ class LatentMathNode(io.ComfyNode):
|
||||
rl = result_latent.copy()
|
||||
rl["samples"] = result_tensor
|
||||
results.append(rl)
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return (move_to_device(results, original_device), stack)
|
||||
rl = result_latent.copy()
|
||||
rl["samples"] = result_t
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return (move_to_device([rl], original_device), stack)
|
||||
|
||||
@@ -108,7 +108,7 @@ class MaskMathNode(io.ComfyNode):
|
||||
"batch_count": float(ae.shape[0]),
|
||||
} | generate_dim_variables(ae)
|
||||
|
||||
v_stacked, v_cnt = get_v_variable(V_norm, length_mismatch=length_mismatch)
|
||||
v_stacked, v_cnt = get_v_variable(V_norm)
|
||||
if v_stacked is not None:
|
||||
variables["V"] = v_stacked
|
||||
variables["Vcnt"] = float(v_cnt)
|
||||
@@ -140,8 +140,6 @@ class MaskMathNode(io.ComfyNode):
|
||||
res_list = []
|
||||
for result_chunk in res:
|
||||
res_list.append(result_chunk)
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return (res_list, stack)
|
||||
else:
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return ([result], stack)
|
||||
|
||||
@@ -73,8 +73,8 @@ class NoiseExecutor:
|
||||
else:
|
||||
self.tree = expr
|
||||
self.stack = stack
|
||||
|
||||
seed = -1
|
||||
# Samplers seed their own noise (ancestral/SDE) from noise.seed, so pass the first input's seed through
|
||||
self.seed = next((v.seed for v in V.values() if v is not None), 0)
|
||||
|
||||
def generate_noise(self, input_latent: torch.Tensor) -> torch.Tensor:
|
||||
samples = input_latent["samples"]
|
||||
|
||||
@@ -1383,7 +1383,7 @@ func3:
|
||||
/**
|
||||
text_image(text, font, size, [max_width], [weight], [rotation_angle], [line_spacing], [italic], [underline]) - renders text to a 2D tensor with values 0-1
|
||||
- text: text to render; line breaks start new lines
|
||||
- font: font name to look up in the system fonts, or a path to a font file
|
||||
- font: font name to look up in the system fonts, or a path to a font file in a system font folder or the ComfyUI input folder
|
||||
- size: font size in pixels
|
||||
- max_width: wrap lines wider than this many pixels (default: 0, no wrapping)
|
||||
- weight: font weight 100-900 as in CSS (default: 400)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,423 +0,0 @@
|
||||
SIN=1
|
||||
COS=2
|
||||
TAN=3
|
||||
ASIN=4
|
||||
ACOS=5
|
||||
ATAN=6
|
||||
ATAN2=7
|
||||
SINH=8
|
||||
COSH=9
|
||||
TANH=10
|
||||
ASINH=11
|
||||
ACOSH=12
|
||||
ATANH=13
|
||||
ABS=14
|
||||
SQRT=15
|
||||
LN=16
|
||||
LOG=17
|
||||
EXP=18
|
||||
SMIN=19
|
||||
SMAX=20
|
||||
TMIN=21
|
||||
TMAX=22
|
||||
TNORM=23
|
||||
SNORM=24
|
||||
FLOOR=25
|
||||
CEIL=26
|
||||
ROUND=27
|
||||
GAMMA=28
|
||||
POWE=29
|
||||
SIGM=30
|
||||
CLAMP=31
|
||||
SFFT=32
|
||||
SIFFT=33
|
||||
ANGL=34
|
||||
PRNT=35
|
||||
PRINT_SHAPE=36
|
||||
NVL=37
|
||||
LERP=38
|
||||
STEP=39
|
||||
SMOOTHSTEP=40
|
||||
FRACT=41
|
||||
RELU=42
|
||||
SOFTPLUS=43
|
||||
GELU=44
|
||||
SIGN=45
|
||||
MAP=46
|
||||
EZCONV=47
|
||||
CONV=48
|
||||
SWAP=49
|
||||
TRANSPOSE=50
|
||||
PERM=51
|
||||
RESHAPE=52
|
||||
RANGE=53
|
||||
LINSPACE=54
|
||||
LOGSPACE=55
|
||||
TOPK=56
|
||||
BOTK=57
|
||||
PINV=58
|
||||
SUM=59
|
||||
MEAN=60
|
||||
STD=61
|
||||
VAR=62
|
||||
QUARTILE=63
|
||||
PERCENTILE=64
|
||||
QUANTILE=65
|
||||
DOT=66
|
||||
MOMENT=67
|
||||
ERF=68
|
||||
ERFINV=69
|
||||
ANY=70
|
||||
ALL=71
|
||||
EDGE=72
|
||||
GAUSSIAN=73
|
||||
MEDIAN=74
|
||||
MODE=75
|
||||
CUMSUM=76
|
||||
CUMPROD=77
|
||||
TOPK_IND=78
|
||||
BOTK_IND=79
|
||||
CUBIC_EASE=80
|
||||
ELASTIC_EASE=81
|
||||
SINE_EASE=82
|
||||
SMOOTHERSTEP=83
|
||||
DIST=84
|
||||
REMAP=85
|
||||
COSSIM=86
|
||||
COUNT=87
|
||||
KEYS=88
|
||||
ENABLE_TRACKING=89
|
||||
DISABLE_TRACKING=90
|
||||
RESET_TRACKING=91
|
||||
GET_CHANGED_KEYS=92
|
||||
GET_ADDED_KEYS=93
|
||||
GET_REMOVED_KEYS=94
|
||||
GET_UNCHANGED_KEYS=95
|
||||
REPEAT=96
|
||||
FLATTEN=97
|
||||
APPEND=98
|
||||
GET_VALUE=99
|
||||
FLOW_APPLY=100
|
||||
BATCH_SHUFFLE=101
|
||||
MOTION_MASK=102
|
||||
FLOW_TO_IMAGE=103
|
||||
FLOW_MAG=104
|
||||
FLOW_ANG=105
|
||||
WHERE=106
|
||||
HISTOGRAM=107
|
||||
OVERLAY=108
|
||||
PAD=109
|
||||
CROSS=110
|
||||
MATMUL=111
|
||||
RIFE=112
|
||||
BNOT=113
|
||||
BITCOUNT=114
|
||||
SHAPE=115
|
||||
BAND=116
|
||||
XOR=117
|
||||
BOR=118
|
||||
TENSOR=119
|
||||
ADD_KEY=120
|
||||
REMOVE_KEY=121
|
||||
PUSH=122
|
||||
POP=123
|
||||
CLEAR=124
|
||||
HAS=125
|
||||
GET=126
|
||||
CONCAT=127
|
||||
STACK=128
|
||||
NONZERO=129
|
||||
INT=130
|
||||
FLOAT=131
|
||||
UPPER=132
|
||||
LOWER=133
|
||||
TRIM=134
|
||||
SPLIT=135
|
||||
JOIN=136
|
||||
SUBSTRING=137
|
||||
FIND=138
|
||||
REPLACE=139
|
||||
DILATE=140
|
||||
ERODE=141
|
||||
MORPH_OPEN=142
|
||||
MORPH_CLOSE=143
|
||||
RGB_TO_OKLAB=144
|
||||
RGB_TO_CIELAB=145
|
||||
OKLAB_TO_RGB=146
|
||||
CIELAB_TO_RGB=147
|
||||
RGB_TO_HSV=148
|
||||
HSV_TO_RGB=149
|
||||
INT_TO_RGB=150
|
||||
RGB_TO_INT=151
|
||||
INTERPOLATE_LINEAR=152
|
||||
INTERPOLATE_AREA=153
|
||||
INTERPOLATE_NEAREST=154
|
||||
TEXT_IMAGE=155
|
||||
AS_NESTED=156
|
||||
SVD=157
|
||||
DIAG=158
|
||||
IF=159
|
||||
ELSE=160
|
||||
WHILE=161
|
||||
FOR=162
|
||||
IN=163
|
||||
BREAK=164
|
||||
CONTINUE=165
|
||||
RETURN=166
|
||||
TIMESTAMP=167
|
||||
SORT=168
|
||||
ARGSORT=169
|
||||
ARGMIN=170
|
||||
ARGMAX=171
|
||||
SOFTMAX=172
|
||||
SOFTMIN=173
|
||||
UNIQUE=174
|
||||
FLIP=175
|
||||
STARTSWITH=176
|
||||
ENDSWITH=177
|
||||
SQUEEZE=178
|
||||
UNSQUEEZE=179
|
||||
ROLL=180
|
||||
COV=181
|
||||
CORR=182
|
||||
ENTROPY=183
|
||||
CROP=184
|
||||
NONE=185
|
||||
COORDS=186
|
||||
GATHER=187
|
||||
SCATTER=188
|
||||
SCATTER_ADD=189
|
||||
NOISE=190
|
||||
RAND=191
|
||||
CAUCHY=192
|
||||
EXPONENTIAL=193
|
||||
LOGNORMAL=194
|
||||
BERNOULLI=195
|
||||
POISSON=196
|
||||
GAMMADIST=197
|
||||
BETADIST=198
|
||||
LAPLACEDIST=199
|
||||
GUMBELDIST=200
|
||||
WEIBULLDIST=201
|
||||
CHI2DIST=202
|
||||
STUDENTTDIST=203
|
||||
PERLIN=204
|
||||
CELLULAR=205
|
||||
PLASMA=206
|
||||
RIDGED=207
|
||||
DOMAIN_WARP=208
|
||||
PLUS=209
|
||||
MINUS=210
|
||||
MULT=211
|
||||
DIV=212
|
||||
MOD=213
|
||||
POW=214
|
||||
LSHIFT=215
|
||||
RSHIFT=216
|
||||
GE=217
|
||||
GT=218
|
||||
LE=219
|
||||
LT=220
|
||||
EQ=221
|
||||
EQUEALS=222
|
||||
PLUS_EQ=223
|
||||
MINUS_EQ=224
|
||||
MULT_EQ=225
|
||||
DIV_EQ=226
|
||||
MOD_EQ=227
|
||||
NE=228
|
||||
PIPE=229
|
||||
LPAREN=230
|
||||
RPAREN=231
|
||||
COMMA=232
|
||||
SEMICOLON=233
|
||||
ARROW=234
|
||||
LBRACKET=235
|
||||
RBRACKET=236
|
||||
QUESTION=237
|
||||
COLON=238
|
||||
LBRACE=239
|
||||
RBRACE=240
|
||||
NUMBER=241
|
||||
CONSTANT=242
|
||||
STRING=243
|
||||
VARIABLE=244
|
||||
SL_COMMENT=245
|
||||
ML_COMMENT=246
|
||||
WS=247
|
||||
'sin'=1
|
||||
'cos'=2
|
||||
'tan'=3
|
||||
'asin'=4
|
||||
'acos'=5
|
||||
'atan'=6
|
||||
'atan2'=7
|
||||
'sinh'=8
|
||||
'cosh'=9
|
||||
'tanh'=10
|
||||
'asinh'=11
|
||||
'acosh'=12
|
||||
'atanh'=13
|
||||
'abs'=14
|
||||
'sqrt'=15
|
||||
'ln'=16
|
||||
'log'=17
|
||||
'exp'=18
|
||||
'smin'=19
|
||||
'smax'=20
|
||||
'tmin'=21
|
||||
'tmax'=22
|
||||
'tnorm'=23
|
||||
'snorm'=24
|
||||
'floor'=25
|
||||
'ceil'=26
|
||||
'round'=27
|
||||
'gamma'=28
|
||||
'pow'=29
|
||||
'sigm'=30
|
||||
'clamp'=31
|
||||
'fft'=32
|
||||
'ifft'=33
|
||||
'angle'=34
|
||||
'print'=35
|
||||
'lerp'=38
|
||||
'step'=39
|
||||
'smoothstep'=40
|
||||
'fract'=41
|
||||
'relu'=42
|
||||
'softplus'=43
|
||||
'gelu'=44
|
||||
'sign'=45
|
||||
'map'=46
|
||||
'swap'=49
|
||||
'range'=53
|
||||
'linspace'=54
|
||||
'logspace'=55
|
||||
'topk'=56
|
||||
'botk'=57
|
||||
'pinv'=58
|
||||
'sum'=59
|
||||
'mean'=60
|
||||
'std'=61
|
||||
'var'=62
|
||||
'quantile'=65
|
||||
'dot'=66
|
||||
'moment'=67
|
||||
'erf'=68
|
||||
'erfinv'=69
|
||||
'any'=70
|
||||
'all'=71
|
||||
'edge'=72
|
||||
'median'=74
|
||||
'mode'=75
|
||||
'cumsum'=76
|
||||
'cumprod'=77
|
||||
'smootherstep'=83
|
||||
'remap'=85
|
||||
'keys'=88
|
||||
'repeat'=96
|
||||
'flatten'=97
|
||||
'append'=98
|
||||
'get_value'=99
|
||||
'flow_apply'=100
|
||||
'motion_mask'=102
|
||||
'flow_to_image'=103
|
||||
'where'=106
|
||||
'overlay'=108
|
||||
'pad'=109
|
||||
'cross'=110
|
||||
'matmul'=111
|
||||
'rife'=112
|
||||
'shape'=115
|
||||
'tensor'=119
|
||||
'add_key'=120
|
||||
'stack_push'=122
|
||||
'stack_pop'=123
|
||||
'stack_clear'=124
|
||||
'stack_has'=125
|
||||
'stack_get'=126
|
||||
'stack'=128
|
||||
'nonzero'=129
|
||||
'int'=130
|
||||
'float'=131
|
||||
'upper'=132
|
||||
'lower'=133
|
||||
'trim'=134
|
||||
'split'=135
|
||||
'join'=136
|
||||
'find'=138
|
||||
'replace'=139
|
||||
'dilate'=140
|
||||
'erode'=141
|
||||
'morph_open'=142
|
||||
'morph_close'=143
|
||||
'rgb_to_oklab'=144
|
||||
'rgb_to_cielab'=145
|
||||
'oklab_to_rgb'=146
|
||||
'cielab_to_rgb'=147
|
||||
'rgb_to_hsv'=148
|
||||
'hsv_to_rgb'=149
|
||||
'int_to_rgb'=150
|
||||
'rgb_to_int'=151
|
||||
'interpolate_linear'=152
|
||||
'interpolate_area'=153
|
||||
'text_image'=155
|
||||
'if'=159
|
||||
'else'=160
|
||||
'while'=161
|
||||
'for'=162
|
||||
'in'=163
|
||||
'break'=164
|
||||
'continue'=165
|
||||
'return'=166
|
||||
'sort'=168
|
||||
'argsort'=169
|
||||
'argmin'=170
|
||||
'argmax'=171
|
||||
'softmax'=172
|
||||
'softmin'=173
|
||||
'unique'=174
|
||||
'flip'=175
|
||||
'startswith'=176
|
||||
'endswith'=177
|
||||
'squeeze'=178
|
||||
'unsqueeze'=179
|
||||
'roll'=180
|
||||
'cov'=181
|
||||
'entropy'=183
|
||||
'crop'=184
|
||||
'gather'=187
|
||||
'scatter'=188
|
||||
'scatter_add'=189
|
||||
'+'=209
|
||||
'-'=210
|
||||
'*'=211
|
||||
'/'=212
|
||||
'%'=213
|
||||
'^'=214
|
||||
'<<'=215
|
||||
'>>'=216
|
||||
'>='=217
|
||||
'>'=218
|
||||
'<='=219
|
||||
'<'=220
|
||||
'=='=221
|
||||
'='=222
|
||||
'+='=223
|
||||
'-='=224
|
||||
'*='=225
|
||||
'/='=226
|
||||
'%='=227
|
||||
'!='=228
|
||||
'|'=229
|
||||
'('=230
|
||||
')'=231
|
||||
','=232
|
||||
';'=233
|
||||
'->'=234
|
||||
'['=235
|
||||
']'=236
|
||||
'?'=237
|
||||
':'=238
|
||||
'{'=239
|
||||
'}'=240
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -1,423 +0,0 @@
|
||||
SIN=1
|
||||
COS=2
|
||||
TAN=3
|
||||
ASIN=4
|
||||
ACOS=5
|
||||
ATAN=6
|
||||
ATAN2=7
|
||||
SINH=8
|
||||
COSH=9
|
||||
TANH=10
|
||||
ASINH=11
|
||||
ACOSH=12
|
||||
ATANH=13
|
||||
ABS=14
|
||||
SQRT=15
|
||||
LN=16
|
||||
LOG=17
|
||||
EXP=18
|
||||
SMIN=19
|
||||
SMAX=20
|
||||
TMIN=21
|
||||
TMAX=22
|
||||
TNORM=23
|
||||
SNORM=24
|
||||
FLOOR=25
|
||||
CEIL=26
|
||||
ROUND=27
|
||||
GAMMA=28
|
||||
POWE=29
|
||||
SIGM=30
|
||||
CLAMP=31
|
||||
SFFT=32
|
||||
SIFFT=33
|
||||
ANGL=34
|
||||
PRNT=35
|
||||
PRINT_SHAPE=36
|
||||
NVL=37
|
||||
LERP=38
|
||||
STEP=39
|
||||
SMOOTHSTEP=40
|
||||
FRACT=41
|
||||
RELU=42
|
||||
SOFTPLUS=43
|
||||
GELU=44
|
||||
SIGN=45
|
||||
MAP=46
|
||||
EZCONV=47
|
||||
CONV=48
|
||||
SWAP=49
|
||||
TRANSPOSE=50
|
||||
PERM=51
|
||||
RESHAPE=52
|
||||
RANGE=53
|
||||
LINSPACE=54
|
||||
LOGSPACE=55
|
||||
TOPK=56
|
||||
BOTK=57
|
||||
PINV=58
|
||||
SUM=59
|
||||
MEAN=60
|
||||
STD=61
|
||||
VAR=62
|
||||
QUARTILE=63
|
||||
PERCENTILE=64
|
||||
QUANTILE=65
|
||||
DOT=66
|
||||
MOMENT=67
|
||||
ERF=68
|
||||
ERFINV=69
|
||||
ANY=70
|
||||
ALL=71
|
||||
EDGE=72
|
||||
GAUSSIAN=73
|
||||
MEDIAN=74
|
||||
MODE=75
|
||||
CUMSUM=76
|
||||
CUMPROD=77
|
||||
TOPK_IND=78
|
||||
BOTK_IND=79
|
||||
CUBIC_EASE=80
|
||||
ELASTIC_EASE=81
|
||||
SINE_EASE=82
|
||||
SMOOTHERSTEP=83
|
||||
DIST=84
|
||||
REMAP=85
|
||||
COSSIM=86
|
||||
COUNT=87
|
||||
KEYS=88
|
||||
ENABLE_TRACKING=89
|
||||
DISABLE_TRACKING=90
|
||||
RESET_TRACKING=91
|
||||
GET_CHANGED_KEYS=92
|
||||
GET_ADDED_KEYS=93
|
||||
GET_REMOVED_KEYS=94
|
||||
GET_UNCHANGED_KEYS=95
|
||||
REPEAT=96
|
||||
FLATTEN=97
|
||||
APPEND=98
|
||||
GET_VALUE=99
|
||||
FLOW_APPLY=100
|
||||
BATCH_SHUFFLE=101
|
||||
MOTION_MASK=102
|
||||
FLOW_TO_IMAGE=103
|
||||
FLOW_MAG=104
|
||||
FLOW_ANG=105
|
||||
WHERE=106
|
||||
HISTOGRAM=107
|
||||
OVERLAY=108
|
||||
PAD=109
|
||||
CROSS=110
|
||||
MATMUL=111
|
||||
RIFE=112
|
||||
BNOT=113
|
||||
BITCOUNT=114
|
||||
SHAPE=115
|
||||
BAND=116
|
||||
XOR=117
|
||||
BOR=118
|
||||
TENSOR=119
|
||||
ADD_KEY=120
|
||||
REMOVE_KEY=121
|
||||
PUSH=122
|
||||
POP=123
|
||||
CLEAR=124
|
||||
HAS=125
|
||||
GET=126
|
||||
CONCAT=127
|
||||
STACK=128
|
||||
NONZERO=129
|
||||
INT=130
|
||||
FLOAT=131
|
||||
UPPER=132
|
||||
LOWER=133
|
||||
TRIM=134
|
||||
SPLIT=135
|
||||
JOIN=136
|
||||
SUBSTRING=137
|
||||
FIND=138
|
||||
REPLACE=139
|
||||
DILATE=140
|
||||
ERODE=141
|
||||
MORPH_OPEN=142
|
||||
MORPH_CLOSE=143
|
||||
RGB_TO_OKLAB=144
|
||||
RGB_TO_CIELAB=145
|
||||
OKLAB_TO_RGB=146
|
||||
CIELAB_TO_RGB=147
|
||||
RGB_TO_HSV=148
|
||||
HSV_TO_RGB=149
|
||||
INT_TO_RGB=150
|
||||
RGB_TO_INT=151
|
||||
INTERPOLATE_LINEAR=152
|
||||
INTERPOLATE_AREA=153
|
||||
INTERPOLATE_NEAREST=154
|
||||
TEXT_IMAGE=155
|
||||
AS_NESTED=156
|
||||
SVD=157
|
||||
DIAG=158
|
||||
IF=159
|
||||
ELSE=160
|
||||
WHILE=161
|
||||
FOR=162
|
||||
IN=163
|
||||
BREAK=164
|
||||
CONTINUE=165
|
||||
RETURN=166
|
||||
TIMESTAMP=167
|
||||
SORT=168
|
||||
ARGSORT=169
|
||||
ARGMIN=170
|
||||
ARGMAX=171
|
||||
SOFTMAX=172
|
||||
SOFTMIN=173
|
||||
UNIQUE=174
|
||||
FLIP=175
|
||||
STARTSWITH=176
|
||||
ENDSWITH=177
|
||||
SQUEEZE=178
|
||||
UNSQUEEZE=179
|
||||
ROLL=180
|
||||
COV=181
|
||||
CORR=182
|
||||
ENTROPY=183
|
||||
CROP=184
|
||||
NONE=185
|
||||
COORDS=186
|
||||
GATHER=187
|
||||
SCATTER=188
|
||||
SCATTER_ADD=189
|
||||
NOISE=190
|
||||
RAND=191
|
||||
CAUCHY=192
|
||||
EXPONENTIAL=193
|
||||
LOGNORMAL=194
|
||||
BERNOULLI=195
|
||||
POISSON=196
|
||||
GAMMADIST=197
|
||||
BETADIST=198
|
||||
LAPLACEDIST=199
|
||||
GUMBELDIST=200
|
||||
WEIBULLDIST=201
|
||||
CHI2DIST=202
|
||||
STUDENTTDIST=203
|
||||
PERLIN=204
|
||||
CELLULAR=205
|
||||
PLASMA=206
|
||||
RIDGED=207
|
||||
DOMAIN_WARP=208
|
||||
PLUS=209
|
||||
MINUS=210
|
||||
MULT=211
|
||||
DIV=212
|
||||
MOD=213
|
||||
POW=214
|
||||
LSHIFT=215
|
||||
RSHIFT=216
|
||||
GE=217
|
||||
GT=218
|
||||
LE=219
|
||||
LT=220
|
||||
EQ=221
|
||||
EQUEALS=222
|
||||
PLUS_EQ=223
|
||||
MINUS_EQ=224
|
||||
MULT_EQ=225
|
||||
DIV_EQ=226
|
||||
MOD_EQ=227
|
||||
NE=228
|
||||
PIPE=229
|
||||
LPAREN=230
|
||||
RPAREN=231
|
||||
COMMA=232
|
||||
SEMICOLON=233
|
||||
ARROW=234
|
||||
LBRACKET=235
|
||||
RBRACKET=236
|
||||
QUESTION=237
|
||||
COLON=238
|
||||
LBRACE=239
|
||||
RBRACE=240
|
||||
NUMBER=241
|
||||
CONSTANT=242
|
||||
STRING=243
|
||||
VARIABLE=244
|
||||
SL_COMMENT=245
|
||||
ML_COMMENT=246
|
||||
WS=247
|
||||
'sin'=1
|
||||
'cos'=2
|
||||
'tan'=3
|
||||
'asin'=4
|
||||
'acos'=5
|
||||
'atan'=6
|
||||
'atan2'=7
|
||||
'sinh'=8
|
||||
'cosh'=9
|
||||
'tanh'=10
|
||||
'asinh'=11
|
||||
'acosh'=12
|
||||
'atanh'=13
|
||||
'abs'=14
|
||||
'sqrt'=15
|
||||
'ln'=16
|
||||
'log'=17
|
||||
'exp'=18
|
||||
'smin'=19
|
||||
'smax'=20
|
||||
'tmin'=21
|
||||
'tmax'=22
|
||||
'tnorm'=23
|
||||
'snorm'=24
|
||||
'floor'=25
|
||||
'ceil'=26
|
||||
'round'=27
|
||||
'gamma'=28
|
||||
'pow'=29
|
||||
'sigm'=30
|
||||
'clamp'=31
|
||||
'fft'=32
|
||||
'ifft'=33
|
||||
'angle'=34
|
||||
'print'=35
|
||||
'lerp'=38
|
||||
'step'=39
|
||||
'smoothstep'=40
|
||||
'fract'=41
|
||||
'relu'=42
|
||||
'softplus'=43
|
||||
'gelu'=44
|
||||
'sign'=45
|
||||
'map'=46
|
||||
'swap'=49
|
||||
'range'=53
|
||||
'linspace'=54
|
||||
'logspace'=55
|
||||
'topk'=56
|
||||
'botk'=57
|
||||
'pinv'=58
|
||||
'sum'=59
|
||||
'mean'=60
|
||||
'std'=61
|
||||
'var'=62
|
||||
'quantile'=65
|
||||
'dot'=66
|
||||
'moment'=67
|
||||
'erf'=68
|
||||
'erfinv'=69
|
||||
'any'=70
|
||||
'all'=71
|
||||
'edge'=72
|
||||
'median'=74
|
||||
'mode'=75
|
||||
'cumsum'=76
|
||||
'cumprod'=77
|
||||
'smootherstep'=83
|
||||
'remap'=85
|
||||
'keys'=88
|
||||
'repeat'=96
|
||||
'flatten'=97
|
||||
'append'=98
|
||||
'get_value'=99
|
||||
'flow_apply'=100
|
||||
'motion_mask'=102
|
||||
'flow_to_image'=103
|
||||
'where'=106
|
||||
'overlay'=108
|
||||
'pad'=109
|
||||
'cross'=110
|
||||
'matmul'=111
|
||||
'rife'=112
|
||||
'shape'=115
|
||||
'tensor'=119
|
||||
'add_key'=120
|
||||
'stack_push'=122
|
||||
'stack_pop'=123
|
||||
'stack_clear'=124
|
||||
'stack_has'=125
|
||||
'stack_get'=126
|
||||
'stack'=128
|
||||
'nonzero'=129
|
||||
'int'=130
|
||||
'float'=131
|
||||
'upper'=132
|
||||
'lower'=133
|
||||
'trim'=134
|
||||
'split'=135
|
||||
'join'=136
|
||||
'find'=138
|
||||
'replace'=139
|
||||
'dilate'=140
|
||||
'erode'=141
|
||||
'morph_open'=142
|
||||
'morph_close'=143
|
||||
'rgb_to_oklab'=144
|
||||
'rgb_to_cielab'=145
|
||||
'oklab_to_rgb'=146
|
||||
'cielab_to_rgb'=147
|
||||
'rgb_to_hsv'=148
|
||||
'hsv_to_rgb'=149
|
||||
'int_to_rgb'=150
|
||||
'rgb_to_int'=151
|
||||
'interpolate_linear'=152
|
||||
'interpolate_area'=153
|
||||
'text_image'=155
|
||||
'if'=159
|
||||
'else'=160
|
||||
'while'=161
|
||||
'for'=162
|
||||
'in'=163
|
||||
'break'=164
|
||||
'continue'=165
|
||||
'return'=166
|
||||
'sort'=168
|
||||
'argsort'=169
|
||||
'argmin'=170
|
||||
'argmax'=171
|
||||
'softmax'=172
|
||||
'softmin'=173
|
||||
'unique'=174
|
||||
'flip'=175
|
||||
'startswith'=176
|
||||
'endswith'=177
|
||||
'squeeze'=178
|
||||
'unsqueeze'=179
|
||||
'roll'=180
|
||||
'cov'=181
|
||||
'entropy'=183
|
||||
'crop'=184
|
||||
'gather'=187
|
||||
'scatter'=188
|
||||
'scatter_add'=189
|
||||
'+'=209
|
||||
'-'=210
|
||||
'*'=211
|
||||
'/'=212
|
||||
'%'=213
|
||||
'^'=214
|
||||
'<<'=215
|
||||
'>>'=216
|
||||
'>='=217
|
||||
'>'=218
|
||||
'<='=219
|
||||
'<'=220
|
||||
'=='=221
|
||||
'='=222
|
||||
'+='=223
|
||||
'-='=224
|
||||
'*='=225
|
||||
'/='=226
|
||||
'%='=227
|
||||
'!='=228
|
||||
'|'=229
|
||||
'('=230
|
||||
')'=231
|
||||
','=232
|
||||
';'=233
|
||||
'->'=234
|
||||
'['=235
|
||||
']'=236
|
||||
'?'=237
|
||||
':'=238
|
||||
'{'=239
|
||||
'}'=240
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@ import math
|
||||
import inspect
|
||||
import weakref
|
||||
import torch.nn.functional as F
|
||||
import folder_paths
|
||||
from comfy.nested_tensor import NestedTensor
|
||||
from comfy.model_management import throw_exception_if_processing_interrupted
|
||||
from comfy.k_diffusion import sampling as k_sampling
|
||||
@@ -156,6 +157,17 @@ _BLEND_MODES = {
|
||||
}
|
||||
|
||||
|
||||
_FLOAT8_DTYPES = {
|
||||
dtype for dtype in (
|
||||
getattr(torch, "float8_e4m3fn", None),
|
||||
getattr(torch, "float8_e4m3fnuz", None),
|
||||
getattr(torch, "float8_e5m2", None),
|
||||
getattr(torch, "float8_e5m2fnuz", None),
|
||||
)
|
||||
if dtype is not None
|
||||
}
|
||||
|
||||
|
||||
def _rec709_luma(r, g, b):
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b
|
||||
|
||||
@@ -190,9 +202,7 @@ def _font_axis_name(axis):
|
||||
return str(name).lower()
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def _system_fonts():
|
||||
"""Index of installed fonts, scanned once per process (fonts installed later need a restart)."""
|
||||
def _font_dirs():
|
||||
if sys.platform == "win32":
|
||||
search_dirs = [os.path.join(os.environ.get("WINDIR", "C:\\Windows"), "Fonts"), os.path.expandvars(r"%LOCALAPPDATA%\Microsoft\Windows\Fonts")]
|
||||
elif sys.platform == "darwin":
|
||||
@@ -205,9 +215,23 @@ def _system_fonts():
|
||||
os.path.expanduser("~/.local/share/fonts"),
|
||||
os.path.expanduser("~/.fonts"),
|
||||
]
|
||||
return list(dict.fromkeys(search_dirs))
|
||||
|
||||
|
||||
def _is_allowed_font_file(path):
|
||||
"""Font files given by path must be in a system font folder or in ComfyUI's input folder."""
|
||||
if not os.path.isfile(path):
|
||||
return False
|
||||
path = os.path.normcase(os.path.realpath(path))
|
||||
roots = _font_dirs() + [folder_paths.get_input_directory()]
|
||||
return any(path.startswith(os.path.normcase(os.path.realpath(root)) + os.sep) for root in roots)
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=1)
|
||||
def _system_fonts():
|
||||
"""Index of installed fonts, scanned once per process (fonts installed later need a restart)."""
|
||||
fonts = []
|
||||
for directory in dict.fromkeys(search_dirs):
|
||||
for directory in _font_dirs():
|
||||
for root, _, files in os.walk(directory):
|
||||
for fname in files:
|
||||
if not fname.lower().endswith((".ttf", ".otf", ".ttc", ".otc")):
|
||||
@@ -419,20 +443,8 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
return torch.full(t,val,device=self.device)
|
||||
return torch.tensor(val, device=self.device)
|
||||
|
||||
@staticmethod
|
||||
def _float8_dtypes():
|
||||
return {
|
||||
dtype for dtype in (
|
||||
getattr(torch, "float8_e4m3fn", None),
|
||||
getattr(torch, "float8_e4m3fnuz", None),
|
||||
getattr(torch, "float8_e5m2", None),
|
||||
getattr(torch, "float8_e5m2fnuz", None),
|
||||
)
|
||||
if dtype is not None
|
||||
}
|
||||
|
||||
def _apply_binary_operation(self, a, b, torch_op, scalar_op):
|
||||
float8_dtypes = self._float8_dtypes()
|
||||
float8_dtypes = _FLOAT8_DTYPES
|
||||
original_dtype = None
|
||||
if self._is_plain_tensor(a) and a.dtype in float8_dtypes:
|
||||
original_dtype = a.dtype
|
||||
@@ -449,7 +461,7 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
|
||||
def _apply_unary_operation(self, value, torch_op, scalar_op):
|
||||
original_dtype = None
|
||||
if self._is_plain_tensor(value) and value.dtype in self._float8_dtypes():
|
||||
if self._is_plain_tensor(value) and value.dtype in _FLOAT8_DTYPES:
|
||||
original_dtype = value.dtype
|
||||
value = value.to(torch.float16)
|
||||
|
||||
@@ -1342,10 +1354,10 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
dims = self._normalize_dims((yield ctx.expr(2)), val.ndim, ctx, "norm dimension")
|
||||
dim = tuple(dims)
|
||||
original_dtype = val.dtype
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
val = val.to(torch.float32)
|
||||
result = torch.linalg.vector_norm(val, ord=p, dim=dim)
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
result = result.to(original_dtype)
|
||||
return result.item() if result.numel() == 1 else result
|
||||
|
||||
@@ -1359,13 +1371,13 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
if eps < 0:
|
||||
raise ValueError(f"{ctx.start.line}:{ctx.start.column}: normalize eps must be non-negative")
|
||||
original_dtype = val.dtype
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
val = val.to(torch.float32)
|
||||
if val.ndim == 0:
|
||||
result = val / torch.linalg.vector_norm(val, ord=p).clamp_min(eps)
|
||||
else:
|
||||
result = F.normalize(val, p=p, dim=dim, eps=eps)
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
result = result.to(original_dtype)
|
||||
return result.tolist() if return_list else result
|
||||
|
||||
@@ -1380,7 +1392,7 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
raise ValueError(f"{ctx.start.line}:{ctx.start.column}: group_norm groups must be positive and divide the channel count {channels}")
|
||||
|
||||
original_dtype = val.dtype
|
||||
float8_dtypes = self._float8_dtypes()
|
||||
float8_dtypes = _FLOAT8_DTYPES
|
||||
if original_dtype in float8_dtypes:
|
||||
val = val.to(torch.float32)
|
||||
|
||||
@@ -1852,7 +1864,7 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
raise ValueError(f"{ctx.start.line}:{ctx.start.column}: slerp expects one vector dimension")
|
||||
dim = dims[0]
|
||||
|
||||
float8_dtypes = self._float8_dtypes()
|
||||
float8_dtypes = _FLOAT8_DTYPES
|
||||
input_dtypes = (a.dtype, b.dtype)
|
||||
output_dtype = next((dtype for dtype in input_dtypes if dtype in float8_dtypes), None)
|
||||
if output_dtype is None:
|
||||
@@ -2313,7 +2325,7 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
def visitRfftFunc(self, ctx):
|
||||
val = self._promote_to_tensor((yield ctx.expr(0)))
|
||||
dim = self._to_int((yield ctx.expr(1)), ctx, "rfft dimension", strict=True) if len(ctx.expr()) > 1 else -1
|
||||
if val.dtype in self._float8_dtypes() or not (val.is_floating_point() or val.is_complex()):
|
||||
if val.dtype in _FLOAT8_DTYPES or not (val.is_floating_point() or val.is_complex()):
|
||||
val = val.to(torch.float32)
|
||||
return torch.fft.rfft(val, dim=dim)
|
||||
|
||||
@@ -2321,7 +2333,7 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
val = self._promote_to_tensor((yield ctx.expr(0)))
|
||||
n = self._to_int((yield ctx.expr(1)), ctx, "irfft length", strict=True) if len(ctx.expr()) > 1 else None
|
||||
dim = self._to_int((yield ctx.expr(2)), ctx, "irfft dimension", strict=True) if len(ctx.expr()) > 2 else -1
|
||||
if val.dtype in self._float8_dtypes():
|
||||
if val.dtype in _FLOAT8_DTYPES:
|
||||
val = val.to(torch.complex64)
|
||||
return torch.fft.irfft(val, n=n, dim=dim)
|
||||
|
||||
@@ -2420,10 +2432,10 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
elif val.ndim > 0:
|
||||
dims = tuple(range(val.ndim))
|
||||
original_dtype = val.dtype
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
val = val.to(torch.float32)
|
||||
result = val if dims is None else torch.logsumexp(val, dim=dims)
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
result = result.to(original_dtype)
|
||||
return result.item() if result.numel() == 1 else result
|
||||
|
||||
@@ -2672,7 +2684,7 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
def visitOuterFunc(self, ctx):
|
||||
a = self._promote_to_tensor((yield ctx.expr(0))).flatten()
|
||||
b = self._promote_to_tensor((yield ctx.expr(1))).flatten()
|
||||
float8_dtypes = self._float8_dtypes()
|
||||
float8_dtypes = _FLOAT8_DTYPES
|
||||
output_dtype = a.dtype if a.dtype in float8_dtypes else b.dtype if b.dtype in float8_dtypes else None
|
||||
if output_dtype is not None:
|
||||
a = a.to(torch.float32)
|
||||
@@ -2685,20 +2697,20 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
if val.ndim < 2 or val.shape[-1] != val.shape[-2]:
|
||||
raise ValueError(f"{ctx.start.line}:{ctx.start.column}: trace expects square matrices")
|
||||
original_dtype = val.dtype
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
val = val.to(torch.float32)
|
||||
result = torch.diagonal(val, dim1=-2, dim2=-1).sum(dim=-1)
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
result = result.to(original_dtype)
|
||||
return result.item() if result.numel() == 1 else result
|
||||
|
||||
def visitDetFunc(self, ctx):
|
||||
val = self._promote_to_tensor((yield ctx.expr()))
|
||||
original_dtype = val.dtype
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
val = val.to(torch.float32)
|
||||
result = torch.linalg.det(val)
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
result = result.to(original_dtype)
|
||||
return result.item() if result.numel() == 1 else result
|
||||
|
||||
@@ -2710,10 +2722,10 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
if not pseudo and val.shape[-1] != val.shape[-2]:
|
||||
raise ValueError(f"{ctx.start.line}:{ctx.start.column}: inv without pseudo requires square matrices")
|
||||
original_dtype = val.dtype
|
||||
if original_dtype in self._float8_dtypes():
|
||||
if original_dtype in _FLOAT8_DTYPES:
|
||||
val = val.to(torch.float32)
|
||||
result = torch.linalg.pinv(val) if pseudo else torch.linalg.inv(val)
|
||||
return result.to(original_dtype) if original_dtype in self._float8_dtypes() else result
|
||||
return result.to(original_dtype) if original_dtype in _FLOAT8_DTYPES else result
|
||||
|
||||
def visitSolveFunc(self, ctx):
|
||||
a = self._promote_to_tensor((yield ctx.expr(0)))
|
||||
@@ -2721,7 +2733,7 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
if a.ndim < 2 or a.shape[-1] != a.shape[-2]:
|
||||
raise ValueError(f"{ctx.start.line}:{ctx.start.column}: solve expects square coefficient matrices")
|
||||
|
||||
float8_dtypes = self._float8_dtypes()
|
||||
float8_dtypes = _FLOAT8_DTYPES
|
||||
output_dtype = a.dtype if a.dtype in float8_dtypes else b.dtype if b.dtype in float8_dtypes else None
|
||||
if a.dtype in float8_dtypes or not (a.is_floating_point() or a.is_complex()):
|
||||
a = a.to(torch.float32)
|
||||
@@ -2736,7 +2748,7 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
if val.ndim < 2:
|
||||
raise ValueError(f"{ctx.start.line}:{ctx.start.column}: matrix_rank expects matrices")
|
||||
original_dtype = val.dtype
|
||||
if original_dtype in self._float8_dtypes() or not (val.is_floating_point() or val.is_complex()):
|
||||
if original_dtype in _FLOAT8_DTYPES or not (val.is_floating_point() or val.is_complex()):
|
||||
val = val.to(torch.float32)
|
||||
tol = (yield ctx.expr(1)) if len(ctx.expr()) > 1 else None
|
||||
if self._is_tensor(tol):
|
||||
@@ -3536,7 +3548,7 @@ class UnifiedMathVisitor(MathExprVisitor):
|
||||
tier = _FONT_WEIGHT_TIERS[bisect.bisect_left((150, 250, 350, 450, 550, 650, 750, 850), weight_val)]
|
||||
synthetic_italic = synthetic_bold = False
|
||||
variation_weight, variation_italic = weight_val, is_italic
|
||||
if os.path.isfile(font_name):
|
||||
if _is_allowed_font_file(font_name):
|
||||
font_path = font_name
|
||||
else:
|
||||
font_path = _find_font(font_name, tier, weight_val, is_italic)
|
||||
|
||||
@@ -264,7 +264,7 @@ INBUILT_FUNCTION_META = {
|
||||
'interpolate_area': {'min_args': 2, 'max_args': 2, 'signature': 'interpolate_area(x, scale)', 'forms': [['x', 'scale']], 'description': 'resizes x [N, C, ...] with area interpolation. A number scales every spatial dimension; a list is the target spatial size', 'details': '', 'params': {'x': 'tensor shaped [N, C, ...] with 1-3 spatial dimensions', 'scale': 'a number scales every spatial dimension; a list gives the target spatial size'}, 'aliases': []},
|
||||
'interpolate_nearest': {'min_args': 2, 'max_args': 2, 'signature': 'interpolate_nearest(x, scale)', 'forms': [['x', 'scale']], 'description': 'resizes x [N, C, ...] with nearest-neighbour interpolation. A number scales every spatial dimension; a list is the target spatial size', 'details': '', 'params': {'x': 'tensor shaped [N, C, ...] with 1-3 spatial dimensions', 'scale': 'a number scales every spatial dimension; a list gives the target spatial size'}, 'aliases': ['interpolate_nearest_exact']},
|
||||
'interpolate_nearest_exact': {'min_args': 2, 'max_args': 2, 'signature': 'interpolate_nearest_exact(x, scale)', 'forms': [['x', 'scale']], 'description': 'resizes x [N, C, ...] with nearest-neighbour interpolation. A number scales every spatial dimension; a list is the target spatial size', 'details': '', 'params': {'x': 'tensor shaped [N, C, ...] with 1-3 spatial dimensions', 'scale': 'a number scales every spatial dimension; a list gives the target spatial size'}, 'aliases': ['interpolate_nearest']},
|
||||
'text_image': {'min_args': 3, 'max_args': 9, 'signature': 'text_image(text, font, size, [max_width], [weight], [rotation_angle], [line_spacing], [italic], [underline])', 'forms': [['text', 'font', 'size', '[max_width]', '[weight]', '[rotation_angle]', '[line_spacing]', '[italic]', '[underline]']], 'description': 'renders text to a 2D tensor with values 0-1', 'details': '', 'params': {'text': 'text to render; line breaks start new lines', 'font': 'font name to look up in the system fonts, or a path to a font file', 'size': 'font size in pixels', 'max_width': 'wrap lines wider than this many pixels (default: 0, no wrapping)', 'weight': 'font weight 100-900 as in CSS (default: 400)', 'rotation_angle': 'rotation in degrees, counter-clockwise (default: 0)', 'line_spacing': 'line distance as a multiple of the line height (default: 1)', 'italic': 'truthy for italic text (default: false)', 'underline': 'truthy to underline the text (default: false)'}, 'aliases': []},
|
||||
'text_image': {'min_args': 3, 'max_args': 9, 'signature': 'text_image(text, font, size, [max_width], [weight], [rotation_angle], [line_spacing], [italic], [underline])', 'forms': [['text', 'font', 'size', '[max_width]', '[weight]', '[rotation_angle]', '[line_spacing]', '[italic]', '[underline]']], 'description': 'renders text to a 2D tensor with values 0-1', 'details': '', 'params': {'text': 'text to render; line breaks start new lines', 'font': 'font name to look up in the system fonts, or a path to a font file in a system font folder or the ComfyUI input folder', 'size': 'font size in pixels', 'max_width': 'wrap lines wider than this many pixels (default: 0, no wrapping)', 'weight': 'font weight 100-900 as in CSS (default: 400)', 'rotation_angle': 'rotation in degrees, counter-clockwise (default: 0)', 'line_spacing': 'line distance as a multiple of the line height (default: 1)', 'italic': 'truthy for italic text (default: false)', 'underline': 'truthy to underline the text (default: false)'}, 'aliases': []},
|
||||
'as_nested_tensor': {'min_args': 1, 'max_args': 1, 'signature': 'as_nested_tensor(values)', 'forms': [['values']], 'description': 'converts a list to a nested tensor (special object containing tensors of different shapes behaving like a tensor)', 'details': '', 'params': {'values': 'list of tensors; their shapes may differ'}, 'aliases': ['as_nested']},
|
||||
'as_nested': {'min_args': 1, 'max_args': 1, 'signature': 'as_nested(values)', 'forms': [['values']], 'description': 'converts a list to a nested tensor (special object containing tensors of different shapes behaving like a tensor)', 'details': '', 'params': {'values': 'list of tensors; their shapes may differ'}, 'aliases': ['as_nested_tensor']},
|
||||
'svd': {'min_args': 1, 'max_args': 2, 'signature': 'svd(x, [full_matrices])', 'forms': [['x', '[full_matrices]']], 'description': 'computes the singular value decomposition of x. Returns a list of 3 tensors U, S, Vh such that x = matmul(matmul(U, diagonal_matrix(S, shape(U))), Vh)', 'details': '', 'params': {'x': 'matrix, or a batch of matrices in the last two dimensions', 'full_matrices': 'truthy to return full-size U and Vh (default: false)'}, 'aliases': ['singular_value_decomposition']},
|
||||
|
||||
@@ -6,25 +6,29 @@ from torchvision.utils import flow_to_image as torchvision_flow_to_image
|
||||
import numpy as np
|
||||
import folder_paths
|
||||
import comfy.utils
|
||||
import comfy.model_management
|
||||
import comfy.model_patcher
|
||||
|
||||
_raft_model = None
|
||||
folder_paths.folder_names_and_paths.setdefault("optical_flow", ([os.path.join(folder_paths.models_dir, "optical_flow")], folder_paths.supported_pt_extensions))
|
||||
|
||||
def get_raft_model(device):
|
||||
global _raft_model
|
||||
if _raft_model is None:
|
||||
# Small (~20MB) and offloaded by model management like any other model, so it is loaded once per process
|
||||
_raft_patcher = None
|
||||
|
||||
def get_raft_model():
|
||||
global _raft_patcher
|
||||
if _raft_patcher is None:
|
||||
names = folder_paths.get_filename_list("optical_flow")
|
||||
model = raft_large(weights=None, progress=False)
|
||||
model.load_state_dict(comfy.utils.load_torch_file(folder_paths.get_full_path_or_raise("optical_flow", names[0]), safe_load=True))
|
||||
_raft_patcher = comfy.model_patcher.ModelPatcher(model.eval(), load_device=comfy.model_management.get_torch_device(), offload_device=comfy.model_management.unet_offload_device())
|
||||
comfy.model_management.load_model_gpu(_raft_patcher)
|
||||
return _raft_patcher.model
|
||||
if names:
|
||||
model = raft_large(weights=None, progress=False)
|
||||
model.load_state_dict(comfy.utils.load_torch_file(folder_paths.get_full_path_or_raise("optical_flow", names[0]), safe_load=True))
|
||||
else:
|
||||
# No local checkpoint: download torchvision's RAFT weights once and keep a copy in models/optical_flow
|
||||
weights = Raft_Large_Weights.DEFAULT
|
||||
model = raft_large(weights=weights, progress=True)
|
||||
save_dir = folder_paths.get_folder_paths("optical_flow")[0]
|
||||
os.makedirs(save_dir, exist_ok=True)
|
||||
torch.save(model.state_dict(), os.path.join(save_dir, os.path.basename(weights.url)))
|
||||
_raft_model = model.to(device).eval()
|
||||
return _raft_model
|
||||
|
||||
def warp(x, flow, padding_mode='reflection'):
|
||||
"""
|
||||
@@ -90,8 +94,8 @@ def get_optical_flow(img1, img2, tiling_size=0, iterations=12, multi_scale=False
|
||||
img1, img2: [H, W, C] or [B, H, W, C]
|
||||
Returns: [B, H, W, 2] flow vectors
|
||||
"""
|
||||
device = img1.device
|
||||
model = get_raft_model(device)
|
||||
model = get_raft_model()
|
||||
device = comfy.model_management.get_torch_device()
|
||||
|
||||
img1_proc = preprocess_image(img1, device)
|
||||
img2_proc = preprocess_image(img2, device)
|
||||
@@ -176,7 +180,7 @@ def get_optical_flow(img1, img2, tiling_size=0, iterations=12, multi_scale=False
|
||||
flow[:, 1] *= float(h) / h_new
|
||||
|
||||
# [B, 2, H, W] -> [B, H, W, 2]
|
||||
return flow.movedim(1, -1)
|
||||
return flow.movedim(1, -1).to(img1.device)
|
||||
|
||||
def calculate_occlusion_mask(flow):
|
||||
"""
|
||||
|
||||
@@ -22,4 +22,4 @@ class ScriptTextInput(io.ComfyNode):
|
||||
|
||||
@classmethod
|
||||
def execute(cls, script):
|
||||
return (remove_dead_code(parse_expr(script)),)
|
||||
return (remove_dead_code(parse_expr.__wrapped__(script)),)
|
||||
|
||||
@@ -69,7 +69,7 @@ class StringMathNode(io.ComfyNode):
|
||||
"z": F.get("F3", 0.0) if F.get("F3") is not None else 0.0
|
||||
}
|
||||
|
||||
v_stacked, v_cnt = get_v_variable(V, length_mismatch="do nothing")
|
||||
v_stacked, v_cnt = get_v_variable(V)
|
||||
if v_stacked is not None:
|
||||
variables["V"] = v_stacked
|
||||
variables["Vcnt"] = float(v_cnt)
|
||||
@@ -105,9 +105,7 @@ class StringMathNode(io.ComfyNode):
|
||||
for start in range(0, len(s), n):
|
||||
yield s[start:start+n]
|
||||
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
return (chunks(result,batching), stack)
|
||||
else:
|
||||
stack = stack if remember_stack else copy.deepcopy(stack)
|
||||
|
||||
return ([result], stack)
|
||||
|
||||
@@ -169,10 +169,10 @@ class VideoMathNode(io.ComfyNode):
|
||||
variables[v_name].is_lazy_var = True
|
||||
|
||||
def lazy_v_stack():
|
||||
return get_v_variable(V_norm, length_mismatch=length_mismatch)[0]
|
||||
return get_v_variable(V_norm)[0]
|
||||
lazy_v_stack.is_lazy_var = True
|
||||
def lazy_v_count():
|
||||
return float(get_v_variable(V_norm, length_mismatch=length_mismatch)[1])
|
||||
return float(get_v_variable(V_norm)[1])
|
||||
lazy_v_count.is_lazy_var = True
|
||||
variables["V"] = lazy_v_stack
|
||||
variables["Vcnt"] = lazy_v_count
|
||||
@@ -251,10 +251,10 @@ class VideoMathNode(io.ComfyNode):
|
||||
variables[v_name].is_lazy_var = True
|
||||
|
||||
def lazy_v_stack():
|
||||
return get_v_variable(V_norm_waveforms, length_mismatch=length_mismatch)[0]
|
||||
return get_v_variable(V_norm_waveforms)[0]
|
||||
lazy_v_stack.is_lazy_var = True
|
||||
def lazy_v_count():
|
||||
return float(get_v_variable(V_norm_waveforms, length_mismatch=length_mismatch)[1])
|
||||
return float(get_v_variable(V_norm_waveforms)[1])
|
||||
lazy_v_count.is_lazy_var = True
|
||||
variables["V"] = lazy_v_stack
|
||||
variables["Vcnt"] = lazy_v_count
|
||||
|
||||
@@ -100,8 +100,7 @@ class NoiseExecutor:
|
||||
self.z = z
|
||||
self.expr = Noise
|
||||
self.tree = parse_expr(Noise)
|
||||
|
||||
seed = -1
|
||||
self.seed = next((n.seed for n in (a, b, c, d) if n is not None), 0)
|
||||
|
||||
def generate_noise(self, input_latent: torch.Tensor) -> torch.Tensor:
|
||||
samples = input_latent["samples"]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import functools
|
||||
|
||||
from antlr4.error.ErrorListener import ErrorListener
|
||||
from antlr4 import InputStream, CommonTokenStream
|
||||
from antlr4.atn.PredictionMode import PredictionMode
|
||||
@@ -66,8 +68,10 @@ def as_tensor(value, shape):
|
||||
return torch.cat(value)
|
||||
|
||||
|
||||
# check_lazy_status and execute both parse the same expression; trees are only read, so they can be shared.
|
||||
@functools.lru_cache(maxsize=64)
|
||||
def parse_expr(expr: str):
|
||||
"""Parse a math expression and return the parse tree."""
|
||||
"""Parse a math expression and return the parse tree. The tree is shared, use parse_expr.__wrapped__ for one you modify."""
|
||||
input_stream = InputStream(expr)
|
||||
lexer = MathExprLexer(input_stream)
|
||||
stream = CommonTokenStream(lexer)
|
||||
@@ -299,7 +303,7 @@ def normalize_to_common_shape(*tensors, mode="pad"):
|
||||
result.append(t.contiguous())
|
||||
return tuple(result)
|
||||
|
||||
def get_v_variable(v_norm_dict, length_mismatch="error"):
|
||||
def get_v_variable(v_norm_dict):
|
||||
"""
|
||||
Collects V0, V1, ... from the dict (ignoring NestedTensor component keys
|
||||
like V0_0, V1_1), and returns them as a list and count.
|
||||
|
||||
+2
-2
@@ -100,7 +100,7 @@ class BoolToIntNode(io.ComfyNode):
|
||||
display_name="Bool -> Int",
|
||||
category="More math/converters",
|
||||
inputs=[
|
||||
io.Boolean.Input(id="value", default=0),
|
||||
io.Boolean.Input(id="value", default=False),
|
||||
],
|
||||
outputs=[
|
||||
io.Int.Output(),
|
||||
@@ -125,7 +125,7 @@ class IntToBoolNode(io.ComfyNode):
|
||||
category="More math/converters",
|
||||
display_name="Int -> bool",
|
||||
inputs=[
|
||||
io.Int.Input(id="value", default=0.0),
|
||||
io.Int.Input(id="value", default=0),
|
||||
],
|
||||
outputs=[
|
||||
io.Boolean.Output(),
|
||||
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
antlr4-python3-runtime
|
||||
torch
|
||||
pillow
|
||||
pillow
|
||||
numpy
|
||||
scipy
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Quick test to verify bitwise operations work with tensors"""
|
||||
import sys
|
||||
sys.path.insert(0, r'D:\stability\Data\Packages\ComfyUI')
|
||||
|
||||
import torch
|
||||
from custom_nodes.more_math.more_math.Parser.UnifiedMathVisitor import UnifiedMathVisitor
|
||||
|
||||
def test_bitwise_xor_float():
|
||||
"""Test XOR with float tensors (the reported bug)"""
|
||||
print("Testing bitwise XOR with float tensors...")
|
||||
|
||||
# Create float tensors (this was causing the error)
|
||||
a = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32)
|
||||
b = torch.tensor([4.0, 5.0, 6.0], dtype=torch.float32)
|
||||
|
||||
visitor = UnifiedMathVisitor({"a": a, "b": b})
|
||||
|
||||
try:
|
||||
# This should convert to int64, perform XOR, then convert back
|
||||
result = visitor._bitwise_op(a, b, torch.bitwise_xor, lambda x, y: x ^ y)
|
||||
print("✓ XOR succeeded!")
|
||||
print(f" Input a (float32): {a}")
|
||||
print(f" Input b (float32): {b}")
|
||||
print(f" Result: {result}")
|
||||
print(f" Result dtype: {result.dtype}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ XOR failed: {e}")
|
||||
return False
|
||||
|
||||
def test_bitwise_and_float():
|
||||
"""Test AND with float tensors"""
|
||||
print("\nTesting bitwise AND with float tensors...")
|
||||
|
||||
a = torch.tensor([15.0, 14.0, 13.0], dtype=torch.float32)
|
||||
b = torch.tensor([7.0, 3.0, 1.0], dtype=torch.float32)
|
||||
|
||||
visitor = UnifiedMathVisitor({"a": a, "b": b})
|
||||
|
||||
try:
|
||||
result = visitor._bitwise_op(a, b, torch.bitwise_and, lambda x, y: x & y)
|
||||
print("✓ AND succeeded!")
|
||||
print(f" Input a (float32): {a}")
|
||||
print(f" Input b (float32): {b}")
|
||||
print(f" Result: {result}")
|
||||
print(f" Result dtype: {result.dtype}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ AND failed: {e}")
|
||||
return False
|
||||
|
||||
def test_bitwise_or_float():
|
||||
"""Test OR with float tensors"""
|
||||
print("\nTesting bitwise OR with float tensors...")
|
||||
|
||||
a = torch.tensor([15.0, 14.0, 13.0], dtype=torch.float32)
|
||||
b = torch.tensor([7.0, 3.0, 1.0], dtype=torch.float32)
|
||||
|
||||
visitor = UnifiedMathVisitor({"a": a, "b": b})
|
||||
|
||||
try:
|
||||
result = visitor._bitwise_op(a, b, torch.bitwise_or, lambda x, y: x | y)
|
||||
print("✓ OR succeeded!")
|
||||
print(f" Input a (float32): {a}")
|
||||
print(f" Input b (float32): {b}")
|
||||
print(f" Result: {result}")
|
||||
print(f" Result dtype: {result.dtype}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ OR failed: {e}")
|
||||
return False
|
||||
|
||||
def test_bitwise_not_float():
|
||||
"""Test NOT with float tensors"""
|
||||
print("\nTesting bitwise NOT with float tensors...")
|
||||
|
||||
a = torch.tensor([1.0, 2.0, 3.0], dtype=torch.float32)
|
||||
|
||||
visitor = UnifiedMathVisitor({"a": a})
|
||||
|
||||
try:
|
||||
result = visitor._bitwise_not(a)
|
||||
print("✓ NOT succeeded!")
|
||||
print(f" Input a (float32): {a}")
|
||||
print(f" Result: {result}")
|
||||
print(f" Result dtype: {result.dtype}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ NOT failed: {e}")
|
||||
return False
|
||||
|
||||
def test_int_tensors_preserved():
|
||||
"""Ensure int tensors still work as before"""
|
||||
print("\nTesting that int tensor dtypes are preserved...")
|
||||
|
||||
a = torch.tensor([15, 14, 13], dtype=torch.int16)
|
||||
b = torch.tensor([7, 3, 1], dtype=torch.int16)
|
||||
|
||||
visitor = UnifiedMathVisitor({"a": a, "b": b})
|
||||
|
||||
try:
|
||||
result = visitor._bitwise_op(a, b, torch.bitwise_and, lambda x, y: x & y)
|
||||
assert result.dtype == torch.int16, f"Expected int16, got {result.dtype}"
|
||||
print("✓ Int16 dtype preserved!")
|
||||
print(f" Input a (int16): {a}")
|
||||
print(f" Input b (int16): {b}")
|
||||
print(f" Result (int16): {result}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"✗ Int16 test failed: {e}")
|
||||
return False
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("=" * 70)
|
||||
print("Bitwise Operations Fix Verification")
|
||||
print("=" * 70)
|
||||
|
||||
results = [
|
||||
test_bitwise_xor_float(),
|
||||
test_bitwise_and_float(),
|
||||
test_bitwise_or_float(),
|
||||
test_bitwise_not_float(),
|
||||
test_int_tensors_preserved(),
|
||||
]
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
if all(results):
|
||||
print("✓ All tests passed!")
|
||||
else:
|
||||
print("✗ Some tests failed")
|
||||
sys.exit(1)
|
||||
print("=" * 70)
|
||||
@@ -1,170 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test bitwise shift operators and bit count function
|
||||
"""
|
||||
import torch
|
||||
import sys
|
||||
sys.path.insert(0, 'custom_nodes/more_math')
|
||||
|
||||
from more_math.Parser.MathExprParser import MathExprParser
|
||||
from more_math.Parser.UnifiedMathVisitor import UnifiedMathVisitor
|
||||
from antlr4 import InputStream, CommonTokenFactory
|
||||
|
||||
def parse_and_evaluate(expression, variables=None):
|
||||
"""Parse and evaluate a math expression"""
|
||||
if variables is None:
|
||||
variables = {}
|
||||
|
||||
input_stream = InputStream(expression)
|
||||
lexer = MathExprParser(input_stream).lexer
|
||||
stream = CommonTokenFactory()
|
||||
parser = MathExprParser(input_stream)
|
||||
tree = parser.start()
|
||||
|
||||
visitor = UnifiedMathVisitor(variables, device='cpu')
|
||||
result = visitor.visit(tree)
|
||||
return result
|
||||
|
||||
def test_bit_shifts():
|
||||
"""Test bitwise shift operators"""
|
||||
print("=" * 60)
|
||||
print("Testing Bitwise Shift Operators")
|
||||
print("=" * 60)
|
||||
|
||||
test_cases = [
|
||||
# Left shift: 5 << 2 = 20 (0101 << 2 = 10100)
|
||||
("5 << 2", {}, 20),
|
||||
|
||||
# Right shift: 20 >> 2 = 5 (10100 >> 2 = 0101)
|
||||
("20 >> 2", {}, 5),
|
||||
|
||||
# Left shift with variable
|
||||
("x << 3", {"x": 4}, 32), # 4 << 3 = 32
|
||||
|
||||
# Right shift with variable
|
||||
("x >> 2", {"x": 16}, 4), # 16 >> 2 = 4
|
||||
|
||||
# Chained shifts
|
||||
("(8 << 2) >> 3", {}, 4), # (32) >> 3 = 4
|
||||
]
|
||||
|
||||
for expr, vars, expected in test_cases:
|
||||
try:
|
||||
result = parse_and_evaluate(expr, vars)
|
||||
status = "✓" if result == expected else "✗"
|
||||
print(f"{status} {expr:30} = {result:10} (expected {expected})")
|
||||
except Exception as e:
|
||||
print(f"✗ {expr:30} ERROR: {e}")
|
||||
|
||||
def test_bit_count():
|
||||
"""Test bit count function"""
|
||||
print("\n" + "=" * 60)
|
||||
print("Testing Bitwise Bit Count Function")
|
||||
print("=" * 60)
|
||||
|
||||
test_cases = [
|
||||
# bitcount(5) = 2 (0101 has 2 set bits)
|
||||
("bitcount(5)", {}, 2),
|
||||
|
||||
# bitcount(15) = 4 (1111 has 4 set bits)
|
||||
("bitcount(15)", {}, 4),
|
||||
|
||||
# bitcount(7) = 3 (111 has 3 set bits)
|
||||
("bitcount(7)", {}, 3),
|
||||
|
||||
# bitcount(255) = 8 (11111111 has 8 set bits)
|
||||
("bitcount(255)", {}, 8),
|
||||
|
||||
# bitcount(0) = 0
|
||||
("bitcount(0)", {}, 0),
|
||||
|
||||
# With variable
|
||||
("bitcount(x)", {"x": 31}, 5), # 31 = 11111 = 5 bits set
|
||||
]
|
||||
|
||||
for expr, vars, expected in test_cases:
|
||||
try:
|
||||
result = parse_and_evaluate(expr, vars)
|
||||
status = "✓" if result == expected else "✗"
|
||||
print(f"{status} {expr:30} = {result:10} (expected {expected})")
|
||||
except Exception as e:
|
||||
print(f"✗ {expr:30} ERROR: {e}")
|
||||
|
||||
def test_bit_shifts_with_tensors():
|
||||
"""Test bitwise shifts with tensors"""
|
||||
print("\n" + "=" * 60)
|
||||
print("Testing Bitwise Shifts with Tensors")
|
||||
print("=" * 60)
|
||||
|
||||
vars = {
|
||||
"a": torch.tensor([1, 2, 4, 8], dtype=torch.int32),
|
||||
"shift": 2,
|
||||
}
|
||||
|
||||
try:
|
||||
result = parse_and_evaluate("a << shift", vars)
|
||||
expected = torch.tensor([4, 8, 16, 32], dtype=torch.int32)
|
||||
match = torch.equal(result, expected)
|
||||
status = "✓" if match else "✗"
|
||||
print(f"{status} tensor_shift_left: [1,2,4,8] << 2 = {result.tolist()}")
|
||||
except Exception as e:
|
||||
print(f"✗ tensor_shift_left ERROR: {e}")
|
||||
|
||||
try:
|
||||
result = parse_and_evaluate("a >> shift", vars)
|
||||
expected = torch.tensor([0, 0, 1, 2], dtype=torch.int32)
|
||||
match = torch.equal(result, expected)
|
||||
status = "✓" if match else "✗"
|
||||
print(f"{status} tensor_shift_right: [1,2,4,8] >> 2 = {result.tolist()}")
|
||||
except Exception as e:
|
||||
print(f"✗ tensor_shift_right ERROR: {e}")
|
||||
|
||||
def test_bit_count_with_tensors():
|
||||
"""Test bit count with tensors"""
|
||||
print("\n" + "=" * 60)
|
||||
print("Testing Bit Count with Tensors")
|
||||
print("=" * 60)
|
||||
|
||||
vars = {
|
||||
"nums": torch.tensor([5, 15, 7, 255], dtype=torch.int32),
|
||||
}
|
||||
|
||||
try:
|
||||
result = parse_and_evaluate("bitcount(nums)", vars)
|
||||
# Expected: [2, 4, 3, 8] set bits
|
||||
print(f"✓ bitcount([5,15,7,255]): {result}")
|
||||
except Exception as e:
|
||||
print(f"✗ bitcount_tensor ERROR: {e}")
|
||||
|
||||
def test_combinations():
|
||||
"""Test combinations of shift and bit count"""
|
||||
print("\n" + "=" * 60)
|
||||
print("Testing Combinations")
|
||||
print("=" * 60)
|
||||
|
||||
test_cases = [
|
||||
# Shift then count bits
|
||||
("bitcount(5 << 2)", {}, 2), # 5 << 2 = 20 (10100) = 2 bits
|
||||
|
||||
# Combined with other operators
|
||||
("(5 << 2) | (3 << 4)", {}, 0xCC), # 20 | 48 = 0xCC = 204
|
||||
]
|
||||
|
||||
for expr, vars, expected in test_cases:
|
||||
try:
|
||||
result = parse_and_evaluate(expr, vars)
|
||||
status = "✓" if result == expected else "✗"
|
||||
print(f"{status} {expr:35} = {result:10} (expected {expected})")
|
||||
except Exception as e:
|
||||
print(f"✗ {expr:35} ERROR: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_bit_shifts()
|
||||
test_bit_count()
|
||||
test_bit_shifts_with_tensors()
|
||||
test_bit_count_with_tensors()
|
||||
test_combinations()
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("All tests completed!")
|
||||
print("=" * 60)
|
||||
@@ -9,7 +9,7 @@ from more_math.helper_functions import parse_expr, checkLazyNew
|
||||
|
||||
|
||||
def run(script, variables=None, optimize=True, stack=None):
|
||||
tree = parse_expr(script)
|
||||
tree = parse_expr.__wrapped__(script)
|
||||
if optimize:
|
||||
remove_dead_code(tree)
|
||||
out = io.StringIO()
|
||||
@@ -109,5 +109,5 @@ def test_last_statement_of_a_block_stays():
|
||||
|
||||
|
||||
def test_unused_inputs_are_no_longer_requested():
|
||||
tree = remove_dead_code(parse_expr("u = V1 * 2; V0"))
|
||||
tree = remove_dead_code(parse_expr.__wrapped__("u = V1 * 2; V0"))
|
||||
assert checkLazyNew(tree, {"V0": None, "V1": None}, {}) == {"V0"}
|
||||
|
||||
@@ -102,6 +102,16 @@ class TestMathGuider(unittest.TestCase):
|
||||
# At step 2 with 2 steps: 2 / 2 = 1.0
|
||||
self.assertTrue(torch.allclose(res2, torch.tensor(1.0)))
|
||||
|
||||
def test_math_guider_batched_sigma_and_substeps(self):
|
||||
# Samplers pass sigma with one entry per batch item; heun-like samplers also call the model between sigmas
|
||||
math_guider = MathGuider({"V0": MockGuider(1.0)}, {}, "current_step + sigma * 0", "V0", {})
|
||||
math_guider.sigmas = torch.tensor([10.0, 5.0, 0.0])
|
||||
math_guider.steps = 2
|
||||
x = torch.zeros((2, 1, 1, 1))
|
||||
self.assertTrue(torch.allclose(math_guider(x, torch.tensor([5.0, 5.0])), torch.tensor(1.0)))
|
||||
self.assertTrue(torch.allclose(math_guider(x, torch.tensor([7.0, 7.0])), torch.tensor(0.0)))
|
||||
self.assertTrue(torch.allclose(math_guider(x, torch.tensor([10.0, 10.0])), torch.tensor(0.0)))
|
||||
|
||||
def test_math_guider_crop_function(self):
|
||||
"""Test crop function within guider context"""
|
||||
g0 = MockGuider(1.0)
|
||||
|
||||
@@ -360,6 +360,7 @@ def test_noise_math_5d():
|
||||
class MockNoise:
|
||||
def __init__(self, tensor):
|
||||
self.tensor = tensor
|
||||
self.seed = 0
|
||||
|
||||
def generate_noise(self, input_latent):
|
||||
return self.tensor
|
||||
@@ -382,6 +383,7 @@ def test_noise_math_autogrow():
|
||||
class MockNoise:
|
||||
def __init__(self, tensor):
|
||||
self.tensor = tensor
|
||||
self.seed = 0
|
||||
|
||||
def generate_noise(self, input_latent):
|
||||
return self.tensor
|
||||
|
||||
@@ -9,6 +9,9 @@ from PIL import ImageFont
|
||||
from more_math.Parser.UnifiedMathVisitor import ChangeTrackingDict, MathDict, UnifiedMathVisitor
|
||||
from more_math.helper_functions import checkLazyNew, parse_expr
|
||||
from more_math.FloatMathNode import FloatMathNode
|
||||
from more_math.ImageMathNode import ImageMathNode
|
||||
from more_math.LatentMathNode import LatentMathNode
|
||||
from more_math.MaskMathNode import MaskMathNode
|
||||
|
||||
|
||||
def _visit(expression, variables):
|
||||
@@ -80,17 +83,12 @@ def test_lambda_calls_require_exact_argument_count(call):
|
||||
def test_text_image_size_expression_is_evaluated_once(monkeypatch):
|
||||
visitor_module = importlib.import_module("more_math.Parser.UnifiedMathVisitor")
|
||||
default_font = ImageFont.load_default()
|
||||
original_isfile = os.path.isfile
|
||||
monkeypatch.setattr(
|
||||
visitor_module.ImageFont,
|
||||
"truetype",
|
||||
lambda *args, **kwargs: default_font,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
visitor_module.os.path,
|
||||
"isfile",
|
||||
lambda path: path == "mock-font" or original_isfile(path),
|
||||
)
|
||||
monkeypatch.setattr(visitor_module, "_is_allowed_font_file", lambda path: path == "mock-font")
|
||||
|
||||
values = MathDict()
|
||||
_visit(
|
||||
@@ -101,6 +99,15 @@ def test_text_image_size_expression_is_evaluated_once(monkeypatch):
|
||||
assert len(values) == 1
|
||||
|
||||
|
||||
def test_text_image_rejects_font_path_outside_font_folders(monkeypatch):
|
||||
visitor_module = importlib.import_module("more_math.Parser.UnifiedMathVisitor")
|
||||
monkeypatch.setattr(visitor_module, "_find_font", lambda *args: None)
|
||||
path = os.path.abspath(__file__).replace("\\", "/")
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
_visit(f'text_image("x", "{path}", 12)', {})
|
||||
|
||||
|
||||
def test_stack_list_of_tensors_with_negative_dimension():
|
||||
first = torch.tensor([1.0, 2.0])
|
||||
second = torch.tensor([3.0, 4.0])
|
||||
@@ -280,6 +287,28 @@ def test_unconnected_stack_is_not_shared_between_runs():
|
||||
assert stack == {0: [1.0]}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("node, value, extra", [
|
||||
(ImageMathNode, torch.zeros(2, 4, 4, 3), {"use_compute_device": False}),
|
||||
(MaskMathNode, torch.zeros(2, 4, 4), {}),
|
||||
(LatentMathNode, {"samples": torch.zeros(2, 4, 4, 4)}, {"use_compute_device": False}),
|
||||
])
|
||||
@pytest.mark.parametrize("batching", [0, 1])
|
||||
def test_stack_across_list_runs(node, value, extra, batching):
|
||||
# ComfyUI runs the node once per list item and passes the same stack object every time
|
||||
def run(stack, remember):
|
||||
return node.execute(V={"V0": value}, F={}, Expression="stack_push(0, 1); V0", batching=batching, remember_stack=remember, stack=stack, **extra)[-1]
|
||||
|
||||
shared = {}
|
||||
run(shared, True)
|
||||
assert run(shared, True) == {0: [1.0, 1.0]}
|
||||
|
||||
fresh = {}
|
||||
first, second = run(fresh, False), run(fresh, False)
|
||||
assert fresh == {}
|
||||
assert first == second == {0: [1.0]}
|
||||
assert first is not second
|
||||
|
||||
|
||||
def test_top_level_return_stops_script():
|
||||
assert _visit("x = 1; return 5; x = 2; x", {}) == 5
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ export const FUNCTION_META = {
|
||||
"interpolate_area": { minArgs: 2, maxArgs: 2, signature: "interpolate_area(x, scale)", forms: [["x", "scale"]], description: "resizes x [N, C, ...] with area interpolation. A number scales every spatial dimension; a list is the target spatial size", details: "", params: {"x": "tensor shaped [N, C, ...] with 1-3 spatial dimensions", "scale": "a number scales every spatial dimension; a list gives the target spatial size"}, aliases: [] },
|
||||
"interpolate_nearest": { minArgs: 2, maxArgs: 2, signature: "interpolate_nearest(x, scale)", forms: [["x", "scale"]], description: "resizes x [N, C, ...] with nearest-neighbour interpolation. A number scales every spatial dimension; a list is the target spatial size", details: "", params: {"x": "tensor shaped [N, C, ...] with 1-3 spatial dimensions", "scale": "a number scales every spatial dimension; a list gives the target spatial size"}, aliases: ["interpolate_nearest_exact"] },
|
||||
"interpolate_nearest_exact": { minArgs: 2, maxArgs: 2, signature: "interpolate_nearest_exact(x, scale)", forms: [["x", "scale"]], description: "resizes x [N, C, ...] with nearest-neighbour interpolation. A number scales every spatial dimension; a list is the target spatial size", details: "", params: {"x": "tensor shaped [N, C, ...] with 1-3 spatial dimensions", "scale": "a number scales every spatial dimension; a list gives the target spatial size"}, aliases: ["interpolate_nearest"] },
|
||||
"text_image": { minArgs: 3, maxArgs: 9, signature: "text_image(text, font, size, [max_width], [weight], [rotation_angle], [line_spacing], [italic], [underline])", forms: [["text", "font", "size", "[max_width]", "[weight]", "[rotation_angle]", "[line_spacing]", "[italic]", "[underline]"]], description: "renders text to a 2D tensor with values 0-1", details: "", params: {"text": "text to render; line breaks start new lines", "font": "font name to look up in the system fonts, or a path to a font file", "size": "font size in pixels", "max_width": "wrap lines wider than this many pixels (default: 0, no wrapping)", "weight": "font weight 100-900 as in CSS (default: 400)", "rotation_angle": "rotation in degrees, counter-clockwise (default: 0)", "line_spacing": "line distance as a multiple of the line height (default: 1)", "italic": "truthy for italic text (default: false)", "underline": "truthy to underline the text (default: false)"}, aliases: [] },
|
||||
"text_image": { minArgs: 3, maxArgs: 9, signature: "text_image(text, font, size, [max_width], [weight], [rotation_angle], [line_spacing], [italic], [underline])", forms: [["text", "font", "size", "[max_width]", "[weight]", "[rotation_angle]", "[line_spacing]", "[italic]", "[underline]"]], description: "renders text to a 2D tensor with values 0-1", details: "", params: {"text": "text to render; line breaks start new lines", "font": "font name to look up in the system fonts, or a path to a font file in a system font folder or the ComfyUI input folder", "size": "font size in pixels", "max_width": "wrap lines wider than this many pixels (default: 0, no wrapping)", "weight": "font weight 100-900 as in CSS (default: 400)", "rotation_angle": "rotation in degrees, counter-clockwise (default: 0)", "line_spacing": "line distance as a multiple of the line height (default: 1)", "italic": "truthy for italic text (default: false)", "underline": "truthy to underline the text (default: false)"}, aliases: [] },
|
||||
"as_nested_tensor": { minArgs: 1, maxArgs: 1, signature: "as_nested_tensor(values)", forms: [["values"]], description: "converts a list to a nested tensor (special object containing tensors of different shapes behaving like a tensor)", details: "", params: {"values": "list of tensors; their shapes may differ"}, aliases: ["as_nested"] },
|
||||
"as_nested": { minArgs: 1, maxArgs: 1, signature: "as_nested(values)", forms: [["values"]], description: "converts a list to a nested tensor (special object containing tensors of different shapes behaving like a tensor)", details: "", params: {"values": "list of tensors; their shapes may differ"}, aliases: ["as_nested_tensor"] },
|
||||
"svd": { minArgs: 1, maxArgs: 2, signature: "svd(x, [full_matrices])", forms: [["x", "[full_matrices]"]], description: "computes the singular value decomposition of x. Returns a list of 3 tensors U, S, Vh such that x = matmul(matmul(U, diagonal_matrix(S, shape(U))), Vh)", details: "", params: {"x": "matrix, or a batch of matrices in the last two dimensions", "full_matrices": "truthy to return full-size U and Vh (default: false)"}, aliases: ["singular_value_decomposition"] },
|
||||
|
||||
Reference in New Issue
Block a user