Apply a set of integer **pipelines** to a set of **images** and produce one named output for every (image, pipeline) pair.
This is an interview-friendly version of an image-processing problem: instead of real image objects, each image path maps to a single **integer value** in `image_store`. Each pipeline is a list of operations applied **in order**, left to right.
## What to implement
```python
def solution(image_paths, image_store, pipelines, output_dir):
...
```
For **every** image index `i` (over `image_paths`) and **every** pipeline index `j` (over `pipelines`), run pipeline `j` on image `i`'s value and emit one result.
## Input
- **`image_paths`** — list of image-path strings. The value of image `i` is `image_store[image_paths[i]]`.
- **`image_store`** — dict mapping each image path to its integer value. Every path in `image_paths` is present as a key.
- **`pipelines`** — list of pipelines. Each pipeline is a list of operation tuples (a pipeline may be empty).
- **`output_dir`** — string used as the directory prefix for output file names.
## Operations
Each operation transforms the current integer value `v`:
- **`('ADD', x)`** → `v + x`
- **`('SUB', x)`** → `v - x`
- **`('MUL', x)`** → `v * x`
- **`('NEG',)`** → `-v`
Operations within a pipeline are applied sequentially in the order they appear. An **empty pipeline** performs no operations and leaves the value unchanged (identity).
## Output
Return a **list of `(output_path, result_value)` tuples**.
For image index `i` and pipeline index `j`:
- **`result_value`** is image `i`'s value after running pipeline `j`'s operations in order.
- **`output_path`** is built from `output_dir` plus the file name `img{i}_pipe{j}.png`:
- Strip **any** trailing `/` characters from `output_dir`, then join with `/`.
Example: `output_dir = 'tmp/'` (or `'tmp'`) → `tmp/img0_pipe0.png`.
- If `output_dir` is the empty string `''` (or becomes empty after stripping trailing slashes), there is **no** leading separator → `img0_pipe0.png`.
**Ordering:** results are ordered **first by image index `i`, then by pipeline index `j`** (image `0` with every pipeline, then image `1` with every pipeline, and so on).
The returned list therefore has exactly `len(image_paths) * len(pipelines)` entries.
## Notes & edge cases
- If the same image path appears multiple times in `image_paths`, an output is still produced for **each position** (each index `i` is independent).
- An empty `image_paths` or empty `pipelines` yields an empty result list.
- Your approach should **avoid unnecessary repeated work** — e.g. don't reload the same image path more than once, and don't re-run a pipeline's operation list from scratch for every image.
## Constraints
- `0 <= len(image_paths)`, `0 <= len(pipelines)`
- A pipeline may be empty.
- All paths in `image_paths` exist in `image_store`.
- The total number of operations across all pipelines is at most `2 * 10^5`.
- The returned list has exactly `len(image_paths) * len(pipelines)` entries, so any solution must spend at least `O(m * n)` time to build the output (where `m = len(image_paths)`, `n = len(pipelines)`).
## Example
```
image_paths = ['a.png', 'b.png']
image_store = {'a.png': 2, 'b.png': 5}
pipelines = [[('ADD', 3), ('MUL', 2)], [('NEG',), ('SUB', 4)]]
output_dir = 'out'
# pipeline 0 on 2: (2+3)*2 = 10 ; pipeline 1 on 2: -(2)-4 = -6
# pipeline 0 on 5: (5+3)*2 = 16 ; pipeline 1 on 5: -(5)-4 = -9
=> [('out/img0_pipe0.png', 10), ('out/img0_pipe1.png', -6),
('out/img1_pipe0.png', 16), ('out/img1_pipe1.png', -9)]
```
Examples
Input: (['a.png', 'b.png'], {'a.png': 2, 'b.png': 5}, [[('ADD', 3), ('MUL', 2)], [('NEG',), ('SUB', 4)]], 'out')
Expected Output: [('out/img0_pipe0.png', 10), ('out/img0_pipe1.png', -6), ('out/img1_pipe0.png', 16), ('out/img1_pipe1.png', -9)]
Input: (['x', 'x', 'y'], {'x': -3, 'y': 0}, [[], [('MUL', -1), ('ADD', 2)], [('SUB', 5), ('NEG',)]], 'res')
Expected Output: [('res/img0_pipe0.png', -3), ('res/img0_pipe1.png', 5), ('res/img0_pipe2.png', 8), ('res/img1_pipe0.png', -3), ('res/img1_pipe1.png', 5), ('res/img1_pipe2.png', 8), ('res/img2_pipe0.png', 0), ('res/img2_pipe1.png', 2), ('res/img2_pipe2.png', 5)]
Input: ([], {}, [[('ADD', 1)]], 'tmp')
Expected Output: []
Input: (['z'], {'z': 4}, [[('ADD', 1), ('MUL', 3), ('NEG',), ('SUB', 2)]], 'tmp/')
Expected Output: [('tmp/img0_pipe0.png', -17)]
Input: (['p'], {'p': 7}, [], 'out')
Expected Output:
Input: (['k'], {'k': 9}, [[]], '')
Expected Output:
Input: (['m', 'm'], {'m': 5}, [[('NEG',), ('NEG',), ('MUL', 2)], [('SUB', 5), ('ADD', 5)]], 'd/')
Expected Output: