# Felix sparse field idea ## Case: Current implementation (assumes `s` is pre-shifted) - sparse field `s: Field[V,V2E]` - `e: Field[E]` ```python= def sten(e, s): return reduce(dot, 0.0)(s, shift(V2E)(e)) ``` ### In field view ```python= def sten(e: Field[Edge], s: Field[Vertex, V2EDim]) -> Field[Vertex] return neighbor_sum(e(V2E) * s, axis=V2EDim) ``` ## New idea - new dimension (location type) let's call it `VE` with points living on the connection between Vertex and Edge neighbors (no order, it's not V2E or E2V) - sparse field `s: Field[VE]` - connectivity mapping from VE to edge location `V2VE` ```python= def sten(e, s): return reduce(dot, 0.0)(shift(V2VE)(s), shift(V2E)(e)) ``` ### In field view `V2VE` maps from `VE` to `Vertex, V2EDim` `V2E` maps from `Edge` to `Vertex, V2EDim` ```python= def sten(e: Field[Edge], s: Field[VE]) -> Field[Vertex] return neighbor_sum(e(V2E) * s(V2VE), axis=V2EDim) ``` #### Note There is also a (ineffecient) mapping `E2VE`, which maps from `VE` to `Edge, E2VDim`. Inefficient because neighbors are not ordered in the `Field[VE]`, if they were ordered for `V2VE`. ### Picture ``` (0v) ---0e--- (1v) ---1e--- (2v) 0ve 1ve 2ve 3ve ``` ``` V2VE_tbl = [[-1, 0], [1, 2], [3, -1]] E2VE_tbl = [[0, 1], [2,3]] ``` ## Notes CE: C2CE EC: E2CE ### Other ideas ```python= # e, s are iterator pointing to Vertex shift(V2E_,0)(s) # is now pointing to (Vertex, V2EDim) return shift(V2E_,0)(s)*shift(V2E,0)(e)+... ``` ```python= def sten(e0: Field[Edge, MyDim], e1: Field[Edge, MyDim]) -> Field[Vertex] return sum(e1(offset) * e1(offset) for offset in V2E) return e1(V2E)[V2E(0)] * e1(V2E[0]) + e1(V2E[1] * e2(V2E[1] + ...)) ```