# `Edifice.Graph.GraphSAGE`
[🔗](https://github.com/blasphemetheus/edifice/blob/main/lib/edifice/graph/graph_sage.ex#L1)

GraphSAGE - Inductive Representation Learning on Large Graphs.

GraphSAGE learns node embeddings by sampling and aggregating features from
a node's local neighborhood. Unlike transductive methods (GCN), GraphSAGE
can generate embeddings for previously unseen nodes, making it suitable for
evolving graphs and inductive settings.

## Architecture

```
Node Features [batch, num_nodes, input_dim]
Adjacency     [batch, num_nodes, num_nodes]
      |
      v
+--------------------------------------+
| GraphSAGE Layer 1:                   |
|   1. Aggregate neighbor features     |
|      h_N(v) = AGG({h_u : u in N(v)})|
|   2. Concatenate with self           |
|      h_v' = [h_v || h_N(v)]         |
|   3. Project and normalize           |
|      h_v' = W * h_v' / ||h_v'||     |
+--------------------------------------+
      |
      v
+--------------------------------------+
| GraphSAGE Layer 2                    |
+--------------------------------------+
      |
      v
Node Embeddings [batch, num_nodes, hidden_dim]
```

## Aggregation Strategies

| Aggregator | Description |
|------------|-------------|
| `:mean`    | Mean of neighbor features (default) |
| `:max`     | Element-wise max of neighbor features |
| `:pool`    | Max-pooled through a dense layer |

## Usage

    model = GraphSAGE.build(
      input_dim: 16,
      hidden_dims: [64, 64],
      aggregator: :mean,
      num_classes: 7
    )

## References

- Hamilton et al., "Inductive Representation Learning on Large Graphs" (NeurIPS 2017)
- https://arxiv.org/abs/1706.02216

# `build_opt`

```elixir
@type build_opt() ::
  {:activation, atom()}
  | {:aggregator, :mean | :max | :pool}
  | {:dropout, float()}
  | {:hidden_dims, pos_integer()}
  | {:input_dim, pos_integer()}
  | {:num_classes, pos_integer() | nil}
  | {:pool, atom()}
```

Options for `build/1`.

# `build`

```elixir
@spec build([build_opt()]) :: Axon.t()
```

Build a GraphSAGE model.

## Options

- `:input_dim` - Input feature dimension per node (required)
- `:hidden_dims` - List of hidden dimensions for each layer (default: [64, 64])
- `:aggregator` - Aggregation strategy: :mean, :max, :pool (default: :mean)
- `:num_classes` - If provided, adds a classification head (default: nil)
- `:activation` - Activation function (default: :relu)
- `:dropout` - Dropout rate (default: 0.0)
- `:pool` - Global pooling mode for graph classification: :mean, :sum, :max (default: nil)

## Returns

An Axon model with two inputs ("nodes" and "adjacency").

# `output_size`

```elixir
@spec output_size(keyword()) :: pos_integer()
```

Get the output size of a GraphSAGE model.

# `sage_layer`

```elixir
@spec sage_layer(Axon.t(), Axon.t(), pos_integer(), keyword()) :: Axon.t()
```

Single GraphSAGE layer: aggregate neighbors, concatenate with self, project.

## Options

- `:name` - Layer name prefix (default: "sage")
- `:aggregator` - Aggregation strategy (default: :mean)
- `:activation` - Activation function (default: :relu)
- `:dropout` - Dropout rate (default: 0.0)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
