group-planner 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2025, Piotr Berlowski
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -1,3 +1,336 @@
1
- # Temporary Holding Version
1
+ # Group Planner
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A TypeScript library for competitor partitioning algorithms, designed to be integrated into Next.js applications. Provides multiple algorithmic approaches to partition competitors into balanced subsets based on equipment class, age category, and gender preferences.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Algorithm Approaches**: Mixed Integer Programming (Greedy & HiGHS), K-means Clustering
8
+ - **Flexible Constraints**: Configurable subset sizes (3-6 competitors, prefer 4). A target is never size 1 or 2.
9
+ - **Guardian Constraint Enforcement**: Competitors must be in the same subset as their guardians
10
+ - **Multiple Optimization Criteria**:
11
+ - Even gender distribution within subsets
12
+ - Age category homogeneity
13
+ - Equipment class grouping or distribution
14
+ - Guardian relationship handling
15
+ - **TypeScript Support**: Full type safety and IntelliSense
16
+ - **Performance Optimized**: Efficient algorithms suitable for up to 168 competitors
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install group-planner
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ### Usage
27
+
28
+ ```typescript
29
+ import { solve, type Competitor } from 'group-planner';
30
+
31
+ const competitors: Competitor[] = [
32
+ { id: '001', equipmentClass: 'HB', ageCategory: 'J', gender: 'M' },
33
+ { id: '002', equipmentClass: 'HB', ageCategory: 'J', gender: 'F' },
34
+ { id: '003', equipmentClass: 'LB', ageCategory: 'A', gender: 'M' }, // Guardian
35
+ { id: '004', equipmentClass: 'LB', ageCategory: 'A', gender: 'F' },
36
+ { id: '005', equipmentClass: 'BBR', ageCategory: 'C', gender: 'M', guardianId: '003' }, // Must be with guardian 003
37
+ // ... more competitors
38
+ ];
39
+
40
+ // Auto-select best algorithm (default)
41
+ const result = await solve(competitors, {
42
+ groupByEquipmentClass: true,
43
+ preferredSubsetSize: 4,
44
+ });
45
+
46
+ // Or specify a particular algorithm
47
+ const mipResult = await solve(competitors, { algorithm: 'mip' });
48
+ const higgsResult = await solve(competitors, { algorithm: 'mip-lp' }); // HiGHS MIP solver
49
+ const clusteringResult = await solve(competitors, { algorithm: 'clustering' });
50
+
51
+ console.log(`Algorithm used: ${result.algorithmUsed}`);
52
+ console.log(`Score: ${result.result.score}`);
53
+ console.log(`Subsets:`, result.result.subsets);
54
+ ```
55
+
56
+ ### Algorithm Comparison
57
+
58
+ If you want to compare all algorithms and see detailed results:
59
+
60
+ ```typescript
61
+ import { compareAlgorithms } from 'group-planner';
62
+
63
+ const { bestResult, allResults } = await compareAlgorithms(competitors, {
64
+ groupByEquipmentClass: true,
65
+ preferredSubsetSize: 4,
66
+ });
67
+
68
+ console.log(`Best algorithm: ${bestResult.algorithmUsed}`);
69
+ allResults.forEach(result => {
70
+ console.log(`${result.algorithmUsed}: Score ${result.result.score} (${result.executionTime}ms)`);
71
+ });
72
+ ```
73
+
74
+
75
+ ## Algorithm Approaches
76
+
77
+ ### 1. Mixed Integer Programming (MIP)
78
+ Formulates the problem as an optimization problem with binary variables and constraints. Treats guardian families as atomic units that must be assigned together.
79
+
80
+ ```typescript
81
+ import { solveMIP } from 'group-planner';
82
+
83
+ const result = solveMIP(competitors, options);
84
+ ```
85
+
86
+ ### 2. K-means Clustering
87
+ Uses feature encoding and weighted distance metrics to cluster guardian families based on similarity, then adjusts clusters to meet size constraints while keeping families together.
88
+
89
+ ```typescript
90
+ import { solveClustering } from 'group-planner';
91
+
92
+ const result = solveClustering(competitors, options);
93
+ ```
94
+
95
+ ### 3. Branch-and-bound
96
+ Systematically searches the solution space by assigning guardian families (not individual competitors) to subsets, ensuring guardians and their dependents stay together.
97
+
98
+ ```typescript
99
+ // Branch-and-bound algorithm has been removed due to performance issues
100
+ // Use 'mip', 'mip-lp', or 'clustering' algorithms instead
101
+ ```
102
+
103
+ ## Configuration Options
104
+
105
+ ```typescript
106
+ interface PartitionOptions {
107
+ /** Prefer grouping competitors of same equipment class together vs distributing evenly */
108
+ groupByEquipmentClass: boolean;
109
+ /** Maximum number of subsets allowed (default: 28) */
110
+ maxSubsets?: number;
111
+ /** Minimum subset size. Below 3 is raised to 3 (default: 3) */
112
+ minSubsetSize?: number;
113
+ /** Maximum subset size (default: 6) */
114
+ maxSubsetSize?: number;
115
+ /** Preferred subset size (default: 4) */
116
+ preferredSubsetSize?: number;
117
+ /** Weight for same gender preference (default: 1.0) */
118
+ genderWeight?: number;
119
+ /** Weight for same age category preference (default: 1.0) */
120
+ ageCategoryWeight?: number;
121
+ /** Weight for equipment class grouping preference (default: 1.0) */
122
+ equipmentClassWeight?: number;
123
+ /** Extra weight for subsets that are exactly preferredSubsetSize (default: 0) */
124
+ closedGroupWeight?: number;
125
+ /** Host labels for bowstyle, age, and gender. Defaults to the built-in IFAA lists. */
126
+ solutionSpace?: SolutionSpace;
127
+ }
128
+ ```
129
+
130
+ ## Competitor Interface
131
+
132
+ ```typescript
133
+ interface Competitor {
134
+ id: string;
135
+ equipmentClass: string; // IFAA code, or any label listed in solutionSpace
136
+ ageCategory: string; // IFAA age code, or any label listed in solutionSpace
137
+ gender: string; // F, M, or any label listed in solutionSpace
138
+ guardianId?: string; // Reference to another competitor who is the guardian
139
+ }
140
+ ```
141
+
142
+ ### Equipment Classes
143
+ - **HB**: Heavy Bow
144
+ - **LB**: Light Bow
145
+ - **TR**: Traditional Recurve
146
+ - **BHR**: Barebow Heavy Recurve
147
+ - **BBR**: Barebow Basic Recurve
148
+ - **FSR**: Freestyle Recurve
149
+ - **BBC**: Barebow Compound
150
+ - **BL**: Barebow Longbow
151
+ - **BU**: Barebow Unlimited
152
+ - **FSC**: Freestyle Compound
153
+ - **FU**: Freestyle Unlimited
154
+
155
+ ### Age Groups
156
+ - **C**: Children
157
+ - **J**: Juniors
158
+ - **YA**: Young Adults
159
+ - **A**: Adults
160
+ - **V**: Veterans
161
+ - **S**: Seniors
162
+
163
+ ### Gender
164
+ - **F**: Female
165
+ - **M**: Male
166
+
167
+ ## Algorithm Selection
168
+
169
+ The library supports four algorithm options:
170
+
171
+ ### Algorithm Options
172
+
173
+ ```typescript
174
+ type Algorithm = 'mip' | 'clustering' | 'branch-and-bound' | 'auto';
175
+ ```
176
+
177
+ - **`'auto'` (default)**: Runs all three algorithms and returns the result with the highest score
178
+ - **`'mip'`**: Mixed Integer Programming approach using greedy heuristic
179
+ - **`'clustering'`**: K-means clustering with constraint adjustment
180
+ - **`'branch-and-bound'`**: Systematic search with pruning
181
+
182
+ ### When to Use Each Algorithm
183
+
184
+ - **Auto**: Best for production use when you want optimal results
185
+ - **MIP**: Good balance of speed and quality, handles large datasets well
186
+ - **Clustering**: Fast execution, good for real-time applications
187
+ - **Branch-and-bound**: Most thorough search, best for smaller datasets (≤48 competitors)
188
+
189
+ ### Algorithm Performance Characteristics
190
+
191
+ | Algorithm | Speed | Quality | Max Competitors | Memory Usage |
192
+ |-----------|-------|---------|-----------------|--------------|
193
+ | MIP | Fast | High | 168 | Low |
194
+ | Clustering | Fastest | Good | 168 | Low |
195
+ | Branch-and-bound | Slow | Highest | ~48 | Medium |
196
+ | Auto | Slow | Highest | 168 | Medium |
197
+
198
+ ## Result Structure
199
+
200
+ ```typescript
201
+ interface PartitionResult {
202
+ subsets: Competitor[][];
203
+ score: number;
204
+ metadata: {
205
+ totalCompetitors: number;
206
+ totalSubsets: number;
207
+ averageSubsetSize: number;
208
+ scoreBreakdown: {
209
+ sizeScore: number;
210
+ closedGroupScore: number;
211
+ genderScore: number;
212
+ ageCategoryScore: number;
213
+ equipmentClassScore: number;
214
+ };
215
+ };
216
+ }
217
+ ```
218
+
219
+ ## Algorithm Selection
220
+
221
+ The library supports different algorithms via the `algorithm` option:
222
+
223
+ ```typescript
224
+ type Algorithm = 'mip' | 'mip-lp' | 'clustering' | 'auto';
225
+
226
+ // Available algorithms:
227
+ const mipResult = await solve(competitors, { algorithm: 'mip' }); // Greedy MIP solver
228
+ const higgsResult = await solve(competitors, { algorithm: 'mip-lp' }); // HiGHS MIP solver (WebAssembly)
229
+ const clusteringResult = await solve(competitors, { algorithm: 'clustering' }); // K-means clustering
230
+ const autoResult = await solve(competitors, { algorithm: 'auto' }); // Auto-select best (default)
231
+ ```
232
+
233
+ ### Performance Guide
234
+
235
+ - **MIP (Greedy)**: Fast, good for most cases, handles all constraint types
236
+ - **MIP-LP (HiGHS)**: Most optimal results, slower, excellent constraint satisfaction
237
+ - **Clustering**: Fast, good for large datasets, may need constraint post-processing
238
+ - **Auto**: Runs all algorithms and returns the best result
239
+
240
+ ### Special Constraints
241
+
242
+ - **≤112 competitors**: When `maxSubsetSize` is omitted, maximum subset size is limited to 4. An explicit `maxSubsetSize` is kept.
243
+ - **Closed groups**: Raise `closedGroupWeight` to prefer subsets of exactly `preferredSubsetSize`. Gender, age, and equipment weights still trade off inside that size.
244
+ - **No short targets**: Subset size is at least 3. A leftover archer is not placed on a target of 1 or 2.
245
+ - **Guardian relationships**: Automatically preserved across all algorithms
246
+ - **Maximum 28 subsets**: Hard limit enforced by all algorithms
247
+
248
+ ## Guardian Constraints
249
+
250
+ The library automatically handles guardian relationships:
251
+
252
+ ```typescript
253
+ import {
254
+ createGuardianFamilies,
255
+ validateGuardianConstraints,
256
+ validateCompetitors,
257
+ EQUIPMENT_CLASSES,
258
+ AGE_GROUPS
259
+ } from 'group-planner';
260
+
261
+ // Validate competitor data before processing
262
+ const validation = validateCompetitors(competitors);
263
+ if (!validation.valid) {
264
+ console.log('Validation errors:', validation.errors);
265
+ return;
266
+ }
267
+
268
+ // View how competitors are grouped into families
269
+ const families = createGuardianFamilies(competitors);
270
+ console.log('Guardian families:', families);
271
+
272
+ // Validate that a solution respects guardian constraints
273
+ const guardianValidation = validateGuardianConstraints(competitors, subsets);
274
+ if (!guardianValidation.valid) {
275
+ console.log('Guardian constraint violations:', guardianValidation.errors);
276
+ }
277
+
278
+ // Access available categories
279
+ console.log('Equipment classes:', EQUIPMENT_CLASSES);
280
+ console.log('Age groups:', AGE_GROUPS);
281
+ ```
282
+
283
+ ## Examples
284
+
285
+ See `src/example.ts` for complete usage examples including:
286
+ - Basic partitioning with all three algorithms
287
+ - Guardian relationship handling and validation
288
+ - Comparing equipment class grouping vs distribution strategies
289
+ - Custom scoring weights
290
+
291
+ ## Development
292
+
293
+ ### Setup
294
+
295
+ ```bash
296
+ npm install
297
+ ```
298
+
299
+ ### Build
300
+
301
+ ```bash
302
+ npm run build
303
+ ```
304
+
305
+ ### Development Mode
306
+
307
+ ```bash
308
+ npm run dev
309
+ ```
310
+
311
+ ### Type Checking
312
+
313
+ ```bash
314
+ npm run type-check
315
+ ```
316
+
317
+ ## Algorithm Performance
318
+
319
+ - **MIP Solver**: Fast greedy heuristic, good for large datasets
320
+ - **K-means Clustering**: Balanced approach, handles feature similarity well
321
+ - **Branch-and-bound**: Most thorough search, best for smaller datasets (<50 competitors)
322
+
323
+ ## Release
324
+
325
+ The package name `group-planner` is unscoped. `prepublishOnly` cleans and builds `dist` before publish:
326
+
327
+ ```bash
328
+ npm test
329
+ npm publish
330
+ ```
331
+
332
+ Installing from git runs `prepare`, which builds `dist` as well.
333
+
334
+ ## License
335
+
336
+ MIT
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Core types for competitor partitioning algorithms
3
+ */
4
+ /** Built-in IFAA catalogue. Callers can supply any other labels through SolutionSpace. */
5
+ type EquipmentClass = 'HB' | 'LB' | 'TR' | 'BHR' | 'BBR' | 'FSR' | 'BBC' | 'BL' | 'BU' | 'FSC' | 'FU';
6
+ type AgeGroup = 'C' | 'J' | 'YA' | 'A' | 'V' | 'S';
7
+ type Gender = 'F' | 'M';
8
+ type Algorithm = 'mip' | 'mip-lp' | 'clustering' | 'auto';
9
+ /**
10
+ * Labels the solver is allowed to see. When omitted, the built-in IFAA lists are used.
11
+ * Pass the host application's own age, gender, and bowstyle ids here.
12
+ */
13
+ interface SolutionSpace {
14
+ equipmentClasses: readonly string[];
15
+ ageCategories: readonly string[];
16
+ genders: readonly string[];
17
+ }
18
+ interface Competitor {
19
+ id: string;
20
+ equipmentClass: string;
21
+ ageCategory: string;
22
+ gender: string;
23
+ guardianId?: string;
24
+ }
25
+ interface PartitionOptions {
26
+ /** Algorithm to use for partitioning (default: 'auto') */
27
+ algorithm?: Algorithm;
28
+ /** Prefer grouping competitors of same equipment class together vs distributing evenly */
29
+ groupByEquipmentClass: boolean;
30
+ /** Maximum number of subsets allowed (default: 28) */
31
+ maxSubsets?: number;
32
+ /** Minimum subset size. Values below 3 are raised to 3. Size 1 and 2 are never a target. */
33
+ minSubsetSize?: number;
34
+ /** Maximum subset size (default: 6) */
35
+ maxSubsetSize?: number;
36
+ /** Preferred subset size (default: 4) */
37
+ preferredSubsetSize?: number;
38
+ /** Weight for same gender preference (default: 1.0) */
39
+ genderWeight?: number;
40
+ /** Weight for same age category preference (default: 1.0) */
41
+ ageCategoryWeight?: number;
42
+ /** Weight for equipment class grouping preference (default: 1.0) */
43
+ equipmentClassWeight?: number;
44
+ /**
45
+ * Extra weight for subsets whose size equals preferredSubsetSize.
46
+ * Zero keeps the historical size score. Raise it when full groups should outrank mix.
47
+ */
48
+ closedGroupWeight?: number;
49
+ /** When set, competitor labels are checked against these lists instead of the IFAA defaults. */
50
+ solutionSpace?: SolutionSpace;
51
+ }
52
+ interface PartitionResult {
53
+ subsets: Competitor[][];
54
+ score: number;
55
+ metadata: {
56
+ totalCompetitors: number;
57
+ totalSubsets: number;
58
+ averageSubsetSize: number;
59
+ scoreBreakdown: {
60
+ sizeScore: number;
61
+ closedGroupScore: number;
62
+ genderScore: number;
63
+ ageCategoryScore: number;
64
+ equipmentClassScore: number;
65
+ };
66
+ };
67
+ }
68
+ interface AlgorithmResult {
69
+ result: PartitionResult;
70
+ executionTime: number;
71
+ algorithmUsed: string;
72
+ }
73
+
74
+ /**
75
+ * Utility functions for competitor partitioning
76
+ */
77
+
78
+ type ResolvedPartitionOptions = Omit<Required<PartitionOptions>, 'solutionSpace'> & {
79
+ solutionSpace?: SolutionSpace;
80
+ };
81
+ /**
82
+ * Default partition options
83
+ */
84
+ declare const DEFAULT_OPTIONS: ResolvedPartitionOptions;
85
+ /**
86
+ * Validates that a partition solution meets all constraints
87
+ */
88
+ declare function validatePartition(competitors: Competitor[], subsets: Competitor[][], options?: Partial<PartitionOptions>): {
89
+ valid: boolean;
90
+ errors: string[];
91
+ };
92
+ /**
93
+ * Calculates the quality score for a partition solution
94
+ */
95
+ declare function calculateScore(subsets: Competitor[][], options?: Partial<PartitionOptions>): {
96
+ score: number;
97
+ breakdown: PartitionResult['metadata']['scoreBreakdown'];
98
+ };
99
+ /**
100
+ * Creates a partition result with metadata
101
+ */
102
+ declare function createPartitionResult(subsets: Competitor[][], options?: Partial<PartitionOptions>): PartitionResult;
103
+ /**
104
+ * Helper to get competitors by guardian relationship
105
+ */
106
+ declare function getGuardianGroups(competitors: Competitor[]): Map<string, Competitor[]>;
107
+ /**
108
+ * Groups competitors into guardian families (guardian + their dependents)
109
+ * Returns an array where each element is either a single competitor or a guardian family
110
+ */
111
+ declare function createGuardianFamilies(competitors: Competitor[]): Competitor[][];
112
+ /**
113
+ * Validates that guardian constraints are satisfied in the partition
114
+ */
115
+ declare function validateGuardianConstraints(competitors: Competitor[], subsets: Competitor[][]): {
116
+ valid: boolean;
117
+ errors: string[];
118
+ };
119
+ declare function isValidCompetitor(competitor: unknown, space?: SolutionSpace): competitor is Competitor;
120
+ /**
121
+ * Validates an array of competitors
122
+ */
123
+ declare function validateCompetitors(competitors: any[], space?: SolutionSpace): {
124
+ valid: boolean;
125
+ errors: string[];
126
+ };
127
+
128
+ /** A target smaller than this is not a group. Size 1 and size 2 are never emitted. */
129
+ declare const MINIMUM_SUBSET_SIZE = 3;
130
+ declare function smallestAllowedSubset(requestedMin: number): number;
131
+ /**
132
+ * Drops or repairs targets of size 1 or 2.
133
+ * A short group is filled from donors, merged into another group, or removed.
134
+ * Removed archers are not given a target.
135
+ */
136
+ declare function retainLegalSubsets(subsets: Competitor[][], min: number, max: number): Competitor[][];
137
+
138
+ /**
139
+ * Constants for competitor categories and validation
140
+ */
141
+
142
+ /**
143
+ * Valid equipment classes
144
+ */
145
+ declare const EQUIPMENT_CLASSES: readonly EquipmentClass[];
146
+ /**
147
+ * Valid age groups (ordered from youngest to oldest)
148
+ */
149
+ declare const AGE_GROUPS: readonly AgeGroup[];
150
+ /**
151
+ * Valid genders
152
+ */
153
+ declare const GENDERS: readonly Gender[];
154
+ /**
155
+ * Equipment class descriptions for documentation
156
+ */
157
+ declare const EQUIPMENT_CLASS_DESCRIPTIONS: Record<EquipmentClass, string>;
158
+ /**
159
+ * Age group descriptions for documentation
160
+ */
161
+ declare const AGE_GROUP_DESCRIPTIONS: Record<AgeGroup, string>;
162
+ /**
163
+ * Gender descriptions for documentation
164
+ */
165
+ declare const GENDER_DESCRIPTIONS: Record<Gender, string>;
166
+ /**
167
+ * Checks if a value is a valid equipment class
168
+ */
169
+ declare function isValidEquipmentClass(value: string, allowed?: readonly string[]): boolean;
170
+ /**
171
+ * Checks if a value is a valid age group
172
+ */
173
+ declare function isValidAgeGroup(value: string, allowed?: readonly string[]): boolean;
174
+ /**
175
+ * Checks if a value is a valid gender
176
+ */
177
+ declare function isValidGender(value: string, allowed?: readonly string[]): boolean;
178
+ /**
179
+ * Gets the age group order for comparison (lower number = younger)
180
+ */
181
+ declare function getAgeGroupOrder(ageGroup: AgeGroup): number;
182
+ /**
183
+ * Compares two age groups (-1 if a is younger, 0 if same, 1 if a is older)
184
+ */
185
+ declare function compareAgeGroups(a: AgeGroup, b: AgeGroup): number;
186
+
187
+ /**
188
+ * Mixed Integer Programming approach for competitor partitioning
189
+ *
190
+ * This algorithm formulates the partitioning problem as a MIP problem where:
191
+ * - Binary variables x[i][j] indicate if competitor i is in subset j
192
+ * - Objective function maximizes the quality score based on preferences
193
+ * - Constraints ensure valid partitioning
194
+ */
195
+
196
+ /**
197
+ * Solves the competitor partitioning problem using Mixed Integer Programming
198
+ */
199
+ declare function solveMIP(competitors: Competitor[], options?: Partial<PartitionOptions>): AlgorithmResult;
200
+
201
+ /**
202
+ * Mixed Integer Programming approach using HiGHS solver
203
+ *
204
+ * This algorithm formulates the partitioning problem as a proper MIP problem where:
205
+ * - Binary variables x[i][j] indicate if competitor i is in subset j
206
+ * - Objective function maximizes the quality score based on preferences
207
+ * - Constraints ensure valid partitioning and guardian relationships
208
+ */
209
+
210
+ /**
211
+ * Solves the competitor partitioning problem using HiGHS MIP solver
212
+ */
213
+ declare function solveMIPWithLP(competitors: Competitor[], options?: Partial<PartitionOptions>): Promise<AlgorithmResult>;
214
+
215
+ /**
216
+ * Clustering approach for competitor partitioning
217
+ *
218
+ * This algorithm uses a modified K-means clustering approach where:
219
+ * - Competitors are represented as feature vectors
220
+ * - Distance metric considers gender, age category, and equipment class
221
+ * - Clusters are formed and then adjusted to meet size constraints
222
+ * - Post-processing ensures all constraints are satisfied
223
+ */
224
+
225
+ /**
226
+ * Solves the competitor partitioning problem using clustering with guardian constraints
227
+ */
228
+ declare function solveClustering(competitors: Competitor[], options?: Partial<PartitionOptions>): AlgorithmResult;
229
+
230
+ /**
231
+ * Group Planner Library
232
+ *
233
+ * A TypeScript library for competitor partitioning algorithms.
234
+ * Provides three different approaches: Mixed Integer Programming,
235
+ * K-means Clustering, and Branch-and-bound.
236
+ */
237
+
238
+ /**
239
+ * Main solver function - single API entry point for all algorithms
240
+ *
241
+ * @param competitors - Array of competitor objects to partition
242
+ * @param options - Configuration options including algorithm selection
243
+ * @returns Algorithm result with partitioned subsets
244
+ *
245
+ * @example
246
+ * ```typescript
247
+ * // Use specific algorithm
248
+ * const result = solve(competitors, { algorithm: 'mip' });
249
+ *
250
+ * // Use auto-selection (runs all algorithms, returns best)
251
+ * const result = solve(competitors, { algorithm: 'auto' });
252
+ *
253
+ * // Use default algorithm (auto)
254
+ * const result = solve(competitors);
255
+ * ```
256
+ */
257
+ declare function solve(competitors: Competitor[], options?: Partial<PartitionOptions>): Promise<AlgorithmResult>;
258
+ /**
259
+ * Runs all algorithms and returns detailed results for comparison
260
+ *
261
+ * @param competitors - Array of competitor objects to partition
262
+ * @param options - Configuration options (algorithm option is ignored)
263
+ * @returns Object with best result and all algorithm results
264
+ *
265
+ * @example
266
+ * ```typescript
267
+ * const { bestResult, allResults } = compareAlgorithms(competitors);
268
+ * console.log('Best:', bestResult.algorithmUsed);
269
+ * allResults.forEach(r => console.log(`${r.algorithmUsed}: ${r.result.score}`));
270
+ * ```
271
+ */
272
+ declare function compareAlgorithms(competitors: Competitor[], options?: Partial<PartitionOptions>): Promise<{
273
+ bestResult: AlgorithmResult;
274
+ allResults: AlgorithmResult[];
275
+ }>;
276
+ declare const version = "0.1.0";
277
+
278
+ export { AGE_GROUPS, AGE_GROUP_DESCRIPTIONS, type AgeGroup, type Algorithm, type AlgorithmResult, type Competitor, DEFAULT_OPTIONS, EQUIPMENT_CLASSES, EQUIPMENT_CLASS_DESCRIPTIONS, type EquipmentClass, GENDERS, GENDER_DESCRIPTIONS, type Gender, MINIMUM_SUBSET_SIZE, type PartitionOptions, type PartitionResult, type SolutionSpace, calculateScore, compareAgeGroups, compareAlgorithms, createGuardianFamilies, createPartitionResult, getAgeGroupOrder, getGuardianGroups, isValidAgeGroup, isValidCompetitor, isValidEquipmentClass, isValidGender, retainLegalSubsets, smallestAllowedSubset, solve, solveClustering, solveMIP, solveMIPWithLP, validateCompetitors, validateGuardianConstraints, validatePartition, version };