cuGenOpt/skills/cugenopt-problem-gen/reference/encoding-guide.md

156 lines
5.6 KiB
Markdown
Raw Normal View History

# Encoding Selection & Dimension Guide
## Encoding Types
cuGenOpt supports three encoding types. Choose based on the nature of the decision variables.
### Permutation
**Use when**: each element appears exactly once (ordering/assignment).
| Scenario | RowMode | D1 | D2 | dim2_default | total_elements |
|----------|---------|----|----|-------------|----------------|
| TSP (n cities) | Single | 1 | next_pow2(n) | n | — |
| QAP (n facilities) | Single | 1 | next_pow2(n) | n | — |
| Assignment (n tasks) | Single | 1 | next_pow2(n) | n | — |
| JSP (m machines, j jobs) | Fixed | next_pow2(m) | next_pow2(j) | j | — |
| VRP (k vehicles, n customers) | Partition | next_pow2(k) | max(next_pow2(n/k*2), 64) | 0 | n |
| VRPTW (k vehicles, n customers) | Partition | next_pow2(k) | max(next_pow2(n/k*2), 64) | 0 | n |
**Partition specifics**:
- `dim2_default = 0` tells the framework to distribute elements across rows
- `total_elements = n` is the count of elements to distribute
- `cross_row_prob` controls how often cross-row operators fire (typically 0.20.4)
- Elements are customer/job indices `0..n-1`; depot/source is implicit (not in the solution)
### Binary
**Use when**: each position is a yes/no decision.
| Scenario | RowMode | D1 | D2 | dim2_default |
|----------|---------|----|----|-------------|
| 0-1 Knapsack (n items) | Single | 1 | next_pow2(n) | n |
| Scheduling (n shifts) | Single | 1 | next_pow2(n) | n |
| Subset selection (n candidates) | Single | 1 | next_pow2(n) | n |
| Multi-row scheduling (m workers, n shifts) | Fixed | next_pow2(m) | next_pow2(n) | n |
**Solution values**: `sol.data[row][col]` is 0 or 1.
### Integer
**Use when**: each position takes a bounded integer value.
| Scenario | RowMode | D1 | D2 | dim2_default | lower_bound | upper_bound |
|----------|---------|----|----|-------------|-------------|-------------|
| Graph coloring (n nodes, c colors) | Single | 1 | next_pow2(n) | n | 0 | c-1 |
| Load balancing (n tasks, m machines) | Single | 1 | next_pow2(n) | n | 0 | m-1 |
| Multi-machine scheduling | Fixed | next_pow2(m) | next_pow2(j) | j | 0 | max_time |
**Solution values**: `sol.data[row][col]` is in `[value_lower_bound, value_upper_bound]`.
Set bounds in config:
```cuda
cfg.value_lower_bound = 0;
cfg.value_upper_bound = num_colors - 1;
```
## Dimension Calculation Rules
### D1 and D2 (Template Parameters)
These are **compile-time constants** and define the maximum capacity:
- Must be sufficient for the largest instance you plan to solve
- Power of 2 is recommended for memory alignment
- Larger values waste registers/memory; keep as small as possible
```
next_pow2(x):
1→1, 2→2, 3→4, 5→8, 9→16, 17→32, 33→64, 65→128, ...
```
### dim1 and dim2_default (Runtime Parameters)
Set in `config()` to the actual problem size:
- `dim1 ≤ D1`: actual number of rows used
- `dim2_default ≤ D2`: actual number of columns per row
- For Partition mode: `dim2_default = 0` (framework handles distribution)
### Choosing D2 for Partition Mode
Since rows have variable length, D2 must accommodate the longest possible row:
```
D2 = max(next_pow2(total_elements / D1 * 2), 64)
```
The `*2` factor provides headroom for unbalanced distributions.
## Shared Memory Sizing
### When to Use Shared Memory
Shared memory provides ~10x faster access than global memory. Use it when:
- Problem has a data matrix (distance, cost, weight)
- The matrix is accessed repeatedly during objective/penalty evaluation
### How to Size
Report the **actual** data size. The framework handles the rest:
```cuda
size_t shared_mem_bytes() const {
// Distance matrix + demand array
return (size_t)stride * stride * sizeof(float) + (size_t)n * sizeof(float);
}
```
The framework automatically:
1. If ≤ 48KB: uses default shared memory
2. If 48KBmax_smem: calls `cudaFuncSetAttribute` to extend (GPU-dependent max: T4=64KB, V100=96KB, A100/A800=164KB, H100=228KB)
3. If > max_smem: falls back to global memory, uses `working_set_bytes()` for L2 cache population sizing
### working_set_bytes
Always return the actual data size, regardless of whether it fits in shared memory:
```cuda
size_t working_set_bytes() const {
return (size_t)n * n * sizeof(float);
}
```
This is used by the framework to auto-calculate population size based on L2 cache capacity.
## RowMode Details
### Single (default)
- `dim1 = 1`, single row of elements
- No cross-row operators
- Simplest and most common
### Fixed
- `dim1 > 1`, all rows have the same length (`dim2_default`)
- Cross-row operators: ROW_SWAP, ROW_REVERSE
- No SPLIT/MERGE (rows cannot change length)
- Use for: JSP (machines × jobs), multi-worker scheduling
### Partition
- `dim1 > 1`, rows have variable length
- Elements are distributed across rows (total count = `total_elements`)
- Cross-row operators: CROSS_RELOCATE, CROSS_SWAP, SEG_RELOCATE, SEG_SWAP, CROSS_EXCHANGE, SPLIT, MERGE
- `cross_row_prob` controls the probability of selecting cross-row operators
- Use for: VRP (vehicles × customers), any partitioning problem
## Quick Reference: Problem → Config
| Problem | Encoding | RowMode | D1 | D2 | cross_row_prob |
|---------|----------|---------|----|----|---------------|
| TSP-50 | Perm | Single | 1 | 64 | 0 |
| TSP-500 | Perm | Single | 1 | 512 | 0 |
| QAP-15 | Perm | Single | 1 | 16 | 0 |
| Assignment-12 | Perm | Single | 1 | 16 | 0 |
| VRP-30-4v | Perm | Partition | 4 | 32 | 0.3 |
| VRPTW-100-25v | Perm | Partition | 32 | 32 | 0.3 |
| Knapsack-100 | Binary | Single | 1 | 128 | 0 |
| Scheduling-20 | Binary | Single | 1 | 32 | 0 |
| Graph Color-50 | Integer | Single | 1 | 64 | 0 |
| JSP-6m-6j | Perm | Fixed | 8 | 8 | 0.2 |