1function cells = tbi_partition(sn, options)
2% CELLS = TBI_PARTITION(SN, OPTIONS)
4% Partition
the station set into cells
for trajectory-based iteration.
5% Honors options.config.tbi_cells, a cell array of disjoint station index
6% vectors covering 1:nstations. Otherwise stations are agglomerated
7% greedily on
the symmetrized station-level routing weights, targeting
8% options.config.tbi_cellsize stations per cell (
default 5), so that
9% strongly coupled stations share a cell and connecting flows stay weak.
11% Copyright (c) 2012-2026, Imperial College London
17if isfield(options.config,
'tbi_cells') && ~isempty(options.config.tbi_cells)
18 cells = options.config.tbi_cells;
19 covered = sort(cell2mat(cellfun(@(x) x(:)', cells(:)', 'UniformOutput', false)));
20 if numel(covered) ~= M || any(covered(:)' ~= 1:M)
21 line_error(mfilename,sprintf('options.config.tbi_cells must be a partition of
the station set 1:%d.', M));
26if isfield(options.config,'tbi_cellsize') && ~isempty(options.config.tbi_cellsize)
27 cellsize = options.config.tbi_cellsize;
32% station-level coupling weights, aggregated over classes and symmetrized
37 W(i,j) = sum(sum(rt((i-1)*K+(1:K), (j-1)*K+(1:K))));
43ncells_target = max(1, ceil(M/cellsize));
45C = A; % inter-cell coupling weights
46while numel(cells) > ncells_target
48 szs = cellfun(@numel, cells);
49 % most coupled cell pair, respecting
the cell size cap
50 maxc = -1; besta = 0; bestb = 0;
53 if szs(a)+szs(b) <= 2*cellsize && C(a,b) > maxc
60 if besta == 0 % every merge exceeds
the size cap: merge
the two smallest
62 besta = min(ord(1),ord(2));
63 bestb = max(ord(1),ord(2));
65 cells{besta} = [cells{besta}, cells{bestb}];
66 C(besta,:) = C(besta,:) + C(bestb,:);
67 C(:,besta) = C(:,besta) + C(:,bestb);