refactor: renamed LazyValueFunc to Func
parent
84825c2642
commit
dccf952ad3
|
@ -48,7 +48,7 @@ from .flow_kinds import (
|
||||||
FlowKind,
|
FlowKind,
|
||||||
InfoFlow,
|
InfoFlow,
|
||||||
RangeFlow,
|
RangeFlow,
|
||||||
LazyValueFuncFlow,
|
FuncFlow,
|
||||||
ParamsFlow,
|
ParamsFlow,
|
||||||
ScalingMode,
|
ScalingMode,
|
||||||
ValueFlow,
|
ValueFlow,
|
||||||
|
@ -119,7 +119,7 @@ __all__ = [
|
||||||
'FlowKind',
|
'FlowKind',
|
||||||
'InfoFlow',
|
'InfoFlow',
|
||||||
'RangeFlow',
|
'RangeFlow',
|
||||||
'LazyValueFuncFlow',
|
'FuncFlow',
|
||||||
'ParamsFlow',
|
'ParamsFlow',
|
||||||
'ScalingMode',
|
'ScalingMode',
|
||||||
'ValueFlow',
|
'ValueFlow',
|
||||||
|
|
|
@ -19,7 +19,7 @@ from .capabilities import CapabilitiesFlow
|
||||||
from .flow_kinds import FlowKind
|
from .flow_kinds import FlowKind
|
||||||
from .info import InfoFlow
|
from .info import InfoFlow
|
||||||
from .lazy_range import RangeFlow, ScalingMode
|
from .lazy_range import RangeFlow, ScalingMode
|
||||||
from .lazy_value_func import LazyValueFuncFlow
|
from .lazy_func import FuncFlow
|
||||||
from .params import ParamsFlow
|
from .params import ParamsFlow
|
||||||
from .value import ValueFlow
|
from .value import ValueFlow
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ __all__ = [
|
||||||
'InfoFlow',
|
'InfoFlow',
|
||||||
'RangeFlow',
|
'RangeFlow',
|
||||||
'ScalingMode',
|
'ScalingMode',
|
||||||
'LazyValueFuncFlow',
|
'FuncFlow',
|
||||||
'ParamsFlow',
|
'ParamsFlow',
|
||||||
'ValueFlow',
|
'ValueFlow',
|
||||||
]
|
]
|
||||||
|
|
|
@ -40,7 +40,7 @@ class FlowKind(enum.StrEnum):
|
||||||
Array: An object with dimensions, and possibly a unit.
|
Array: An object with dimensions, and possibly a unit.
|
||||||
Whenever a `Value` is defined, a single-element `list` will also be generated by default as `Array`
|
Whenever a `Value` is defined, a single-element `list` will also be generated by default as `Array`
|
||||||
However, for any other array-like variants (or sockets that only represent array-like objects), `Array` should be defined manually.
|
However, for any other array-like variants (or sockets that only represent array-like objects), `Array` should be defined manually.
|
||||||
LazyValueFunc: A composable function.
|
Func: A composable function.
|
||||||
Can be used to represent computations for which all data is not yet known, or for which just-in-time compilation can drastically increase performance.
|
Can be used to represent computations for which all data is not yet known, or for which just-in-time compilation can drastically increase performance.
|
||||||
Range: An object that generates an `Array` from range information (start/stop/step/spacing).
|
Range: An object that generates an `Array` from range information (start/stop/step/spacing).
|
||||||
This should be used instead of `Array` whenever possible.
|
This should be used instead of `Array` whenever possible.
|
||||||
|
@ -55,7 +55,7 @@ class FlowKind(enum.StrEnum):
|
||||||
Array = enum.auto()
|
Array = enum.auto()
|
||||||
|
|
||||||
# Lazy
|
# Lazy
|
||||||
LazyValueFunc = enum.auto()
|
Func = enum.auto()
|
||||||
Range = enum.auto()
|
Range = enum.auto()
|
||||||
|
|
||||||
# Auxiliary
|
# Auxiliary
|
||||||
|
@ -96,7 +96,7 @@ class FlowKind(enum.StrEnum):
|
||||||
return {
|
return {
|
||||||
FlowKind.Value: FlowKind.Value,
|
FlowKind.Value: FlowKind.Value,
|
||||||
FlowKind.Array: FlowKind.Array,
|
FlowKind.Array: FlowKind.Array,
|
||||||
FlowKind.LazyValueFunc: FlowKind.LazyValueFunc,
|
FlowKind.Func: FlowKind.Func,
|
||||||
FlowKind.Range: FlowKind.Range,
|
FlowKind.Range: FlowKind.Range,
|
||||||
}[self]
|
}[self]
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ class FlowKind(enum.StrEnum):
|
||||||
FlowKind.Value: 'CIRCLE',
|
FlowKind.Value: 'CIRCLE',
|
||||||
FlowKind.Array: 'SQUARE',
|
FlowKind.Array: 'SQUARE',
|
||||||
FlowKind.Range: 'SQUARE',
|
FlowKind.Range: 'SQUARE',
|
||||||
FlowKind.LazyValueFunc: 'DIAMOND',
|
FlowKind.Func: 'DIAMOND',
|
||||||
}[self]
|
}[self]
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
@ -119,7 +119,7 @@ class FlowKind(enum.StrEnum):
|
||||||
FlowKind.Value: 'Value',
|
FlowKind.Value: 'Value',
|
||||||
FlowKind.Array: 'Array',
|
FlowKind.Array: 'Array',
|
||||||
FlowKind.Range: 'Range',
|
FlowKind.Range: 'Range',
|
||||||
FlowKind.LazyValueFunc: 'Func',
|
FlowKind.Func: 'Func',
|
||||||
FlowKind.Params: 'Parameters',
|
FlowKind.Params: 'Parameters',
|
||||||
FlowKind.Info: 'Information',
|
FlowKind.Info: 'Information',
|
||||||
}[v]
|
}[v]
|
||||||
|
|
|
@ -30,7 +30,7 @@ LazyFunction: typ.TypeAlias = typ.Callable[[typ.Any, ...], typ.Any]
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True, kw_only=True)
|
@dataclasses.dataclass(frozen=True, kw_only=True)
|
||||||
class LazyValueFuncFlow:
|
class FuncFlow:
|
||||||
r"""Defines a flow of data as incremental function composition.
|
r"""Defines a flow of data as incremental function composition.
|
||||||
|
|
||||||
For specific math system usage instructions, please consult the documentation of relevant nodes.
|
For specific math system usage instructions, please consult the documentation of relevant nodes.
|
||||||
|
@ -44,9 +44,9 @@ class LazyValueFuncFlow:
|
||||||
- **Performant**: Since no operations are happening, the UI feels fast and snappy.
|
- **Performant**: Since no operations are happening, the UI feels fast and snappy.
|
||||||
|
|
||||||
## Strongly Related FlowKinds
|
## Strongly Related FlowKinds
|
||||||
For doing math, `LazyValueFunc` relies on two other `FlowKind`s, which must run in parallel:
|
For doing math, `Func` relies on two other `FlowKind`s, which must run in parallel:
|
||||||
|
|
||||||
- `FlowKind.Info`: Tracks the name, `spux.MathType`, unit (if any), length, and index coordinates for the raw data object produced by `LazyValueFunc`.
|
- `FlowKind.Info`: Tracks the name, `spux.MathType`, unit (if any), length, and index coordinates for the raw data object produced by `Func`.
|
||||||
- `FlowKind.Params`: Tracks the particular values of input parameters to the lazy function, each of which can also be symbolic.
|
- `FlowKind.Params`: Tracks the particular values of input parameters to the lazy function, each of which can also be symbolic.
|
||||||
|
|
||||||
For more, please see the documentation for each.
|
For more, please see the documentation for each.
|
||||||
|
@ -84,12 +84,12 @@ class LazyValueFuncFlow:
|
||||||
## 'A0', 'KV0' are of length 'p' and 'q'
|
## 'A0', 'KV0' are of length 'p' and 'q'
|
||||||
def f_0(*args, **kwargs): ...
|
def f_0(*args, **kwargs): ...
|
||||||
|
|
||||||
lazy_value_func_0 = LazyValueFuncFlow(
|
lazy_func_0 = FuncFlow(
|
||||||
func=f_0,
|
func=f_0,
|
||||||
func_args=[(a_i, type(a_i)) for a_i in A0],
|
func_args=[(a_i, type(a_i)) for a_i in A0],
|
||||||
func_kwargs={k: v for k,v in KV0},
|
func_kwargs={k: v for k,v in KV0},
|
||||||
)
|
)
|
||||||
output_0 = lazy_value_func.func(*A0_computed, **KV0_computed)
|
output_0 = lazy_func.func(*A0_computed, **KV0_computed)
|
||||||
```
|
```
|
||||||
|
|
||||||
## `depth>0`: Composition Chaining
|
## `depth>0`: Composition Chaining
|
||||||
|
@ -120,7 +120,7 @@ class LazyValueFuncFlow:
|
||||||
## 'A1', 'KV1' are therefore of length 'r' and 's'
|
## 'A1', 'KV1' are therefore of length 'r' and 's'
|
||||||
def f_1(output_0, *args, **kwargs): ...
|
def f_1(output_0, *args, **kwargs): ...
|
||||||
|
|
||||||
lazy_value_func_1 = lazy_value_func_0.compose_within(
|
lazy_func_1 = lazy_func_0.compose_within(
|
||||||
enclosing_func=f_1,
|
enclosing_func=f_1,
|
||||||
enclosing_func_args=[(a_i, type(a_i)) for a_i in A1],
|
enclosing_func_args=[(a_i, type(a_i)) for a_i in A1],
|
||||||
enclosing_func_kwargs={k: type(v) for k,v in K1},
|
enclosing_func_kwargs={k: type(v) for k,v in K1},
|
||||||
|
@ -128,10 +128,10 @@ class LazyValueFuncFlow:
|
||||||
|
|
||||||
A_computed = A0_computed + A1_computed
|
A_computed = A0_computed + A1_computed
|
||||||
KW_computed = KV0_computed + KV1_computed
|
KW_computed = KV0_computed + KV1_computed
|
||||||
output_1 = lazy_value_func_1.func(*A_computed, **KW_computed)
|
output_1 = lazy_func_1.func(*A_computed, **KW_computed)
|
||||||
```
|
```
|
||||||
|
|
||||||
By using `LazyValueFunc`, we've guaranteed that even hugely deep $n$s won't ever look more complicated than this.
|
By using `Func`, we've guaranteed that even hugely deep $n$s won't ever look more complicated than this.
|
||||||
|
|
||||||
## `max depth`: "Realization"
|
## `max depth`: "Realization"
|
||||||
So, we've composed a bunch of functions of functions of ...
|
So, we've composed a bunch of functions of functions of ...
|
||||||
|
@ -142,22 +142,22 @@ class LazyValueFuncFlow:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# A_all and KW_all must be tracked on the side.
|
# A_all and KW_all must be tracked on the side.
|
||||||
output_n = lazy_value_func_n.func(*A_all, **KW_all)
|
output_n = lazy_func_n.func(*A_all, **KW_all)
|
||||||
```
|
```
|
||||||
|
|
||||||
Of course, this comes with enormous overhead.
|
Of course, this comes with enormous overhead.
|
||||||
Aside from the function calls themselves (which can be non-trivial), we must also contend with the enormous inefficiency of performing array operations sequentially.
|
Aside from the function calls themselves (which can be non-trivial), we must also contend with the enormous inefficiency of performing array operations sequentially.
|
||||||
|
|
||||||
That brings us to the killer feature of `LazyValueFuncFlow`, and the motivating reason for doing any of this at all:
|
That brings us to the killer feature of `FuncFlow`, and the motivating reason for doing any of this at all:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
output_n = lazy_value_func_n.func_jax(*A_all, **KW_all)
|
output_n = lazy_func_n.func_jax(*A_all, **KW_all)
|
||||||
```
|
```
|
||||||
|
|
||||||
What happened was, **the entire pipeline** was compiled, optimized, and computed with bare-metal performance on either a CPU, GPU, or TPU.
|
What happened was, **the entire pipeline** was compiled, optimized, and computed with bare-metal performance on either a CPU, GPU, or TPU.
|
||||||
With the help of the `jax` library (and its underlying OpenXLA bytecode), all of that inefficiency has been optimized based on _what we're trying to do_, not _exactly how we're doing it_, in order to maximize the use of modern massively-parallel devices.
|
With the help of the `jax` library (and its underlying OpenXLA bytecode), all of that inefficiency has been optimized based on _what we're trying to do_, not _exactly how we're doing it_, in order to maximize the use of modern massively-parallel devices.
|
||||||
|
|
||||||
See the documentation of `LazyValueFunc.func_jax()` for more information on this process.
|
See the documentation of `Func.func_jax()` for more information on this process.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -187,12 +187,12 @@ class LazyValueFuncFlow:
|
||||||
As a more nuanced example, when lag occurs due to the computing an image-based plot based on live-computed math, then the visual feedback of _the plot actually changing_ seems to have a similar effect, not least because it's emotionally well-understood that detaching the `Viewer` node would also remove the lag.
|
As a more nuanced example, when lag occurs due to the computing an image-based plot based on live-computed math, then the visual feedback of _the plot actually changing_ seems to have a similar effect, not least because it's emotionally well-understood that detaching the `Viewer` node would also remove the lag.
|
||||||
|
|
||||||
In short: Even if lazy evaluation didn't make any math faster, it will still _feel_ faster (to a point - raw performance obviously still matters).
|
In short: Even if lazy evaluation didn't make any math faster, it will still _feel_ faster (to a point - raw performance obviously still matters).
|
||||||
Without `LazyValueFuncFlow`, the point of evaluation cannot be chosen at all, which is a huge issue for all the named reasons.
|
Without `FuncFlow`, the point of evaluation cannot be chosen at all, which is a huge issue for all the named reasons.
|
||||||
With `LazyValueFuncFlow`, better-chosen evaluation points can be chosen to cause the _user experience_ of high performance, simply because we were able to shift the exact same computation to a point in time where the user either understands or tolerates the delay better.
|
With `FuncFlow`, better-chosen evaluation points can be chosen to cause the _user experience_ of high performance, simply because we were able to shift the exact same computation to a point in time where the user either understands or tolerates the delay better.
|
||||||
|
|
||||||
## Flexibility
|
## Flexibility
|
||||||
Large-scale math is done on tensors, whether one knows (or likes!) it or not.
|
Large-scale math is done on tensors, whether one knows (or likes!) it or not.
|
||||||
To this end, the indexed arrays produced by `LazyValueFuncFlow.func_jax` aren't quite sufficient for most operations we want to do:
|
To this end, the indexed arrays produced by `FuncFlow.func_jax` aren't quite sufficient for most operations we want to do:
|
||||||
|
|
||||||
- **Naming**: What _is_ each axis?
|
- **Naming**: What _is_ each axis?
|
||||||
Unnamed index axes are sometimes easy to decode, but in general, names have an unexpectedly critical function when operating on arrays.
|
Unnamed index axes are sometimes easy to decode, but in general, names have an unexpectedly critical function when operating on arrays.
|
||||||
|
@ -206,13 +206,13 @@ class LazyValueFuncFlow:
|
||||||
|
|
||||||
Not only do we endeavor to track these, but we also introduce unit-awareness to the coordinates, and design the entire math system to visually communicate the state of arrays before/after every single computation, as well as only expose operations that this tracked data indicates possible.
|
Not only do we endeavor to track these, but we also introduce unit-awareness to the coordinates, and design the entire math system to visually communicate the state of arrays before/after every single computation, as well as only expose operations that this tracked data indicates possible.
|
||||||
|
|
||||||
In practice, this happens in `FlowKind.Info`, which due to having its own `FlowKind` "lane" can be adjusted without triggering changes to (and therefore recompilation of) the `FlowKind.LazyValueFunc` chain.
|
In practice, this happens in `FlowKind.Info`, which due to having its own `FlowKind` "lane" can be adjusted without triggering changes to (and therefore recompilation of) the `FlowKind.Func` chain.
|
||||||
**Please consult the `InfoFlow` documentation for more**.
|
**Please consult the `InfoFlow` documentation for more**.
|
||||||
|
|
||||||
## Performance
|
## Performance
|
||||||
All values introduced while processing are kept in a seperate `FlowKind` lane, with its own incremental caching: `FlowKind.Params`.
|
All values introduced while processing are kept in a seperate `FlowKind` lane, with its own incremental caching: `FlowKind.Params`.
|
||||||
|
|
||||||
It's a simple mechanism, but for the cost of introducing an extra `FlowKind` "lane", all of the values used to process data can be live-adjusted without the overhead of recompiling the entire `LazyValueFunc` every time anything changes.
|
It's a simple mechanism, but for the cost of introducing an extra `FlowKind` "lane", all of the values used to process data can be live-adjusted without the overhead of recompiling the entire `Func` every time anything changes.
|
||||||
Moreover, values used to process data don't even have to be numbers yet: They can be expressions of symbolic variables, complete with units, which are only realized at the very end of the chain, by the node that absolutely cannot function without the actual numerical data.
|
Moreover, values used to process data don't even have to be numbers yet: They can be expressions of symbolic variables, complete with units, which are only realized at the very end of the chain, by the node that absolutely cannot function without the actual numerical data.
|
||||||
|
|
||||||
See the `ParamFlow` documentation for more information.
|
See the `ParamFlow` documentation for more information.
|
||||||
|
@ -224,7 +224,7 @@ class LazyValueFuncFlow:
|
||||||
A few teasers of what nodes can do with this system:
|
A few teasers of what nodes can do with this system:
|
||||||
|
|
||||||
**Auto-Differentiation**: `jax.jit` isn't even really the killer feature of `jax`.
|
**Auto-Differentiation**: `jax.jit` isn't even really the killer feature of `jax`.
|
||||||
`jax` can automatically differentiate `LazyValueFuncFlow.func_jax` with respect to any input parameter, including for fwd/bck jacobians/hessians, with robust numerical stability.
|
`jax` can automatically differentiate `FuncFlow.func_jax` with respect to any input parameter, including for fwd/bck jacobians/hessians, with robust numerical stability.
|
||||||
When used in
|
When used in
|
||||||
**Symbolic Interop**: Any `sympy` expression containing symbolic variables can be compiled, by `sympy`, into a `jax`-compatible function which takes
|
**Symbolic Interop**: Any `sympy` expression containing symbolic variables can be compiled, by `sympy`, into a `jax`-compatible function which takes
|
||||||
We make use of this in the `Expr` socket, enabling true symbolic math to be used in high-performance lazy `jax` computations.
|
We make use of this in the `Expr` socket, enabling true symbolic math to be used in high-performance lazy `jax` computations.
|
||||||
|
@ -304,7 +304,7 @@ class LazyValueFuncFlow:
|
||||||
if self.supports_jax:
|
if self.supports_jax:
|
||||||
return jax.jit(self.func)
|
return jax.jit(self.func)
|
||||||
|
|
||||||
msg = 'Can\'t express LazyValueFuncFlow as JAX function (using jax.jit), since "self.supports_jax" is False'
|
msg = 'Can\'t express FuncFlow as JAX function (using jax.jit), since "self.supports_jax" is False'
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
@ -317,7 +317,7 @@ class LazyValueFuncFlow:
|
||||||
enclosing_func_kwargs: dict[str, type] = MappingProxyType({}),
|
enclosing_func_kwargs: dict[str, type] = MappingProxyType({}),
|
||||||
supports_jax: bool = False,
|
supports_jax: bool = False,
|
||||||
) -> typ.Self:
|
) -> typ.Self:
|
||||||
"""Compose `self.func` within the given enclosing function, which itself takes arguments, and create a new `LazyValueFuncFlow` to contain it.
|
"""Compose `self.func` within the given enclosing function, which itself takes arguments, and create a new `FuncFlow` to contain it.
|
||||||
|
|
||||||
This is the fundamental operation used to "chain" functions together.
|
This is the fundamental operation used to "chain" functions together.
|
||||||
|
|
||||||
|
@ -328,13 +328,13 @@ class LazyValueFuncFlow:
|
||||||
C = spux.MathType.Complex
|
C = spux.MathType.Complex
|
||||||
x, y = sp.symbols('x y', real=True)
|
x, y = sp.symbols('x y', real=True)
|
||||||
|
|
||||||
# Prepare "Root" LazyValueFuncFlow w/x,y args
|
# Prepare "Root" FuncFlow w/x,y args
|
||||||
expr_root = 3*x + y**2 - 100
|
expr_root = 3*x + y**2 - 100
|
||||||
expr_root_func = sp.lambdify([x, y], expr, 'jax')
|
expr_root_func = sp.lambdify([x, y], expr, 'jax')
|
||||||
|
|
||||||
func_root = LazyValueFuncFlow(func=expr_root_func, func_args=[R,R], supports_jax=True)
|
func_root = FuncFlow(func=expr_root_func, func_args=[R,R], supports_jax=True)
|
||||||
|
|
||||||
# Compose "Enclosing" LazyValueFuncFlow w/z arg
|
# Compose "Enclosing" FuncFlow w/z arg
|
||||||
r = sp.Symbol('z', real=True)
|
r = sp.Symbol('z', real=True)
|
||||||
z = sp.Symbol('z', complex=True)
|
z = sp.Symbol('z', complex=True)
|
||||||
expr = 10*sp.re(z) / (z + r)
|
expr = 10*sp.re(z) / (z + r)
|
||||||
|
@ -351,7 +351,7 @@ class LazyValueFuncFlow:
|
||||||
Returns:
|
Returns:
|
||||||
A lazy function that takes both the enclosed and enclosing arguments, and returns the value of the enclosing function (whose first argument is the output value of the enclosed function).
|
A lazy function that takes both the enclosed and enclosing arguments, and returns the value of the enclosing function (whose first argument is the output value of the enclosed function).
|
||||||
"""
|
"""
|
||||||
return LazyValueFuncFlow(
|
return FuncFlow(
|
||||||
func=lambda *args, **kwargs: enclosing_func(
|
func=lambda *args, **kwargs: enclosing_func(
|
||||||
self.func(
|
self.func(
|
||||||
*list(args[: len(self.func_args)]),
|
*list(args[: len(self.func_args)]),
|
||||||
|
@ -373,17 +373,17 @@ class LazyValueFuncFlow:
|
||||||
|
|
||||||
Generally, `self.func` produces a single array as output (when doing math, at least).
|
Generally, `self.func` produces a single array as output (when doing math, at least).
|
||||||
But sometimes (as in the `OperateMathNode`), we need to perform a binary operation between two arrays, like say, $+$.
|
But sometimes (as in the `OperateMathNode`), we need to perform a binary operation between two arrays, like say, $+$.
|
||||||
Without realizing both `LazyValueFuncFlow`s, it's not immediately obvious how one might accomplish this.
|
Without realizing both `FuncFlow`s, it's not immediately obvious how one might accomplish this.
|
||||||
|
|
||||||
This overloaded function of the `|` operator (used as `left | right`) solves that problem.
|
This overloaded function of the `|` operator (used as `left | right`) solves that problem.
|
||||||
A new `LazyValueFuncFlow` is created, which takes the arguments of both inputs, and which produces a single output value: A 2-tuple, where each element if the output of each function.
|
A new `FuncFlow` is created, which takes the arguments of both inputs, and which produces a single output value: A 2-tuple, where each element if the output of each function.
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
Consider this illustrative (pseudocode) example:
|
Consider this illustrative (pseudocode) example:
|
||||||
```python
|
```python
|
||||||
# Presume a,b are values, and that A,B are their identifiers.
|
# Presume a,b are values, and that A,B are their identifiers.
|
||||||
func_1 = LazyValueFuncFlow(func=compute_big_data_1, func_args=[A])
|
func_1 = FuncFlow(func=compute_big_data_1, func_args=[A])
|
||||||
func_2 = LazyValueFuncFlow(func=compute_big_data_2, func_args=[B])
|
func_2 = FuncFlow(func=compute_big_data_2, func_args=[B])
|
||||||
|
|
||||||
f = (func_1 | func_2).compose_within(func=lambda D: D[0] + D[1])
|
f = (func_1 | func_2).compose_within(func=lambda D: D[0] + D[1])
|
||||||
|
|
||||||
|
@ -402,7 +402,7 @@ class LazyValueFuncFlow:
|
||||||
Returns:
|
Returns:
|
||||||
A lazy function that takes all arguments of both inputs, and returns a 2-tuple containing both output arguments.
|
A lazy function that takes all arguments of both inputs, and returns a 2-tuple containing both output arguments.
|
||||||
"""
|
"""
|
||||||
return LazyValueFuncFlow(
|
return FuncFlow(
|
||||||
func=lambda *args, **kwargs: (
|
func=lambda *args, **kwargs: (
|
||||||
self.func(
|
self.func(
|
||||||
*list(args[: len(self.func_args)]),
|
*list(args[: len(self.func_args)]),
|
|
@ -29,7 +29,7 @@ from blender_maxwell.utils import logger
|
||||||
|
|
||||||
from .array import ArrayFlow
|
from .array import ArrayFlow
|
||||||
from .flow_kinds import FlowKind
|
from .flow_kinds import FlowKind
|
||||||
from .lazy_value_func import LazyValueFuncFlow
|
from .lazy_func import FuncFlow
|
||||||
|
|
||||||
log = logger.get(__name__)
|
log = logger.get(__name__)
|
||||||
|
|
||||||
|
@ -361,7 +361,7 @@ class RangeFlow:
|
||||||
The ordering of the symbols is identical to `self.symbols`, which is guaranteed to be a deterministically sorted list of symbols.
|
The ordering of the symbols is identical to `self.symbols`, which is guaranteed to be a deterministically sorted list of symbols.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A `LazyValueFuncFlow` that, given the input symbols defined in `self.symbols`,
|
A `FuncFlow` that, given the input symbols defined in `self.symbols`,
|
||||||
"""
|
"""
|
||||||
# Compile JAX Functions for Start/End Expressions
|
# Compile JAX Functions for Start/End Expressions
|
||||||
## FYI, JAX-in-JAX works perfectly fine.
|
## FYI, JAX-in-JAX works perfectly fine.
|
||||||
|
@ -378,18 +378,18 @@ class RangeFlow:
|
||||||
return gen_array
|
return gen_array
|
||||||
|
|
||||||
@functools.cached_property
|
@functools.cached_property
|
||||||
def as_lazy_value_func(self) -> LazyValueFuncFlow:
|
def as_lazy_func(self) -> FuncFlow:
|
||||||
"""Creates a `LazyValueFuncFlow` using the output of `self.as_func`.
|
"""Creates a `FuncFlow` using the output of `self.as_func`.
|
||||||
|
|
||||||
This is useful for ex. parameterizing the first array in the node graph, without binding an entire computed array.
|
This is useful for ex. parameterizing the first array in the node graph, without binding an entire computed array.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
The the function enclosed in the `LazyValueFuncFlow` is identical to the one returned by `self.as_func`.
|
The the function enclosed in the `FuncFlow` is identical to the one returned by `self.as_func`.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A `LazyValueFuncFlow` containing `self.as_func`, as well as appropriate supporting settings.
|
A `FuncFlow` containing `self.as_func`, as well as appropriate supporting settings.
|
||||||
"""
|
"""
|
||||||
return LazyValueFuncFlow(
|
return FuncFlow(
|
||||||
func=self.as_func,
|
func=self.as_func,
|
||||||
func_args=[(spux.MathType.from_expr(sym)) for sym in self.symbols],
|
func_args=[(spux.MathType.from_expr(sym)) for sym in self.symbols],
|
||||||
supports_jax=True,
|
supports_jax=True,
|
||||||
|
@ -401,7 +401,7 @@ class RangeFlow:
|
||||||
def realize_start(
|
def realize_start(
|
||||||
self,
|
self,
|
||||||
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
||||||
) -> ArrayFlow | LazyValueFuncFlow:
|
) -> ArrayFlow | FuncFlow:
|
||||||
return spux.sympy_to_python(
|
return spux.sympy_to_python(
|
||||||
self.start.subs({sym: symbol_values[sym.name] for sym in self.symbols})
|
self.start.subs({sym: symbol_values[sym.name] for sym in self.symbols})
|
||||||
)
|
)
|
||||||
|
@ -409,7 +409,7 @@ class RangeFlow:
|
||||||
def realize_stop(
|
def realize_stop(
|
||||||
self,
|
self,
|
||||||
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
||||||
) -> ArrayFlow | LazyValueFuncFlow:
|
) -> ArrayFlow | FuncFlow:
|
||||||
return spux.sympy_to_python(
|
return spux.sympy_to_python(
|
||||||
self.stop.subs({sym: symbol_values[sym.name] for sym in self.symbols})
|
self.stop.subs({sym: symbol_values[sym.name] for sym in self.symbols})
|
||||||
)
|
)
|
||||||
|
@ -417,7 +417,7 @@ class RangeFlow:
|
||||||
def realize_step_size(
|
def realize_step_size(
|
||||||
self,
|
self,
|
||||||
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
||||||
) -> ArrayFlow | LazyValueFuncFlow:
|
) -> ArrayFlow | FuncFlow:
|
||||||
raw_step_size = (self.realize_stop() - self.realize_start() + 1) / self.steps
|
raw_step_size = (self.realize_stop() - self.realize_start() + 1) / self.steps
|
||||||
|
|
||||||
if self.mathtype is spux.MathType.Integer and raw_step_size.is_integer():
|
if self.mathtype is spux.MathType.Integer and raw_step_size.is_integer():
|
||||||
|
@ -427,8 +427,8 @@ class RangeFlow:
|
||||||
def realize(
|
def realize(
|
||||||
self,
|
self,
|
||||||
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
symbol_values: dict[spux.Symbol, typ.Any] = MappingProxyType({}),
|
||||||
kind: typ.Literal[FlowKind.Array, FlowKind.LazyValueFunc] = FlowKind.Array,
|
kind: typ.Literal[FlowKind.Array, FlowKind.Func] = FlowKind.Array,
|
||||||
) -> ArrayFlow | LazyValueFuncFlow:
|
) -> ArrayFlow | FuncFlow:
|
||||||
"""Apply a function to the bounds, effectively rescaling the represented array.
|
"""Apply a function to the bounds, effectively rescaling the represented array.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
@ -458,8 +458,8 @@ class RangeFlow:
|
||||||
|
|
||||||
if kind == FlowKind.Array:
|
if kind == FlowKind.Array:
|
||||||
return ArrayFlow(values=gen_array(), unit=self.unit, is_sorted=True)
|
return ArrayFlow(values=gen_array(), unit=self.unit, is_sorted=True)
|
||||||
if kind == FlowKind.LazyValueFunc:
|
if kind == FlowKind.Func:
|
||||||
return LazyValueFuncFlow(func=gen_array, supports_jax=True)
|
return FuncFlow(func=gen_array, supports_jax=True)
|
||||||
|
|
||||||
msg = f'Invalid kind: {kind}'
|
msg = f'Invalid kind: {kind}'
|
||||||
raise TypeError(msg)
|
raise TypeError(msg)
|
||||||
|
|
|
@ -69,7 +69,7 @@ class ParamsFlow:
|
||||||
unit_system: spux.UnitSystem,
|
unit_system: spux.UnitSystem,
|
||||||
symbol_values: dict[spux.Symbol, spux.SympyExpr] = MappingProxyType({}),
|
symbol_values: dict[spux.Symbol, spux.SympyExpr] = MappingProxyType({}),
|
||||||
):
|
):
|
||||||
"""Realize the function arguments contained in this `ParamsFlow`, making it ready for insertion into `LazyValueFunc.func()`.
|
"""Realize the function arguments contained in this `ParamsFlow`, making it ready for insertion into `Func.func()`.
|
||||||
|
|
||||||
For all `arg`s in `self.func_args`, the following operations are performed:
|
For all `arg`s in `self.func_args`, the following operations are performed:
|
||||||
- **Unit System**: If `arg`
|
- **Unit System**: If `arg`
|
||||||
|
@ -121,7 +121,7 @@ class ParamsFlow:
|
||||||
):
|
):
|
||||||
"""Combine two function parameter lists, such that the LHS will be concatenated with the RHS.
|
"""Combine two function parameter lists, such that the LHS will be concatenated with the RHS.
|
||||||
|
|
||||||
Just like its neighbor in `LazyValueFunc`, this effectively combines two functions with unique parameters.
|
Just like its neighbor in `Func`, this effectively combines two functions with unique parameters.
|
||||||
The next composed function will receive a tuple of two arrays, instead of just one, allowing binary operations to occur.
|
The next composed function will receive a tuple of two arrays, instead of just one, allowing binary operations to occur.
|
||||||
"""
|
"""
|
||||||
return ParamsFlow(
|
return ParamsFlow(
|
||||||
|
|
|
@ -318,12 +318,12 @@ class DataFileFormat(enum.StrEnum):
|
||||||
"""Abstraction of a data file format, providing a regularized way of interacting with filesystem data.
|
"""Abstraction of a data file format, providing a regularized way of interacting with filesystem data.
|
||||||
|
|
||||||
Import/export interacts closely with the `Expr` socket's `FlowKind` semantics:
|
Import/export interacts closely with the `Expr` socket's `FlowKind` semantics:
|
||||||
- `FlowKind.LazyValueFunc`: Generally realized on-import/export.
|
- `FlowKind.Func`: Generally realized on-import/export.
|
||||||
- **Import**: Loading data is generally eager, but memory-mapped file loading would be manageable using this interface.
|
- **Import**: Loading data is generally eager, but memory-mapped file loading would be manageable using this interface.
|
||||||
- **Export**: The function is realized and only the array is inserted into the file.
|
- **Export**: The function is realized and only the array is inserted into the file.
|
||||||
- `FlowKind.Params`: Generally consumed.
|
- `FlowKind.Params`: Generally consumed.
|
||||||
- **Import**: A new, empty `ParamsFlow` object is created.
|
- **Import**: A new, empty `ParamsFlow` object is created.
|
||||||
- **Export**: The `ParamsFlow` is consumed when realizing the `LazyValueFunc`.
|
- **Export**: The `ParamsFlow` is consumed when realizing the `Func`.
|
||||||
- `FlowKind.Info`: As the most important element, it is kept in an (optional) sidecar metadata file.
|
- `FlowKind.Info`: As the most important element, it is kept in an (optional) sidecar metadata file.
|
||||||
- **Import**: The sidecar file is loaded, checked, and used, if it exists. A warning about further processing may show if it doesn't.
|
- **Import**: The sidecar file is loaded, checked, and used, if it exists. A warning about further processing may show if it doesn't.
|
||||||
- **Export**: The sidecar file is written next to the canonical data file, in such a manner that it can be both read and loaded.
|
- **Export**: The sidecar file is written next to the canonical data file, in such a manner that it can be both read and loaded.
|
||||||
|
|
|
@ -57,9 +57,7 @@ class ExtractDataNode(base.MaxwellSimNode):
|
||||||
}
|
}
|
||||||
output_socket_sets: typ.ClassVar = {
|
output_socket_sets: typ.ClassVar = {
|
||||||
'Sim Data': {'Monitor Data': sockets.MaxwellMonitorDataSocketDef()},
|
'Sim Data': {'Monitor Data': sockets.MaxwellMonitorDataSocketDef()},
|
||||||
'Monitor Data': {
|
'Monitor Data': {'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func)},
|
||||||
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
@ -349,7 +347,7 @@ class ExtractDataNode(base.MaxwellSimNode):
|
||||||
return ct.FlowSignal.FlowPending
|
return ct.FlowSignal.FlowPending
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - FlowKind.Array|LazyValueFunc: Monitor Data -> Expr
|
# - FlowKind.Array|Func: Monitor Data -> Expr
|
||||||
####################
|
####################
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
'Expr',
|
'Expr',
|
||||||
|
@ -384,16 +382,14 @@ class ExtractDataNode(base.MaxwellSimNode):
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
# Trigger
|
# Trigger
|
||||||
'Expr',
|
'Expr',
|
||||||
kind=ct.FlowKind.LazyValueFunc,
|
kind=ct.FlowKind.Func,
|
||||||
# Loaded
|
# Loaded
|
||||||
output_sockets={'Expr'},
|
output_sockets={'Expr'},
|
||||||
output_socket_kinds={'Expr': ct.FlowKind.Array},
|
output_socket_kinds={'Expr': ct.FlowKind.Array},
|
||||||
output_sockets_optional={'Expr': True},
|
output_sockets_optional={'Expr': True},
|
||||||
)
|
)
|
||||||
def compute_extracted_data_lazy(
|
def compute_extracted_data_lazy(self, output_sockets: dict) -> ct.FuncFlow | None:
|
||||||
self, output_sockets: dict
|
"""Declare `Expr:Func` by creating a simple function that directly wraps `Expr:Array`.
|
||||||
) -> ct.LazyValueFuncFlow | None:
|
|
||||||
"""Declare `Expr:LazyValueFunc` by creating a simple function that directly wraps `Expr:Array`.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The composable function array, if available, else `ct.FlowSignal.FlowPending`.
|
The composable function array, if available, else `ct.FlowSignal.FlowPending`.
|
||||||
|
@ -402,9 +398,7 @@ class ExtractDataNode(base.MaxwellSimNode):
|
||||||
has_output_expr = not ct.FlowSignal.check(output_expr)
|
has_output_expr = not ct.FlowSignal.check(output_expr)
|
||||||
|
|
||||||
if has_output_expr:
|
if has_output_expr:
|
||||||
return ct.LazyValueFuncFlow(
|
return ct.FuncFlow(func=lambda: output_expr.values, supports_jax=True)
|
||||||
func=lambda: output_expr.values, supports_jax=True
|
|
||||||
)
|
|
||||||
|
|
||||||
return ct.FlowSignal.FlowPending
|
return ct.FlowSignal.FlowPending
|
||||||
|
|
||||||
|
@ -441,7 +435,7 @@ class ExtractDataNode(base.MaxwellSimNode):
|
||||||
"""Declare `Data:Info` by manually selecting appropriate axes, units, etc. for each monitor type.
|
"""Declare `Data:Info` by manually selecting appropriate axes, units, etc. for each monitor type.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Information describing the `Data:LazyValueFunc`, if available, else `ct.FlowSignal.FlowPending`.
|
Information describing the `Data:Func`, if available, else `ct.FlowSignal.FlowPending`.
|
||||||
"""
|
"""
|
||||||
monitor_data = input_sockets['Monitor Data']
|
monitor_data = input_sockets['Monitor Data']
|
||||||
monitor_data_type = props['monitor_data_type']
|
monitor_data_type = props['monitor_data_type']
|
||||||
|
|
|
@ -265,10 +265,10 @@ class FilterMathNode(base.MaxwellSimNode):
|
||||||
bl_label = 'Filter Math'
|
bl_label = 'Filter Math'
|
||||||
|
|
||||||
input_sockets: typ.ClassVar = {
|
input_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc),
|
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func),
|
||||||
}
|
}
|
||||||
output_sockets: typ.ClassVar = {
|
output_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc),
|
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func),
|
||||||
}
|
}
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
@ -518,13 +518,13 @@ class FilterMathNode(base.MaxwellSimNode):
|
||||||
current_bl_socket = self.loose_input_sockets.get('Dim')
|
current_bl_socket = self.loose_input_sockets.get('Dim')
|
||||||
if (
|
if (
|
||||||
current_bl_socket is None
|
current_bl_socket is None
|
||||||
or current_bl_socket.active_kind != ct.FlowKind.LazyValueFunc
|
or current_bl_socket.active_kind != ct.FlowKind.Func
|
||||||
or current_bl_socket.mathtype != spux.MathType.Real
|
or current_bl_socket.mathtype != spux.MathType.Real
|
||||||
or current_bl_socket.physical_type != spux.PhysicalType.NonPhysical
|
or current_bl_socket.physical_type != spux.PhysicalType.NonPhysical
|
||||||
):
|
):
|
||||||
self.loose_input_sockets = {
|
self.loose_input_sockets = {
|
||||||
'Dim': sockets.ExprSocketDef(
|
'Dim': sockets.ExprSocketDef(
|
||||||
active_kind=ct.FlowKind.LazyValueFunc,
|
active_kind=ct.FlowKind.Func,
|
||||||
mathtype=spux.MathType.Real,
|
mathtype=spux.MathType.Real,
|
||||||
physical_type=spux.PhysicalType.NonPhysical,
|
physical_type=spux.PhysicalType.NonPhysical,
|
||||||
show_info_columns=True,
|
show_info_columns=True,
|
||||||
|
@ -536,28 +536,28 @@ class FilterMathNode(base.MaxwellSimNode):
|
||||||
self.loose_input_sockets = {}
|
self.loose_input_sockets = {}
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - FlowKind.Value|LazyValueFunc
|
# - FlowKind.Value|Func
|
||||||
####################
|
####################
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
'Expr',
|
'Expr',
|
||||||
kind=ct.FlowKind.LazyValueFunc,
|
kind=ct.FlowKind.Func,
|
||||||
props={'operation', 'dim_0', 'dim_1', 'slice_tuple'},
|
props={'operation', 'dim_0', 'dim_1', 'slice_tuple'},
|
||||||
input_sockets={'Expr'},
|
input_sockets={'Expr'},
|
||||||
input_socket_kinds={'Expr': {ct.FlowKind.LazyValueFunc, ct.FlowKind.Info}},
|
input_socket_kinds={'Expr': {ct.FlowKind.Func, ct.FlowKind.Info}},
|
||||||
)
|
)
|
||||||
def compute_lazy_value_func(self, props: dict, input_sockets: dict):
|
def compute_lazy_func(self, props: dict, input_sockets: dict):
|
||||||
operation = props['operation']
|
operation = props['operation']
|
||||||
lazy_value_func = input_sockets['Expr'][ct.FlowKind.LazyValueFunc]
|
lazy_func = input_sockets['Expr'][ct.FlowKind.Func]
|
||||||
info = input_sockets['Expr'][ct.FlowKind.Info]
|
info = input_sockets['Expr'][ct.FlowKind.Info]
|
||||||
|
|
||||||
has_lazy_value_func = not ct.FlowSignal.check(lazy_value_func)
|
has_lazy_func = not ct.FlowSignal.check(lazy_func)
|
||||||
has_info = not ct.FlowSignal.check(info)
|
has_info = not ct.FlowSignal.check(info)
|
||||||
|
|
||||||
# Dimension(s)
|
# Dimension(s)
|
||||||
dim_0 = props['dim_0']
|
dim_0 = props['dim_0']
|
||||||
dim_1 = props['dim_1']
|
dim_1 = props['dim_1']
|
||||||
if (
|
if (
|
||||||
has_lazy_value_func
|
has_lazy_func
|
||||||
and has_info
|
and has_info
|
||||||
and operation is not None
|
and operation is not None
|
||||||
and operation.are_dims_valid(info, dim_0, dim_1)
|
and operation.are_dims_valid(info, dim_0, dim_1)
|
||||||
|
@ -570,7 +570,7 @@ class FilterMathNode(base.MaxwellSimNode):
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
|
||||||
return lazy_value_func.compose_within(
|
return lazy_func.compose_within(
|
||||||
operation.jax_func(axis_0, axis_1, slice_tuple),
|
operation.jax_func(axis_0, axis_1, slice_tuple),
|
||||||
enclosing_func_args=operation.func_args,
|
enclosing_func_args=operation.func_args,
|
||||||
supports_jax=True,
|
supports_jax=True,
|
||||||
|
@ -594,14 +594,14 @@ class FilterMathNode(base.MaxwellSimNode):
|
||||||
input_sockets={'Expr', 'Dim'},
|
input_sockets={'Expr', 'Dim'},
|
||||||
input_socket_kinds={
|
input_socket_kinds={
|
||||||
'Expr': ct.FlowKind.Info,
|
'Expr': ct.FlowKind.Info,
|
||||||
'Dim': {ct.FlowKind.LazyValueFunc, ct.FlowKind.Params, ct.FlowKind.Info},
|
'Dim': {ct.FlowKind.Func, ct.FlowKind.Params, ct.FlowKind.Info},
|
||||||
},
|
},
|
||||||
input_sockets_optional={'Dim': True},
|
input_sockets_optional={'Dim': True},
|
||||||
)
|
)
|
||||||
def compute_info(self, props, input_sockets) -> ct.InfoFlow:
|
def compute_info(self, props, input_sockets) -> ct.InfoFlow:
|
||||||
operation = props['operation']
|
operation = props['operation']
|
||||||
info = input_sockets['Expr']
|
info = input_sockets['Expr']
|
||||||
dim_coords = input_sockets['Dim'][ct.FlowKind.LazyValueFunc]
|
dim_coords = input_sockets['Dim'][ct.FlowKind.Func]
|
||||||
dim_params = input_sockets['Dim'][ct.FlowKind.Params]
|
dim_params = input_sockets['Dim'][ct.FlowKind.Params]
|
||||||
dim_info = input_sockets['Dim'][ct.FlowKind.Info]
|
dim_info = input_sockets['Dim'][ct.FlowKind.Info]
|
||||||
dim_symbol = props['set_dim_symbol']
|
dim_symbol = props['set_dim_symbol']
|
||||||
|
|
|
@ -401,7 +401,7 @@ class MapMathNode(base.MaxwellSimNode):
|
||||||
The name and type of the available symbol is clearly shown, and most valid `sympy` expressions that you would expect to work, should work.
|
The name and type of the available symbol is clearly shown, and most valid `sympy` expressions that you would expect to work, should work.
|
||||||
|
|
||||||
Use of expressions generally imposes no performance penalty: Just like the baked-in operations, it is compiled to a high-performance `jax` function.
|
Use of expressions generally imposes no performance penalty: Just like the baked-in operations, it is compiled to a high-performance `jax` function.
|
||||||
Thus, it participates in the `ct.FlowKind.LazyValueFunc` composition chain.
|
Thus, it participates in the `ct.FlowKind.Func` composition chain.
|
||||||
|
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
|
@ -412,10 +412,10 @@ class MapMathNode(base.MaxwellSimNode):
|
||||||
bl_label = 'Map Math'
|
bl_label = 'Map Math'
|
||||||
|
|
||||||
input_sockets: typ.ClassVar = {
|
input_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc),
|
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func),
|
||||||
}
|
}
|
||||||
output_sockets: typ.ClassVar = {
|
output_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc),
|
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func),
|
||||||
}
|
}
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
@ -474,7 +474,7 @@ class MapMathNode(base.MaxwellSimNode):
|
||||||
layout.prop(self, self.blfields['operation'], text='')
|
layout.prop(self, self.blfields['operation'], text='')
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - FlowKind.Value|LazyValueFunc
|
# - FlowKind.Value|Func
|
||||||
####################
|
####################
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
'Expr',
|
'Expr',
|
||||||
|
@ -497,16 +497,14 @@ class MapMathNode(base.MaxwellSimNode):
|
||||||
|
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
'Expr',
|
'Expr',
|
||||||
kind=ct.FlowKind.LazyValueFunc,
|
kind=ct.FlowKind.Func,
|
||||||
props={'operation'},
|
props={'operation'},
|
||||||
input_sockets={'Expr'},
|
input_sockets={'Expr'},
|
||||||
input_socket_kinds={
|
input_socket_kinds={
|
||||||
'Expr': ct.FlowKind.LazyValueFunc,
|
'Expr': ct.FlowKind.Func,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def compute_func(
|
def compute_func(self, props, input_sockets) -> ct.FuncFlow | ct.FlowSignal:
|
||||||
self, props, input_sockets
|
|
||||||
) -> ct.LazyValueFuncFlow | ct.FlowSignal:
|
|
||||||
operation = props['operation']
|
operation = props['operation']
|
||||||
expr = input_sockets['Expr']
|
expr = input_sockets['Expr']
|
||||||
|
|
||||||
|
|
|
@ -261,12 +261,12 @@ class OperateMathNode(base.MaxwellSimNode):
|
||||||
bl_label = 'Operate Math'
|
bl_label = 'Operate Math'
|
||||||
|
|
||||||
input_sockets: typ.ClassVar = {
|
input_sockets: typ.ClassVar = {
|
||||||
'Expr L': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc),
|
'Expr L': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func),
|
||||||
'Expr R': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc),
|
'Expr R': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func),
|
||||||
}
|
}
|
||||||
output_sockets: typ.ClassVar = {
|
output_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(
|
'Expr': sockets.ExprSocketDef(
|
||||||
active_kind=ct.FlowKind.LazyValueFunc, show_info_columns=True
|
active_kind=ct.FlowKind.Func, show_info_columns=True
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +344,7 @@ class OperateMathNode(base.MaxwellSimNode):
|
||||||
layout.prop(self, self.blfields['operation'], text='')
|
layout.prop(self, self.blfields['operation'], text='')
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - FlowKind.Value|LazyValueFunc
|
# - FlowKind.Value|Func
|
||||||
####################
|
####################
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
'Expr',
|
'Expr',
|
||||||
|
@ -373,12 +373,12 @@ class OperateMathNode(base.MaxwellSimNode):
|
||||||
|
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
'Expr',
|
'Expr',
|
||||||
kind=ct.FlowKind.LazyValueFunc,
|
kind=ct.FlowKind.Func,
|
||||||
props={'operation'},
|
props={'operation'},
|
||||||
input_sockets={'Expr L', 'Expr R'},
|
input_sockets={'Expr L', 'Expr R'},
|
||||||
input_socket_kinds={
|
input_socket_kinds={
|
||||||
'Expr L': ct.FlowKind.LazyValueFunc,
|
'Expr L': ct.FlowKind.Func,
|
||||||
'Expr R': ct.FlowKind.LazyValueFunc,
|
'Expr R': ct.FlowKind.Func,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def compose_func(self, props: dict, input_sockets: dict):
|
def compose_func(self, props: dict, input_sockets: dict):
|
||||||
|
|
|
@ -97,7 +97,7 @@ class ReduceMathNode(base.MaxwellSimNode):
|
||||||
'Data',
|
'Data',
|
||||||
props={'active_socket_set', 'operation'},
|
props={'active_socket_set', 'operation'},
|
||||||
input_sockets={'Data', 'Axis', 'Reducer'},
|
input_sockets={'Data', 'Axis', 'Reducer'},
|
||||||
input_socket_kinds={'Reducer': ct.FlowKind.LazyValueFunc},
|
input_socket_kinds={'Reducer': ct.FlowKind.Func},
|
||||||
input_sockets_optional={'Reducer': True},
|
input_sockets_optional={'Reducer': True},
|
||||||
)
|
)
|
||||||
def compute_data(self, props: dict, input_sockets: dict):
|
def compute_data(self, props: dict, input_sockets: dict):
|
||||||
|
|
|
@ -258,10 +258,10 @@ class TransformMathNode(base.MaxwellSimNode):
|
||||||
bl_label = 'Transform Math'
|
bl_label = 'Transform Math'
|
||||||
|
|
||||||
input_sockets: typ.ClassVar = {
|
input_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc),
|
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func),
|
||||||
}
|
}
|
||||||
output_sockets: typ.ClassVar = {
|
output_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc),
|
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func),
|
||||||
}
|
}
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
@ -323,7 +323,7 @@ class TransformMathNode(base.MaxwellSimNode):
|
||||||
layout.prop(self, self.blfields['operation'], text='')
|
layout.prop(self, self.blfields['operation'], text='')
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - Compute: LazyValueFunc / Array
|
# - Compute: Func / Array
|
||||||
####################
|
####################
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
'Expr',
|
'Expr',
|
||||||
|
@ -346,16 +346,14 @@ class TransformMathNode(base.MaxwellSimNode):
|
||||||
|
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
'Expr',
|
'Expr',
|
||||||
kind=ct.FlowKind.LazyValueFunc,
|
kind=ct.FlowKind.Func,
|
||||||
props={'operation'},
|
props={'operation'},
|
||||||
input_sockets={'Expr'},
|
input_sockets={'Expr'},
|
||||||
input_socket_kinds={
|
input_socket_kinds={
|
||||||
'Expr': ct.FlowKind.LazyValueFunc,
|
'Expr': ct.FlowKind.Func,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
def compute_func(
|
def compute_func(self, props, input_sockets) -> ct.FuncFlow | ct.FlowSignal:
|
||||||
self, props, input_sockets
|
|
||||||
) -> ct.LazyValueFuncFlow | ct.FlowSignal:
|
|
||||||
operation = props['operation']
|
operation = props['operation']
|
||||||
expr = input_sockets['Expr']
|
expr = input_sockets['Expr']
|
||||||
|
|
||||||
|
|
|
@ -209,7 +209,7 @@ class VizNode(base.MaxwellSimNode):
|
||||||
####################
|
####################
|
||||||
input_sockets: typ.ClassVar = {
|
input_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(
|
'Expr': sockets.ExprSocketDef(
|
||||||
active_kind=ct.FlowKind.LazyValueFunc,
|
active_kind=ct.FlowKind.Func,
|
||||||
default_symbols=[sim_symbols.x],
|
default_symbols=[sim_symbols.x],
|
||||||
default_value=2 * sim_symbols.x.sp_symbol,
|
default_value=2 * sim_symbols.x.sp_symbol,
|
||||||
),
|
),
|
||||||
|
@ -370,7 +370,7 @@ class VizNode(base.MaxwellSimNode):
|
||||||
props={'viz_mode', 'viz_target', 'colormap'},
|
props={'viz_mode', 'viz_target', 'colormap'},
|
||||||
input_sockets={'Expr'},
|
input_sockets={'Expr'},
|
||||||
input_socket_kinds={
|
input_socket_kinds={
|
||||||
'Expr': {ct.FlowKind.LazyValueFunc, ct.FlowKind.Info, ct.FlowKind.Params}
|
'Expr': {ct.FlowKind.Func, ct.FlowKind.Info, ct.FlowKind.Params}
|
||||||
},
|
},
|
||||||
all_loose_input_sockets=True,
|
all_loose_input_sockets=True,
|
||||||
)
|
)
|
||||||
|
@ -382,7 +382,7 @@ class VizNode(base.MaxwellSimNode):
|
||||||
props={'viz_mode', 'viz_target', 'colormap'},
|
props={'viz_mode', 'viz_target', 'colormap'},
|
||||||
input_sockets={'Expr'},
|
input_sockets={'Expr'},
|
||||||
input_socket_kinds={
|
input_socket_kinds={
|
||||||
'Expr': {ct.FlowKind.LazyValueFunc, ct.FlowKind.Info, ct.FlowKind.Params}
|
'Expr': {ct.FlowKind.Func, ct.FlowKind.Info, ct.FlowKind.Params}
|
||||||
},
|
},
|
||||||
unit_systems={'BlenderUnits': ct.UNITS_BLENDER},
|
unit_systems={'BlenderUnits': ct.UNITS_BLENDER},
|
||||||
all_loose_input_sockets=True,
|
all_loose_input_sockets=True,
|
||||||
|
@ -392,7 +392,7 @@ class VizNode(base.MaxwellSimNode):
|
||||||
self, managed_objs, props, input_sockets, loose_input_sockets, unit_systems
|
self, managed_objs, props, input_sockets, loose_input_sockets, unit_systems
|
||||||
):
|
):
|
||||||
# Retrieve Inputs
|
# Retrieve Inputs
|
||||||
lazy_value_func = input_sockets['Expr'][ct.FlowKind.LazyValueFunc]
|
lazy_func = input_sockets['Expr'][ct.FlowKind.Func]
|
||||||
info = input_sockets['Expr'][ct.FlowKind.Info]
|
info = input_sockets['Expr'][ct.FlowKind.Info]
|
||||||
params = input_sockets['Expr'][ct.FlowKind.Params]
|
params = input_sockets['Expr'][ct.FlowKind.Params]
|
||||||
|
|
||||||
|
@ -422,9 +422,9 @@ class VizNode(base.MaxwellSimNode):
|
||||||
for sym in params.sorted_symbols
|
for sym in params.sorted_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
# Realize LazyValueFunc w/Symbolic Values, Unit System
|
# Realize Func w/Symbolic Values, Unit System
|
||||||
## -> This gives us the actual plot data!
|
## -> This gives us the actual plot data!
|
||||||
data = lazy_value_func.func_jax(
|
data = lazy_func.func_jax(
|
||||||
*params.scaled_func_args(
|
*params.scaled_func_args(
|
||||||
unit_systems['BlenderUnits'], symbol_values=symbol_values
|
unit_systems['BlenderUnits'], symbol_values=symbol_values
|
||||||
),
|
),
|
||||||
|
|
|
@ -29,12 +29,12 @@ class ExprConstantNode(base.MaxwellSimNode):
|
||||||
|
|
||||||
input_sockets: typ.ClassVar = {
|
input_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(
|
'Expr': sockets.ExprSocketDef(
|
||||||
active_kind=ct.FlowKind.LazyValueFunc,
|
active_kind=ct.FlowKind.Func,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
output_sockets: typ.ClassVar = {
|
output_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(
|
'Expr': sockets.ExprSocketDef(
|
||||||
active_kind=ct.FlowKind.LazyValueFunc,
|
active_kind=ct.FlowKind.Func,
|
||||||
show_info_columns=True,
|
show_info_columns=True,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -58,12 +58,12 @@ class ExprConstantNode(base.MaxwellSimNode):
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
# Trigger
|
# Trigger
|
||||||
'Expr',
|
'Expr',
|
||||||
kind=ct.FlowKind.LazyValueFunc,
|
kind=ct.FlowKind.Func,
|
||||||
# Loaded
|
# Loaded
|
||||||
input_sockets={'Expr'},
|
input_sockets={'Expr'},
|
||||||
input_socket_kinds={'Expr': ct.FlowKind.LazyValueFunc},
|
input_socket_kinds={'Expr': ct.FlowKind.Func},
|
||||||
)
|
)
|
||||||
def compute_lazy_value_func(self, input_sockets: dict) -> typ.Any:
|
def compute_lazy_func(self, input_sockets: dict) -> typ.Any:
|
||||||
return input_sockets['Expr']
|
return input_sockets['Expr']
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
|
|
@ -42,7 +42,7 @@ class DataFileImporterNode(base.MaxwellSimNode):
|
||||||
'File Path': sockets.FilePathSocketDef(),
|
'File Path': sockets.FilePathSocketDef(),
|
||||||
}
|
}
|
||||||
output_sockets: typ.ClassVar = {
|
output_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc),
|
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func),
|
||||||
}
|
}
|
||||||
|
|
||||||
####################
|
####################
|
||||||
|
@ -121,11 +121,11 @@ class DataFileImporterNode(base.MaxwellSimNode):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - FlowKind.Array|LazyValueFunc
|
# - FlowKind.Array|Func
|
||||||
####################
|
####################
|
||||||
@events.computes_output_socket(
|
@events.computes_output_socket(
|
||||||
'Expr',
|
'Expr',
|
||||||
kind=ct.FlowKind.LazyValueFunc,
|
kind=ct.FlowKind.Func,
|
||||||
input_sockets={'File Path'},
|
input_sockets={'File Path'},
|
||||||
)
|
)
|
||||||
def compute_func(self, input_sockets: dict) -> td.Simulation:
|
def compute_func(self, input_sockets: dict) -> td.Simulation:
|
||||||
|
@ -144,7 +144,7 @@ class DataFileImporterNode(base.MaxwellSimNode):
|
||||||
# Jax Compatibility: Lazy Data Loading
|
# Jax Compatibility: Lazy Data Loading
|
||||||
## -> Delay loading of data from file as long as we can.
|
## -> Delay loading of data from file as long as we can.
|
||||||
if data_file_format.loader_is_jax_compatible:
|
if data_file_format.loader_is_jax_compatible:
|
||||||
return ct.LazyValueFuncFlow(
|
return ct.FuncFlow(
|
||||||
func=lambda: data_file_format.loader(file_path),
|
func=lambda: data_file_format.loader(file_path),
|
||||||
supports_jax=True,
|
supports_jax=True,
|
||||||
)
|
)
|
||||||
|
@ -152,7 +152,7 @@ class DataFileImporterNode(base.MaxwellSimNode):
|
||||||
# No Jax Compatibility: Eager Data Loading
|
# No Jax Compatibility: Eager Data Loading
|
||||||
## -> Load the data now and bind it.
|
## -> Load the data now and bind it.
|
||||||
data = data_file_format.loader(file_path)
|
data = data_file_format.loader(file_path)
|
||||||
return ct.LazyValueFuncFlow(func=lambda: data, supports_jax=True)
|
return ct.FuncFlow(func=lambda: data, supports_jax=True)
|
||||||
return ct.FlowSignal.FlowPending
|
return ct.FlowSignal.FlowPending
|
||||||
return ct.FlowSignal.FlowPending
|
return ct.FlowSignal.FlowPending
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ class DataFileImporterNode(base.MaxwellSimNode):
|
||||||
'Expr',
|
'Expr',
|
||||||
kind=ct.FlowKind.Info,
|
kind=ct.FlowKind.Info,
|
||||||
output_sockets={'Expr'},
|
output_sockets={'Expr'},
|
||||||
output_socket_kinds={'Expr': ct.FlowKind.LazyValueFunc},
|
output_socket_kinds={'Expr': ct.FlowKind.Func},
|
||||||
)
|
)
|
||||||
def compute_info(self, output_sockets) -> ct.InfoFlow:
|
def compute_info(self, output_sockets) -> ct.InfoFlow:
|
||||||
"""Declare an `InfoFlow` based on the data shape.
|
"""Declare an `InfoFlow` based on the data shape.
|
||||||
|
|
|
@ -66,7 +66,7 @@ class DataFileExporterNode(base.MaxwellSimNode):
|
||||||
bl_label = 'Data File Importer'
|
bl_label = 'Data File Importer'
|
||||||
|
|
||||||
input_sockets: typ.ClassVar = {
|
input_sockets: typ.ClassVar = {
|
||||||
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.LazyValueFunc),
|
'Expr': sockets.ExprSocketDef(active_kind=ct.FlowKind.Func),
|
||||||
'File Path': sockets.FilePathSocketDef(),
|
'File Path': sockets.FilePathSocketDef(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,8 +95,8 @@ class DataFileExporterNode(base.MaxwellSimNode):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def expr_data(self) -> typ.Any | None:
|
def expr_data(self) -> typ.Any | None:
|
||||||
"""Retrieve the input expression's data by evaluating its `LazyValueFunc`."""
|
"""Retrieve the input expression's data by evaluating its `Func`."""
|
||||||
func = self._compute_input('Expr', kind=ct.FlowKind.LazyValueFunc)
|
func = self._compute_input('Expr', kind=ct.FlowKind.Func)
|
||||||
params = self._compute_input('Expr', kind=ct.FlowKind.Params)
|
params = self._compute_input('Expr', kind=ct.FlowKind.Params)
|
||||||
|
|
||||||
has_func = not ct.FlowSignal.check(func)
|
has_func = not ct.FlowSignal.check(func)
|
||||||
|
|
|
@ -133,7 +133,7 @@ class TemporalShapeNode(base.MaxwellSimNode):
|
||||||
},
|
},
|
||||||
input_socket_kinds={
|
input_socket_kinds={
|
||||||
't Range': ct.FlowKind.Range,
|
't Range': ct.FlowKind.Range,
|
||||||
'Envelope': ct.FlowKind.LazyValueFunc,
|
'Envelope': ct.FlowKind.Func,
|
||||||
},
|
},
|
||||||
input_sockets_optional={
|
input_sockets_optional={
|
||||||
'max E': True,
|
'max E': True,
|
||||||
|
|
|
@ -525,9 +525,9 @@ class MaxwellSimSocket(bpy.types.NodeSocket, bl_instance.BLInstance):
|
||||||
msg = f'Socket {self.bl_label} {self.socket_type}): Tried to set "ct.FlowKind.Array", but socket does not define it'
|
msg = f'Socket {self.bl_label} {self.socket_type}): Tried to set "ct.FlowKind.Array", but socket does not define it'
|
||||||
raise NotImplementedError(msg)
|
raise NotImplementedError(msg)
|
||||||
|
|
||||||
# LazyValueFunc
|
# Func
|
||||||
@property
|
@property
|
||||||
def lazy_value_func(self) -> ct.LazyValueFuncFlow:
|
def lazy_func(self) -> ct.FuncFlow:
|
||||||
"""Throws a descriptive error.
|
"""Throws a descriptive error.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
@ -538,8 +538,8 @@ class MaxwellSimSocket(bpy.types.NodeSocket, bl_instance.BLInstance):
|
||||||
"""
|
"""
|
||||||
return ct.FlowSignal.NoFlow
|
return ct.FlowSignal.NoFlow
|
||||||
|
|
||||||
@lazy_value_func.setter
|
@lazy_func.setter
|
||||||
def lazy_value_func(self, lazy_value_func: ct.LazyValueFuncFlow) -> None:
|
def lazy_func(self, lazy_func: ct.FuncFlow) -> None:
|
||||||
"""Throws a descriptive error.
|
"""Throws a descriptive error.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
@ -548,7 +548,7 @@ class MaxwellSimSocket(bpy.types.NodeSocket, bl_instance.BLInstance):
|
||||||
Raises:
|
Raises:
|
||||||
NotImplementedError: When used without being overridden.
|
NotImplementedError: When used without being overridden.
|
||||||
"""
|
"""
|
||||||
msg = f'Socket {self.bl_label} {self.socket_type}): Tried to set "ct.FlowKind.LazyValueFunc", but socket does not define it'
|
msg = f'Socket {self.bl_label} {self.socket_type}): Tried to set "ct.FlowKind.Func", but socket does not define it'
|
||||||
raise NotImplementedError(msg)
|
raise NotImplementedError(msg)
|
||||||
|
|
||||||
# Range
|
# Range
|
||||||
|
@ -595,7 +595,7 @@ class MaxwellSimSocket(bpy.types.NodeSocket, bl_instance.BLInstance):
|
||||||
kind_data_map = {
|
kind_data_map = {
|
||||||
ct.FlowKind.Value: lambda: self.value,
|
ct.FlowKind.Value: lambda: self.value,
|
||||||
ct.FlowKind.Array: lambda: self.array,
|
ct.FlowKind.Array: lambda: self.array,
|
||||||
ct.FlowKind.LazyValueFunc: lambda: self.lazy_value_func,
|
ct.FlowKind.Func: lambda: self.lazy_func,
|
||||||
ct.FlowKind.Range: lambda: self.lazy_range,
|
ct.FlowKind.Range: lambda: self.lazy_range,
|
||||||
ct.FlowKind.Params: lambda: self.params,
|
ct.FlowKind.Params: lambda: self.params,
|
||||||
ct.FlowKind.Info: lambda: self.info,
|
ct.FlowKind.Info: lambda: self.info,
|
||||||
|
@ -784,7 +784,7 @@ class MaxwellSimSocket(bpy.types.NodeSocket, bl_instance.BLInstance):
|
||||||
ct.FlowKind.Value: self.draw_value,
|
ct.FlowKind.Value: self.draw_value,
|
||||||
ct.FlowKind.Array: self.draw_array,
|
ct.FlowKind.Array: self.draw_array,
|
||||||
ct.FlowKind.Range: self.draw_lazy_range,
|
ct.FlowKind.Range: self.draw_lazy_range,
|
||||||
ct.FlowKind.LazyValueFunc: self.draw_lazy_value_func,
|
ct.FlowKind.Func: self.draw_lazy_func,
|
||||||
}[self.active_kind](col)
|
}[self.active_kind](col)
|
||||||
|
|
||||||
# Info Drawing
|
# Info Drawing
|
||||||
|
@ -914,11 +914,11 @@ class MaxwellSimSocket(bpy.types.NodeSocket, bl_instance.BLInstance):
|
||||||
col: Target for defining UI elements.
|
col: Target for defining UI elements.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def draw_lazy_value_func(self, col: bpy.types.UILayout) -> None:
|
def draw_lazy_func(self, col: bpy.types.UILayout) -> None:
|
||||||
"""Draws the socket lazy value function UI on its own line.
|
"""Draws the socket lazy value function UI on its own line.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
Should be overriden by individual socket classes, if they have an editable `FlowKind.LazyValueFunc`.
|
Should be overriden by individual socket classes, if they have an editable `FlowKind.Func`.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
col: Target for defining UI elements.
|
col: Target for defining UI elements.
|
||||||
|
|
|
@ -100,7 +100,7 @@ class ExprBLSocket(base.MaxwellSimSocket):
|
||||||
When active, `self.active_unit` can be used via the UI to select valid unit of the given `self.physical_type`, and `self.unit` works.
|
When active, `self.active_unit` can be used via the UI to select valid unit of the given `self.physical_type`, and `self.unit` works.
|
||||||
The enum itself can be dynamically altered, ex. via its UI dropdown support.
|
The enum itself can be dynamically altered, ex. via its UI dropdown support.
|
||||||
symbols: The symbolic variables valid in the context of the expression.
|
symbols: The symbolic variables valid in the context of the expression.
|
||||||
Various features, including `LazyValueFunc` support, become available when symbols are in use.
|
Various features, including `Func` support, become available when symbols are in use.
|
||||||
The presence of symbols forces fallback to a string-based `sympy` expression UI.
|
The presence of symbols forces fallback to a string-based `sympy` expression UI.
|
||||||
|
|
||||||
active_unit: The currently active unit, as a dropdown.
|
active_unit: The currently active unit, as a dropdown.
|
||||||
|
@ -544,20 +544,20 @@ class ExprBLSocket(base.MaxwellSimSocket):
|
||||||
]
|
]
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# - FlowKind: LazyValueFunc (w/Params if Constant)
|
# - FlowKind: Func (w/Params if Constant)
|
||||||
####################
|
####################
|
||||||
@property
|
@property
|
||||||
def lazy_value_func(self) -> ct.LazyValueFuncFlow:
|
def lazy_func(self) -> ct.FuncFlow:
|
||||||
"""Returns a lazy value that computes the expression returned by `self.value`.
|
"""Returns a lazy value that computes the expression returned by `self.value`.
|
||||||
|
|
||||||
If `self.value` has unknown symbols (as indicated by `self.symbols`), then these will be the arguments of the `LazyValueFuncFlow`.
|
If `self.value` has unknown symbols (as indicated by `self.symbols`), then these will be the arguments of the `FuncFlow`.
|
||||||
Otherwise, the returned lazy value function will be a simple excuse for `self.params` to pass the verbatim `self.value`.
|
Otherwise, the returned lazy value function will be a simple excuse for `self.params` to pass the verbatim `self.value`.
|
||||||
"""
|
"""
|
||||||
# Symbolic
|
# Symbolic
|
||||||
## -> `self.value` is guaranteed to be an expression with unknowns.
|
## -> `self.value` is guaranteed to be an expression with unknowns.
|
||||||
## -> The function computes `self.value` with unknowns as arguments.
|
## -> The function computes `self.value` with unknowns as arguments.
|
||||||
if self.symbols:
|
if self.symbols:
|
||||||
return ct.LazyValueFuncFlow(
|
return ct.FuncFlow(
|
||||||
func=sp.lambdify(
|
func=sp.lambdify(
|
||||||
self.sorted_symbols,
|
self.sorted_symbols,
|
||||||
spux.scale_to_unit(self.value, self.unit),
|
spux.scale_to_unit(self.value, self.unit),
|
||||||
|
@ -572,7 +572,7 @@ class ExprBLSocket(base.MaxwellSimSocket):
|
||||||
## -> ("Dummy" as in returns the same argument that it takes).
|
## -> ("Dummy" as in returns the same argument that it takes).
|
||||||
## -> This is an excuse to let `ParamsFlow` pass `self.value` verbatim.
|
## -> This is an excuse to let `ParamsFlow` pass `self.value` verbatim.
|
||||||
## -> Generally only useful for operations with other expressions.
|
## -> Generally only useful for operations with other expressions.
|
||||||
return ct.LazyValueFuncFlow(
|
return ct.FuncFlow(
|
||||||
func=lambda v: v,
|
func=lambda v: v,
|
||||||
func_args=[
|
func_args=[
|
||||||
self.physical_type if self.physical_type is not None else self.mathtype
|
self.physical_type if self.physical_type is not None else self.mathtype
|
||||||
|
@ -582,7 +582,7 @@ class ExprBLSocket(base.MaxwellSimSocket):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def params(self) -> ct.ParamsFlow:
|
def params(self) -> ct.ParamsFlow:
|
||||||
"""Returns parameter symbols/values to accompany `self.lazy_value_func`.
|
"""Returns parameter symbols/values to accompany `self.lazy_func`.
|
||||||
|
|
||||||
If `self.value` has unknown symbols (as indicated by `self.symbols`), then these will be passed into `ParamsFlow`, which will thus be parameterized (and require realization before use).
|
If `self.value` has unknown symbols (as indicated by `self.symbols`), then these will be passed into `ParamsFlow`, which will thus be parameterized (and require realization before use).
|
||||||
Otherwise, `self.value` is passed verbatim as the only `ParamsFlow.func_arg`.
|
Otherwise, `self.value` is passed verbatim as the only `ParamsFlow.func_arg`.
|
||||||
|
@ -605,13 +605,13 @@ class ExprBLSocket(base.MaxwellSimSocket):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def info(self) -> ct.ArrayFlow:
|
def info(self) -> ct.ArrayFlow:
|
||||||
r"""Returns parameter symbols/values to accompany `self.lazy_value_func`.
|
r"""Returns parameter symbols/values to accompany `self.lazy_func`.
|
||||||
|
|
||||||
The output name/size/mathtype/unit corresponds directly the `ExprSocket`.
|
The output name/size/mathtype/unit corresponds directly the `ExprSocket`.
|
||||||
|
|
||||||
If `self.symbols` has entries, then these will propagate as dimensions with unresolvable `RangeFlow` index descriptions.
|
If `self.symbols` has entries, then these will propagate as dimensions with unresolvable `RangeFlow` index descriptions.
|
||||||
The index range will be $(-\infty,\infty)$, with $0$ steps and no unit.
|
The index range will be $(-\infty,\infty)$, with $0$ steps and no unit.
|
||||||
The order/naming matches `self.params` and `self.lazy_value_func`.
|
The order/naming matches `self.params` and `self.lazy_func`.
|
||||||
|
|
||||||
Otherwise, only the output name/size/mathtype/unit corresponding to the socket is passed along.
|
Otherwise, only the output name/size/mathtype/unit corresponding to the socket is passed along.
|
||||||
"""
|
"""
|
||||||
|
@ -835,13 +835,13 @@ class ExprBLSocket(base.MaxwellSimSocket):
|
||||||
if self.steps != 0:
|
if self.steps != 0:
|
||||||
col.prop(self, self.blfields['steps'], text='')
|
col.prop(self, self.blfields['steps'], text='')
|
||||||
|
|
||||||
def draw_lazy_value_func(self, col: bpy.types.UILayout) -> None:
|
def draw_lazy_func(self, col: bpy.types.UILayout) -> None:
|
||||||
"""Draw the socket body for a single flexible value/expression, for down-chain lazy evaluation.
|
"""Draw the socket body for a single flexible value/expression, for down-chain lazy evaluation.
|
||||||
|
|
||||||
This implements the most flexible variant of the `ExprSocket` UI, providing the user with full runtime-configuration of the exact `self.size`, `self.mathtype`, `self.physical_type`, and `self.symbols` of the expression.
|
This implements the most flexible variant of the `ExprSocket` UI, providing the user with full runtime-configuration of the exact `self.size`, `self.mathtype`, `self.physical_type`, and `self.symbols` of the expression.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
Drawn when `self.active_kind == FlowKind.LazyValueFunc`.
|
Drawn when `self.active_kind == FlowKind.Func`.
|
||||||
|
|
||||||
This is an ideal choice for ex. math nodes that need to accept arbitrary expressions as inputs, with an eye towards lazy evaluation of ex. symbolic terms.
|
This is an ideal choice for ex. math nodes that need to accept arbitrary expressions as inputs, with an eye towards lazy evaluation of ex. symbolic terms.
|
||||||
|
|
||||||
|
@ -872,7 +872,7 @@ class ExprBLSocket(base.MaxwellSimSocket):
|
||||||
# - UI: InfoFlow
|
# - UI: InfoFlow
|
||||||
####################
|
####################
|
||||||
def draw_info(self, info: ct.InfoFlow, col: bpy.types.UILayout) -> None:
|
def draw_info(self, info: ct.InfoFlow, col: bpy.types.UILayout) -> None:
|
||||||
if self.active_kind == ct.FlowKind.LazyValueFunc and self.show_info_columns:
|
if self.active_kind == ct.FlowKind.Func and self.show_info_columns:
|
||||||
row = col.row()
|
row = col.row()
|
||||||
box = row.box()
|
box = row.box()
|
||||||
grid = box.grid_flow(
|
grid = box.grid_flow(
|
||||||
|
@ -927,7 +927,7 @@ class ExprSocketDef(base.SocketDef):
|
||||||
ct.FlowKind.Value,
|
ct.FlowKind.Value,
|
||||||
ct.FlowKind.Range,
|
ct.FlowKind.Range,
|
||||||
ct.FlowKind.Array,
|
ct.FlowKind.Array,
|
||||||
ct.FlowKind.LazyValueFunc,
|
ct.FlowKind.Func,
|
||||||
] = ct.FlowKind.Value
|
] = ct.FlowKind.Value
|
||||||
|
|
||||||
# Socket Interface
|
# Socket Interface
|
||||||
|
|
Loading…
Reference in New Issue