# Connecting Elements

This guide covers the different ways to connect elements in a pipeline.

## Automatic Matching with `connect()`

The simplest way to connect two elements is `pipeline.connect()`. It
automatically matches pads with the same name:

```python
from sgn import Pipeline, IterSource, NullSink

src = IterSource(name="src", source_pad_names=["H1", "L1"],
                 iters={"H1": [1], "L1": [2]})
snk = NullSink(name="snk", sink_pad_names=["H1", "L1"])

p = Pipeline()
p.connect(src, snk)  # H1->H1 and L1->L1 automatically
p.run()
```

## Explicit Mapping with `link_map`

When pad names differ, pass a `link_map` mapping sink pad names to source pad
names:

```python
from sgn import Pipeline, IterSource, NullSink

src = IterSource(name="src", source_pad_names=["output"],
                 iters={"output": [1]})
snk = NullSink(name="snk", sink_pad_names=["input"])

p = Pipeline()
p.connect(src, snk, link_map={"input": "output"})
p.run()
```

## Low-Level: `insert()` and `link()`

For full control, use `insert()` to add elements and `link()` to connect pads
by their full names (`element:type:pad`):

```python
from sgn import Pipeline, IterSource, NullSink

src = IterSource(name="src", source_pad_names=["H1"],
                 iters={"H1": [1]})
snk = NullSink(name="snk", sink_pad_names=["H1"])

p = Pipeline()
p.insert(src, snk, link_map={"snk:snk:H1": "src:src:H1"})
p.run()
```

Full pad names follow the pattern `element_name:pad_type:pad_name` where
`pad_type` is `src` for source pads and `snk` for sink pads.

## Linking Strategies

When using `connect()` without a `link_map`, SGN tries these strategies in
order:

| Strategy | Condition | Behavior |
|---|---|---|
| **Exact match** | Source and sink pad names are identical | Connect matching names 1:1 |
| **Partial match** | Some names overlap | Connect only the matching names |
| **N-to-1** | Single sink pad, multiple source pads | Connect all sources to that one sink |
| **1-to-N** | Single source pad, multiple sink pads | Connect that one source to all sinks |

If none of these strategies apply unambiguously, SGN raises a `ValueError` and
you must provide an explicit `link_map`.

### Partial Match

```python
from sgn import Pipeline, IterSource, NullSink

# Source has H1, L1, V1 but sink only has H1, L1
src = IterSource(name="src", source_pad_names=["H1", "L1", "V1"],
                 iters={"H1": [1], "L1": [2], "V1": [3]})
snk = NullSink(name="snk", sink_pad_names=["H1", "L1"])

p = Pipeline()
# Only H1 and L1 get connected; V1 is unlinked
# (Pipeline.check() would warn about unlinked V1 pad)
p.insert(src, snk)
p.connect(src, snk)  # Partial match: H1->H1, L1->L1
```

### N-to-1 (Fan-in)

```{.python notest}
from sgn import Pipeline, IterSource, NullSink

src1 = IterSource(name="s1", source_pad_names=["H1"], iters={"H1": [1]})
src2 = IterSource(name="s2", source_pad_names=["L1"], iters={"L1": [2]})
snk = NullSink(name="snk", sink_pad_names=["data"])

p = Pipeline()
# Both sources connect to the single sink pad
from sgn.groups import group
p.connect(group(src1, src2), snk)
```

### 1-to-N (Fan-out)

```{.python notest}
from sgn import Pipeline, IterSource, NullSink

src = IterSource(name="src", source_pad_names=["data"], iters={"data": [1]})
snk1 = NullSink(name="s1", sink_pad_names=["H1"])
snk2 = NullSink(name="s2", sink_pad_names=["L1"])

p = Pipeline()
from sgn.groups import group
p.connect(src, group(snk1, snk2))
```

## Chaining

All `connect()`, `insert()`, and `link()` calls return `self`, so you can
chain them:

```{.python notest}
p = Pipeline()
p.connect(src, trn).connect(trn, snk)
```
