GitHub user gidhubuser255 created a discussion: APIs for updating underlying 
function of a node (2 part question)

### (1) Updating function logic
For reference consider the following DAG

```
def A(B: int, C: int) -> int:
    return B + C

def B(D: int) -> int:
    return D + 1

def C(D: int) -> int:
    return D + 2

def D() -> int:
    return 7

dr = driver.Builder().with_modules(__import__('__main__')).build()
dr.execute('A')  # returns 17
```

If I want to update the logic of `B` in the DAG with some function 
`alternative_B`, the best way I've found to do so is to do the following:
```
@config.when(use_alternative_b=False)
def B(D: int) -> int:
    return D + 1

@config.when(name='B', use_alternative_b=True)
def alternative_B(C: int, D: int) -> int:
    return C + D

dr = (
    driver.Builder()
    .with_modules(__import__('__main__'))
    .with_config(use_alternative_b=True)
    .build()
)
dr.execute('A')  # returns 25
```
Which is a bit cumbersome, since it requires modifying source code and adding 
configuration primitives to enable the ability.

An alternative way to do this is how the fn_graph library handles this 
(https://fn-graph.readthedocs.io/en/latest/usage.html#building-up-logic), which 
provides a similar ability to update the implementation of a node by allowing 
you to make updates on your "driver" (called composer in fn_graph). For example 
to achieve the same ability in fn_graph you can do this, no decorators or 
additional config entities needed:
```
composer = Composer().update(A, B, C, D)  # these are all the same defined 
functions as above
composer2 = composer.update(B=alternative_B)  # just plain defined function, no 
decorators
composer3 = composer2.update(B=alternative_B2)

composer2.A()
composer3.A()
```
**Questions:**
1. Is there a similar existing mechanism to this in Hamilton?
2. If not could it be added?

### (2) Updating function logic in a specific branch
Similar to the above consider when you want to update the implementation for a 
function, but only when the path from that function to the root executed 
function passes through another specific node/function.

For example if I want to update `D` to `D__prime` but only in the path that 
includes `B`, in Hamilton I could achieve that like so:
```
def A(B: int, C: int) -> int:
    return B + C

def B(D_thru_B: int) -> int:
    return D + 1

def C(D: int) -> int:
    return D + 2

@config.when(use_d_prime=False)
def D_thru_B(D: int) -> int:
    return D

@config.when(name='D_thru_B', use_d_prime=True)
def D__prime(D: int) -> int:
    return D * 2

def D() -> int:
    return 7
```
But this has a couple problems: (a) if I want to later update all references to 
`D` with `D__prime` (not just through `B`) I'll need to add another `D__prime2` 
with a `config.when(name='D', ...)` and a new config parameter, which is again 
pretty cumbersome. And more importantly (b) this method breaks down when the 
branch specific replacement happens behind a converging point, for example:
```
def A(B: int, C: int) -> int:
    return B + C

def B(D: int) -> int:
    return D + 1

def C(D: int) -> int:
    return D + 2

def D(X: int) -> int:
    return X + 1

def X() -> int:
    return 9
```
If I want to replace `X` in the path of `B` with this method I would need to 
bifurcate all my functions starting at the converging point (`D_thru_B`, 
`X_thru_B`, `D_thru_C`, `X_thru_C`, etc), which would be prohibitive for 
anything more than a very simple example.

**Questions:**
1. Is there a good existing way to achieve this? I'm thinking there's probably 
a way using the existing `Parallelizable` and `Collect` mechanism which can 
already dynamically generate new nodes to add to the graph, and which could be 
used to do the bifurcation I mentioned?
2. Would it be possible to add the ability to do this with something more like 
the fn_graph style api, something like `driver.update(X=X__prime, 
in_path=['B']) `


GitHub link: https://github.com/apache/hamilton/discussions/1397

----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to: 
[email protected]

Reply via email to