@higher.archi/boe 1.0.30 → 1.0.31
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/dist/core/evaluation/decay.d.ts +13 -2
- package/dist/core/evaluation/decay.d.ts.map +1 -1
- package/dist/core/evaluation/decay.js +24 -0
- package/dist/core/evaluation/decay.js.map +1 -1
- package/dist/core/types/rule.d.ts +25 -1
- package/dist/core/types/rule.d.ts.map +1 -1
- package/dist/core/types/rule.js +28 -0
- package/dist/core/types/rule.js.map +1 -1
- package/dist/engines/bayesian/index.d.ts +1 -1
- package/dist/engines/bayesian/index.d.ts.map +1 -1
- package/dist/engines/bayesian/index.js +2 -1
- package/dist/engines/bayesian/index.js.map +1 -1
- package/dist/engines/bayesian/types.d.ts +10 -1
- package/dist/engines/bayesian/types.d.ts.map +1 -1
- package/dist/engines/bayesian/types.js +16 -1
- package/dist/engines/bayesian/types.js.map +1 -1
- package/dist/engines/constraint/types.d.ts +36 -5
- package/dist/engines/constraint/types.d.ts.map +1 -1
- package/dist/engines/constraint/types.js +44 -1
- package/dist/engines/constraint/types.js.map +1 -1
- package/dist/engines/decay/index.d.ts +1 -1
- package/dist/engines/decay/index.d.ts.map +1 -1
- package/dist/engines/decay/index.js +5 -1
- package/dist/engines/decay/index.js.map +1 -1
- package/dist/engines/decay/types.d.ts +26 -4
- package/dist/engines/decay/types.d.ts.map +1 -1
- package/dist/engines/decay/types.js +30 -1
- package/dist/engines/decay/types.js.map +1 -1
- package/dist/engines/defeasible/index.d.ts +1 -1
- package/dist/engines/defeasible/index.d.ts.map +1 -1
- package/dist/engines/defeasible/index.js +8 -1
- package/dist/engines/defeasible/index.js.map +1 -1
- package/dist/engines/defeasible/types.d.ts +40 -5
- package/dist/engines/defeasible/types.d.ts.map +1 -1
- package/dist/engines/defeasible/types.js +56 -1
- package/dist/engines/defeasible/types.js.map +1 -1
- package/dist/engines/ensemble/index.d.ts +1 -0
- package/dist/engines/ensemble/index.d.ts.map +1 -1
- package/dist/engines/ensemble/index.js +5 -1
- package/dist/engines/ensemble/index.js.map +1 -1
- package/dist/engines/ensemble/types.d.ts +17 -2
- package/dist/engines/ensemble/types.d.ts.map +1 -1
- package/dist/engines/ensemble/types.js +23 -0
- package/dist/engines/ensemble/types.js.map +1 -1
- package/dist/engines/expert/index.d.ts +1 -1
- package/dist/engines/expert/index.d.ts.map +1 -1
- package/dist/engines/expert/index.js +3 -1
- package/dist/engines/expert/index.js.map +1 -1
- package/dist/engines/expert/types.d.ts +11 -1
- package/dist/engines/expert/types.d.ts.map +1 -1
- package/dist/engines/expert/types.js +18 -1
- package/dist/engines/expert/types.js.map +1 -1
- package/dist/engines/fuzzy/fuzzy.types.d.ts +65 -8
- package/dist/engines/fuzzy/fuzzy.types.d.ts.map +1 -1
- package/dist/engines/fuzzy/fuzzy.types.js +89 -1
- package/dist/engines/fuzzy/fuzzy.types.js.map +1 -1
- package/dist/engines/loyalty/index.d.ts +1 -0
- package/dist/engines/loyalty/index.d.ts.map +1 -1
- package/dist/engines/loyalty/index.js +8 -1
- package/dist/engines/loyalty/index.js.map +1 -1
- package/dist/engines/loyalty/types.d.ts +36 -5
- package/dist/engines/loyalty/types.d.ts.map +1 -1
- package/dist/engines/loyalty/types.js +40 -0
- package/dist/engines/loyalty/types.js.map +1 -1
- package/dist/engines/menu-engineering/compiler.d.ts +11 -0
- package/dist/engines/menu-engineering/compiler.d.ts.map +1 -0
- package/dist/engines/menu-engineering/compiler.js +119 -0
- package/dist/engines/menu-engineering/compiler.js.map +1 -0
- package/dist/engines/menu-engineering/engine.d.ts +32 -0
- package/dist/engines/menu-engineering/engine.d.ts.map +1 -0
- package/dist/engines/menu-engineering/engine.js +40 -0
- package/dist/engines/menu-engineering/engine.js.map +1 -0
- package/dist/engines/menu-engineering/index.d.ts +9 -0
- package/dist/engines/menu-engineering/index.d.ts.map +1 -0
- package/dist/engines/menu-engineering/index.js +21 -0
- package/dist/engines/menu-engineering/index.js.map +1 -0
- package/dist/engines/menu-engineering/strategy.d.ts +18 -0
- package/dist/engines/menu-engineering/strategy.d.ts.map +1 -0
- package/dist/engines/menu-engineering/strategy.js +318 -0
- package/dist/engines/menu-engineering/strategy.js.map +1 -0
- package/dist/engines/menu-engineering/types.d.ts +187 -0
- package/dist/engines/menu-engineering/types.d.ts.map +1 -0
- package/dist/engines/menu-engineering/types.js +27 -0
- package/dist/engines/menu-engineering/types.js.map +1 -0
- package/dist/engines/monte-carlo/index.d.ts +1 -1
- package/dist/engines/monte-carlo/index.d.ts.map +1 -1
- package/dist/engines/monte-carlo/index.js +5 -1
- package/dist/engines/monte-carlo/index.js.map +1 -1
- package/dist/engines/monte-carlo/types.d.ts +16 -1
- package/dist/engines/monte-carlo/types.d.ts.map +1 -1
- package/dist/engines/monte-carlo/types.js +23 -1
- package/dist/engines/monte-carlo/types.js.map +1 -1
- package/dist/engines/negotiation/index.d.ts +1 -0
- package/dist/engines/negotiation/index.d.ts.map +1 -1
- package/dist/engines/negotiation/index.js +7 -1
- package/dist/engines/negotiation/index.js.map +1 -1
- package/dist/engines/negotiation/types.d.ts +23 -4
- package/dist/engines/negotiation/types.d.ts.map +1 -1
- package/dist/engines/negotiation/types.js +27 -0
- package/dist/engines/negotiation/types.js.map +1 -1
- package/dist/engines/prediction/index.d.ts +1 -1
- package/dist/engines/prediction/index.d.ts.map +1 -1
- package/dist/engines/prediction/index.js +6 -1
- package/dist/engines/prediction/index.js.map +1 -1
- package/dist/engines/prediction/types.d.ts +35 -5
- package/dist/engines/prediction/types.d.ts.map +1 -1
- package/dist/engines/prediction/types.js +39 -1
- package/dist/engines/prediction/types.js.map +1 -1
- package/dist/engines/pricing/index.d.ts +2 -2
- package/dist/engines/pricing/index.d.ts.map +1 -1
- package/dist/engines/pricing/index.js +3 -1
- package/dist/engines/pricing/index.js.map +1 -1
- package/dist/engines/pricing/types.d.ts +15 -1
- package/dist/engines/pricing/types.d.ts.map +1 -1
- package/dist/engines/pricing/types.js +16 -1
- package/dist/engines/pricing/types.js.map +1 -1
- package/dist/engines/ranking/index.d.ts +1 -1
- package/dist/engines/ranking/index.d.ts.map +1 -1
- package/dist/engines/ranking/index.js +6 -1
- package/dist/engines/ranking/index.js.map +1 -1
- package/dist/engines/ranking/types.d.ts +32 -5
- package/dist/engines/ranking/types.d.ts.map +1 -1
- package/dist/engines/ranking/types.js +36 -1
- package/dist/engines/ranking/types.js.map +1 -1
- package/dist/engines/recipe-costing/compiler.d.ts +11 -0
- package/dist/engines/recipe-costing/compiler.d.ts.map +1 -0
- package/dist/engines/recipe-costing/compiler.js +177 -0
- package/dist/engines/recipe-costing/compiler.js.map +1 -0
- package/dist/engines/recipe-costing/engine.d.ts +32 -0
- package/dist/engines/recipe-costing/engine.d.ts.map +1 -0
- package/dist/engines/recipe-costing/engine.js +40 -0
- package/dist/engines/recipe-costing/engine.js.map +1 -0
- package/dist/engines/recipe-costing/index.d.ts +9 -0
- package/dist/engines/recipe-costing/index.d.ts.map +1 -0
- package/dist/engines/recipe-costing/index.js +21 -0
- package/dist/engines/recipe-costing/index.js.map +1 -0
- package/dist/engines/recipe-costing/strategy.d.ts +20 -0
- package/dist/engines/recipe-costing/strategy.d.ts.map +1 -0
- package/dist/engines/recipe-costing/strategy.js +265 -0
- package/dist/engines/recipe-costing/strategy.js.map +1 -0
- package/dist/engines/recipe-costing/types.d.ts +213 -0
- package/dist/engines/recipe-costing/types.d.ts.map +1 -0
- package/dist/engines/recipe-costing/types.js +36 -0
- package/dist/engines/recipe-costing/types.js.map +1 -0
- package/dist/engines/scoring/index.d.ts +1 -1
- package/dist/engines/scoring/index.d.ts.map +1 -1
- package/dist/engines/scoring/index.js +3 -1
- package/dist/engines/scoring/index.js.map +1 -1
- package/dist/engines/scoring/types.d.ts +8 -1
- package/dist/engines/scoring/types.d.ts.map +1 -1
- package/dist/engines/scoring/types.js +18 -1
- package/dist/engines/scoring/types.js.map +1 -1
- package/dist/engines/sentiment/index.d.ts +1 -1
- package/dist/engines/sentiment/index.d.ts.map +1 -1
- package/dist/engines/sentiment/index.js +3 -1
- package/dist/engines/sentiment/index.js.map +1 -1
- package/dist/engines/sentiment/types.d.ts +13 -2
- package/dist/engines/sentiment/types.d.ts.map +1 -1
- package/dist/engines/sentiment/types.js +17 -1
- package/dist/engines/sentiment/types.js.map +1 -1
- package/dist/engines/state-machine/index.d.ts +1 -1
- package/dist/engines/state-machine/index.d.ts.map +1 -1
- package/dist/engines/state-machine/index.js +5 -1
- package/dist/engines/state-machine/index.js.map +1 -1
- package/dist/engines/state-machine/types.d.ts +7 -0
- package/dist/engines/state-machine/types.d.ts.map +1 -1
- package/dist/engines/state-machine/types.js +14 -0
- package/dist/engines/state-machine/types.js.map +1 -1
- package/dist/engines/utility/index.d.ts +2 -2
- package/dist/engines/utility/index.d.ts.map +1 -1
- package/dist/engines/utility/index.js +4 -1
- package/dist/engines/utility/index.js.map +1 -1
- package/dist/engines/utility/types.d.ts +21 -3
- package/dist/engines/utility/types.d.ts.map +1 -1
- package/dist/engines/utility/types.js +37 -1
- package/dist/engines/utility/types.js.map +1 -1
- package/dist/index.d.ts +28 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +73 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/core/evaluation/decay.ts +13 -2
- package/src/core/types/rule.ts +25 -1
- package/src/engines/bayesian/index.ts +1 -0
- package/src/engines/bayesian/types.ts +10 -8
- package/src/engines/constraint/types.ts +40 -11
- package/src/engines/decay/index.ts +4 -0
- package/src/engines/decay/types.ts +26 -4
- package/src/engines/defeasible/index.ts +7 -0
- package/src/engines/defeasible/types.ts +42 -18
- package/src/engines/ensemble/index.ts +6 -0
- package/src/engines/ensemble/types.ts +17 -13
- package/src/engines/expert/index.ts +1 -0
- package/src/engines/expert/types.ts +11 -9
- package/src/engines/fuzzy/fuzzy.types.ts +65 -31
- package/src/engines/loyalty/index.ts +9 -0
- package/src/engines/loyalty/types.ts +36 -5
- package/src/engines/menu-engineering/compiler.ts +145 -0
- package/src/engines/menu-engineering/engine.ts +48 -0
- package/src/engines/menu-engineering/index.ts +47 -0
- package/src/engines/menu-engineering/strategy.ts +414 -0
- package/src/engines/menu-engineering/types.ts +242 -0
- package/src/engines/monte-carlo/index.ts +1 -0
- package/src/engines/monte-carlo/types.ts +16 -21
- package/src/engines/negotiation/index.ts +8 -0
- package/src/engines/negotiation/types.ts +23 -4
- package/src/engines/prediction/index.ts +5 -0
- package/src/engines/prediction/types.ts +35 -5
- package/src/engines/pricing/index.ts +3 -1
- package/src/engines/pricing/types.ts +17 -1
- package/src/engines/ranking/index.ts +5 -0
- package/src/engines/ranking/types.ts +32 -11
- package/src/engines/recipe-costing/compiler.ts +219 -0
- package/src/engines/recipe-costing/engine.ts +48 -0
- package/src/engines/recipe-costing/index.ts +48 -0
- package/src/engines/recipe-costing/strategy.ts +357 -0
- package/src/engines/recipe-costing/types.ts +269 -0
- package/src/engines/scoring/index.ts +2 -0
- package/src/engines/scoring/types.ts +8 -6
- package/src/engines/sentiment/index.ts +2 -0
- package/src/engines/sentiment/types.ts +13 -2
- package/src/engines/state-machine/index.ts +3 -0
- package/src/engines/state-machine/types.ts +8 -0
- package/src/engines/utility/index.ts +5 -0
- package/src/engines/utility/types.ts +23 -3
- package/src/index.ts +146 -8
|
@@ -36,17 +36,24 @@ import { DecayConfig, DecayInfo } from '../../core/evaluation/decay';
|
|
|
36
36
|
* - defeasible: Can be defeated by other rules
|
|
37
37
|
* - defeater: Only blocks conclusions, doesn't assert anything
|
|
38
38
|
*/
|
|
39
|
-
export
|
|
39
|
+
export const RuleStrengths = {
|
|
40
|
+
strict: 'strict',
|
|
41
|
+
defeasible: 'defeasible',
|
|
42
|
+
defeater: 'defeater',
|
|
43
|
+
} as const;
|
|
44
|
+
export type RuleStrength = typeof RuleStrengths[keyof typeof RuleStrengths];
|
|
40
45
|
|
|
41
46
|
/**
|
|
42
47
|
* Conclusion status after evaluation
|
|
43
48
|
*/
|
|
44
|
-
export
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
export const ConclusionStatuses = {
|
|
50
|
+
definitely: 'definitely',
|
|
51
|
+
defeasibly: 'defeasibly',
|
|
52
|
+
defeated: 'defeated',
|
|
53
|
+
blocked: 'blocked',
|
|
54
|
+
undecided: 'undecided',
|
|
55
|
+
} as const;
|
|
56
|
+
export type ConclusionStatus = typeof ConclusionStatuses[keyof typeof ConclusionStatuses];
|
|
50
57
|
|
|
51
58
|
// ========================================
|
|
52
59
|
// Defeat Strength Types
|
|
@@ -55,11 +62,13 @@ export type ConclusionStatus =
|
|
|
55
62
|
/**
|
|
56
63
|
* Semantic defeat strength labels - human-readable
|
|
57
64
|
*/
|
|
58
|
-
export
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
export const SemanticDefeatStrengths = {
|
|
66
|
+
completely: 'completely',
|
|
67
|
+
strongly: 'strongly',
|
|
68
|
+
moderately: 'moderately',
|
|
69
|
+
weakly: 'weakly',
|
|
70
|
+
} as const;
|
|
71
|
+
export type SemanticDefeatStrength = typeof SemanticDefeatStrengths[keyof typeof SemanticDefeatStrengths];
|
|
63
72
|
|
|
64
73
|
/**
|
|
65
74
|
* Semantic strength to numeric mapping
|
|
@@ -91,6 +100,12 @@ export type Credibility =
|
|
|
91
100
|
| 'medium' // 0.7
|
|
92
101
|
| 'low'; // 0.4
|
|
93
102
|
|
|
103
|
+
export const SemanticCredibilityLevels = {
|
|
104
|
+
high: 'high',
|
|
105
|
+
medium: 'medium',
|
|
106
|
+
low: 'low',
|
|
107
|
+
} as const;
|
|
108
|
+
|
|
94
109
|
/**
|
|
95
110
|
* Credibility to numeric mapping
|
|
96
111
|
*/
|
|
@@ -192,11 +207,20 @@ export type SuperiorityRelation = {
|
|
|
192
207
|
/**
|
|
193
208
|
* Aggregation strategy for confidence calculation
|
|
194
209
|
*/
|
|
195
|
-
export
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
210
|
+
export const DefeasibleAggregations = {
|
|
211
|
+
average: 'average',
|
|
212
|
+
maxMin: 'max-min',
|
|
213
|
+
weightedSum: 'weighted-sum',
|
|
214
|
+
probabilistic: 'probabilistic',
|
|
215
|
+
} as const;
|
|
216
|
+
export type AggregationStrategy = typeof DefeasibleAggregations[keyof typeof DefeasibleAggregations];
|
|
217
|
+
|
|
218
|
+
export const ConflictResolutions = {
|
|
219
|
+
specificity: 'specificity',
|
|
220
|
+
priority: 'priority',
|
|
221
|
+
explicit: 'explicit',
|
|
222
|
+
} as const;
|
|
223
|
+
export type ConflictResolution = typeof ConflictResolutions[keyof typeof ConflictResolutions];
|
|
200
224
|
|
|
201
225
|
/**
|
|
202
226
|
* Defeasible engine configuration
|
|
@@ -222,7 +246,7 @@ export type DefeasibleConfig = {
|
|
|
222
246
|
* - 'explicit': Only explicit defeats/superiority apply
|
|
223
247
|
* Default: 'specificity'
|
|
224
248
|
*/
|
|
225
|
-
conflictResolution?:
|
|
249
|
+
conflictResolution?: ConflictResolution;
|
|
226
250
|
|
|
227
251
|
/**
|
|
228
252
|
* Maximum iterations for computing defeat cycles (default: 100)
|
|
@@ -18,13 +18,15 @@ import type { FactInput } from '../../core';
|
|
|
18
18
|
// Fusion Strategy
|
|
19
19
|
// ========================================
|
|
20
20
|
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
export const FusionStrategies = {
|
|
22
|
+
weightedAverage: 'weighted-average',
|
|
23
|
+
median: 'median',
|
|
24
|
+
min: 'min',
|
|
25
|
+
max: 'max',
|
|
26
|
+
voting: 'voting',
|
|
27
|
+
stacking: 'stacking',
|
|
28
|
+
} as const;
|
|
29
|
+
export type FusionStrategy = typeof FusionStrategies[keyof typeof FusionStrategies];
|
|
28
30
|
|
|
29
31
|
// ========================================
|
|
30
32
|
// Member Definitions (Source)
|
|
@@ -123,12 +125,14 @@ export type MemberResult = {
|
|
|
123
125
|
// ========================================
|
|
124
126
|
|
|
125
127
|
/** Semantic agreement levels based on coefficient of variation */
|
|
126
|
-
export
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
export const AgreementLevels = {
|
|
129
|
+
unanimous: 'unanimous',
|
|
130
|
+
strong: 'strong',
|
|
131
|
+
moderate: 'moderate',
|
|
132
|
+
weak: 'weak',
|
|
133
|
+
divided: 'divided',
|
|
134
|
+
} as const;
|
|
135
|
+
export type AgreementLevel = typeof AgreementLevels[keyof typeof AgreementLevels];
|
|
132
136
|
|
|
133
137
|
/** Ensemble result — mirrors ScoringResult shape for downstream compatibility */
|
|
134
138
|
export type EnsembleResult<T extends TierDefinition = TierDefinition> = {
|
|
@@ -32,15 +32,17 @@ import {
|
|
|
32
32
|
* Semantic confidence labels for human-readable rule authoring.
|
|
33
33
|
* Maps to numeric values between 0.0 and 1.0.
|
|
34
34
|
*/
|
|
35
|
-
export
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
export const SemanticConfidences = {
|
|
36
|
+
certain: 'certain',
|
|
37
|
+
veryHigh: 'very-high',
|
|
38
|
+
high: 'high',
|
|
39
|
+
likely: 'likely',
|
|
40
|
+
moderate: 'moderate',
|
|
41
|
+
possible: 'possible',
|
|
42
|
+
unlikely: 'unlikely',
|
|
43
|
+
low: 'low',
|
|
44
|
+
} as const;
|
|
45
|
+
export type SemanticConfidence = typeof SemanticConfidences[keyof typeof SemanticConfidences];
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
48
|
* Mapping from semantic labels to numeric confidence values.
|
|
@@ -15,22 +15,48 @@ import { BindingContext } from '../../core';
|
|
|
15
15
|
* Membership function shapes
|
|
16
16
|
* These define how membership degree (0-1) is calculated from a crisp value
|
|
17
17
|
*/
|
|
18
|
-
export
|
|
18
|
+
export const MembershipShapes = {
|
|
19
|
+
triangle: 'triangle',
|
|
20
|
+
trapezoid: 'trapezoid',
|
|
21
|
+
gaussian: 'gaussian',
|
|
22
|
+
shoulder: 'shoulder',
|
|
23
|
+
block: 'block',
|
|
24
|
+
} as const;
|
|
25
|
+
export type MembershipShape = typeof MembershipShapes[keyof typeof MembershipShapes];
|
|
19
26
|
|
|
20
27
|
/**
|
|
21
28
|
* Semantic position within domain (compiles to numeric center)
|
|
22
29
|
*/
|
|
23
|
-
export
|
|
30
|
+
export const PositionSemantics = {
|
|
31
|
+
veryLow: 'very-low',
|
|
32
|
+
low: 'low',
|
|
33
|
+
medium: 'medium',
|
|
34
|
+
high: 'high',
|
|
35
|
+
veryHigh: 'very-high',
|
|
36
|
+
} as const;
|
|
37
|
+
export type PositionSemantic = typeof PositionSemantics[keyof typeof PositionSemantics];
|
|
24
38
|
|
|
25
39
|
/**
|
|
26
40
|
* Semantic width/spread (compiles to numeric spread as % of domain)
|
|
27
41
|
*/
|
|
28
|
-
export
|
|
42
|
+
export const WidthSemantics = {
|
|
43
|
+
tight: 'tight',
|
|
44
|
+
narrow: 'narrow',
|
|
45
|
+
medium: 'medium',
|
|
46
|
+
wide: 'wide',
|
|
47
|
+
veryWide: 'very-wide',
|
|
48
|
+
} as const;
|
|
49
|
+
export type WidthSemantic = typeof WidthSemantics[keyof typeof WidthSemantics];
|
|
29
50
|
|
|
30
51
|
/**
|
|
31
52
|
* Edge behavior for shoulder/block shapes
|
|
32
53
|
*/
|
|
33
|
-
export
|
|
54
|
+
export const EdgeSemantics = {
|
|
55
|
+
openLeft: 'open-left',
|
|
56
|
+
openRight: 'open-right',
|
|
57
|
+
closed: 'closed',
|
|
58
|
+
} as const;
|
|
59
|
+
export type EdgeSemantic = typeof EdgeSemantics[keyof typeof EdgeSemantics];
|
|
34
60
|
|
|
35
61
|
// ========================================
|
|
36
62
|
// Fuzzy Term Definitions
|
|
@@ -127,33 +153,39 @@ export type CompiledFuzzyVariable = {
|
|
|
127
153
|
/**
|
|
128
154
|
* Aggregation methods - combine multiple rule activations for same output
|
|
129
155
|
*/
|
|
130
|
-
export
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
156
|
+
export const AggregationMethods = {
|
|
157
|
+
max: 'max',
|
|
158
|
+
sum: 'sum',
|
|
159
|
+
probor: 'probor',
|
|
160
|
+
bound: 'bound',
|
|
161
|
+
min: 'min',
|
|
162
|
+
} as const;
|
|
163
|
+
export type AggregationMethod = typeof AggregationMethods[keyof typeof AggregationMethods];
|
|
136
164
|
|
|
137
165
|
/**
|
|
138
166
|
* Defuzzification methods - convert fuzzy output to crisp value
|
|
139
167
|
*/
|
|
140
|
-
export
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
168
|
+
export const DefuzzifyMethods = {
|
|
169
|
+
centroid: 'centroid',
|
|
170
|
+
bisector: 'bisector',
|
|
171
|
+
mom: 'mom',
|
|
172
|
+
som: 'som',
|
|
173
|
+
lom: 'lom',
|
|
174
|
+
wtaver: 'wtaver',
|
|
175
|
+
} as const;
|
|
176
|
+
export type DefuzzifyMethod = typeof DefuzzifyMethods[keyof typeof DefuzzifyMethods];
|
|
147
177
|
|
|
148
178
|
/**
|
|
149
179
|
* Transform methods - post-process the crisp output
|
|
150
180
|
*/
|
|
151
|
-
export
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
181
|
+
export const TransformMethods = {
|
|
182
|
+
clamp: 'clamp',
|
|
183
|
+
round: 'round',
|
|
184
|
+
deadband: 'deadband',
|
|
185
|
+
scale: 'scale',
|
|
186
|
+
quantize: 'quantize',
|
|
187
|
+
} as const;
|
|
188
|
+
export type TransformMethod = typeof TransformMethods[keyof typeof TransformMethods];
|
|
157
189
|
|
|
158
190
|
/**
|
|
159
191
|
* Any defuzzification pipeline stage
|
|
@@ -163,14 +195,16 @@ export type DefuzzifyStage = AggregationMethod | DefuzzifyMethod | TransformMeth
|
|
|
163
195
|
/**
|
|
164
196
|
* Named presets that expand to full pipelines
|
|
165
197
|
*/
|
|
166
|
-
export
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
198
|
+
export const DefuzzifyPresets = {
|
|
199
|
+
balanced: 'balanced',
|
|
200
|
+
smooth: 'smooth',
|
|
201
|
+
decisive: 'decisive',
|
|
202
|
+
cautious: 'cautious',
|
|
203
|
+
aggressive: 'aggressive',
|
|
204
|
+
discrete: 'discrete',
|
|
205
|
+
stable: 'stable',
|
|
206
|
+
} as const;
|
|
207
|
+
export type DefuzzifyPreset = typeof DefuzzifyPresets[keyof typeof DefuzzifyPresets];
|
|
174
208
|
|
|
175
209
|
/**
|
|
176
210
|
* Defuzzification pipeline configuration
|
|
@@ -33,6 +33,15 @@ export type {
|
|
|
33
33
|
LoyaltyIngestResult
|
|
34
34
|
} from './types';
|
|
35
35
|
|
|
36
|
+
// Constants
|
|
37
|
+
export {
|
|
38
|
+
LoyaltyStrategies,
|
|
39
|
+
PointTransactionTypes,
|
|
40
|
+
TierStatuses,
|
|
41
|
+
QualifyingMetrics,
|
|
42
|
+
EvaluationPeriods
|
|
43
|
+
} from './types';
|
|
44
|
+
|
|
36
45
|
// Compiler
|
|
37
46
|
export { compileLoyaltyRuleSet } from './compiler';
|
|
38
47
|
|
|
@@ -14,19 +14,50 @@ import type { Condition } from '../../core/types/condition';
|
|
|
14
14
|
// ========================================
|
|
15
15
|
|
|
16
16
|
/** Loyalty strategy to use */
|
|
17
|
-
export
|
|
17
|
+
export const LoyaltyStrategies = {
|
|
18
|
+
earning: 'earning',
|
|
19
|
+
redemption: 'redemption',
|
|
20
|
+
tierEvaluation: 'tier-evaluation',
|
|
21
|
+
} as const;
|
|
22
|
+
export type LoyaltyStrategy = typeof LoyaltyStrategies[keyof typeof LoyaltyStrategies];
|
|
18
23
|
|
|
19
24
|
/** Point transaction type */
|
|
20
|
-
export
|
|
25
|
+
export const PointTransactionTypes = {
|
|
26
|
+
earn: 'earn',
|
|
27
|
+
redeem: 'redeem',
|
|
28
|
+
expire: 'expire',
|
|
29
|
+
transfer: 'transfer',
|
|
30
|
+
adjust: 'adjust',
|
|
31
|
+
} as const;
|
|
32
|
+
export type PointTransactionType = typeof PointTransactionTypes[keyof typeof PointTransactionTypes];
|
|
21
33
|
|
|
22
34
|
/** Member tier status */
|
|
23
|
-
export
|
|
35
|
+
export const TierStatuses = {
|
|
36
|
+
qualified: 'qualified',
|
|
37
|
+
atRisk: 'at-risk',
|
|
38
|
+
downgradePending: 'downgrade-pending',
|
|
39
|
+
locked: 'locked',
|
|
40
|
+
} as const;
|
|
41
|
+
export type TierStatus = typeof TierStatuses[keyof typeof TierStatuses];
|
|
24
42
|
|
|
25
43
|
/** Qualifying metric for tier evaluation */
|
|
26
|
-
export
|
|
44
|
+
export const QualifyingMetrics = {
|
|
45
|
+
pointsEarned: 'points-earned',
|
|
46
|
+
qualifyingSpend: 'qualifying-spend',
|
|
47
|
+
qualifyingNights: 'qualifying-nights',
|
|
48
|
+
qualifyingFlights: 'qualifying-flights',
|
|
49
|
+
qualifyingRentalDays: 'qualifying-rental-days',
|
|
50
|
+
qualifyingCruiseDays: 'qualifying-cruise-days',
|
|
51
|
+
} as const;
|
|
52
|
+
export type QualifyingMetric = typeof QualifyingMetrics[keyof typeof QualifyingMetrics];
|
|
27
53
|
|
|
28
54
|
/** Evaluation period for tier assessment */
|
|
29
|
-
export
|
|
55
|
+
export const EvaluationPeriods = {
|
|
56
|
+
rolling12Months: 'rolling-12-months',
|
|
57
|
+
calendarYear: 'calendar-year',
|
|
58
|
+
custom: 'custom',
|
|
59
|
+
} as const;
|
|
60
|
+
export type EvaluationPeriod = typeof EvaluationPeriods[keyof typeof EvaluationPeriods];
|
|
30
61
|
|
|
31
62
|
// ========================================
|
|
32
63
|
// Core Domain Types
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Menu Engineering Engine Compiler
|
|
3
|
+
*
|
|
4
|
+
* Validates menu engineering rulesets and resolves defaults.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { CompilationError } from '../../core/errors';
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
MenuEngineeringRuleSet,
|
|
11
|
+
CompiledMenuEngineeringRuleSet,
|
|
12
|
+
CompiledClassifyRuleSet,
|
|
13
|
+
CompiledPriceOptimizationRuleSet,
|
|
14
|
+
CompiledMixAnalysisRuleSet
|
|
15
|
+
} from './types';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Compile and validate a menu engineering ruleset.
|
|
19
|
+
*/
|
|
20
|
+
export function compileMenuEngineeringRuleSet(
|
|
21
|
+
ruleSet: MenuEngineeringRuleSet
|
|
22
|
+
): CompiledMenuEngineeringRuleSet {
|
|
23
|
+
if (!ruleSet.id) {
|
|
24
|
+
throw new CompilationError('Menu engineering ruleset requires an id');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (ruleSet.mode !== 'menu-engineering') {
|
|
28
|
+
throw new CompilationError(`Expected mode 'menu-engineering', got '${ruleSet.mode}'`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!ruleSet.items || ruleSet.items.length === 0) {
|
|
32
|
+
throw new CompilationError('Menu engineering ruleset requires at least one menu item');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Validate unique item IDs
|
|
36
|
+
const itemIds = new Set<string>();
|
|
37
|
+
for (const item of ruleSet.items) {
|
|
38
|
+
if (!item.id) {
|
|
39
|
+
throw new CompilationError('Each menu item requires an id');
|
|
40
|
+
}
|
|
41
|
+
if (itemIds.has(item.id)) {
|
|
42
|
+
throw new CompilationError(`Duplicate menu item id: '${item.id}'`);
|
|
43
|
+
}
|
|
44
|
+
if (item.sellingPrice < 0) {
|
|
45
|
+
throw new CompilationError(`Menu item '${item.id}' sellingPrice must be non-negative`);
|
|
46
|
+
}
|
|
47
|
+
if (item.plateCost < 0) {
|
|
48
|
+
throw new CompilationError(`Menu item '${item.id}' plateCost must be non-negative`);
|
|
49
|
+
}
|
|
50
|
+
if (item.salesCount < 0) {
|
|
51
|
+
throw new CompilationError(`Menu item '${item.id}' salesCount must be non-negative`);
|
|
52
|
+
}
|
|
53
|
+
itemIds.add(item.id);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
switch (ruleSet.strategy) {
|
|
57
|
+
case 'classify':
|
|
58
|
+
return compileClassify(ruleSet);
|
|
59
|
+
case 'price-optimization':
|
|
60
|
+
return compilePriceOptimization(ruleSet);
|
|
61
|
+
case 'mix-analysis':
|
|
62
|
+
return compileMixAnalysis(ruleSet);
|
|
63
|
+
default:
|
|
64
|
+
throw new CompilationError(`Unknown menu engineering strategy: '${(ruleSet as any).strategy}'`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function compileClassify(
|
|
69
|
+
ruleSet: MenuEngineeringRuleSet & { strategy: 'classify' }
|
|
70
|
+
): CompiledClassifyRuleSet {
|
|
71
|
+
const config = ruleSet.config ?? {};
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
id: ruleSet.id,
|
|
75
|
+
name: ruleSet.name,
|
|
76
|
+
mode: 'menu-engineering',
|
|
77
|
+
strategy: 'classify',
|
|
78
|
+
items: ruleSet.items,
|
|
79
|
+
config: {
|
|
80
|
+
mixThresholdMode: config.mixThresholdMode ?? 'average',
|
|
81
|
+
customMixThreshold: config.customMixThreshold ?? 0,
|
|
82
|
+
marginThresholdMode: config.marginThresholdMode ?? 'average',
|
|
83
|
+
customMarginThreshold: config.customMarginThreshold ?? 0
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function compilePriceOptimization(
|
|
89
|
+
ruleSet: MenuEngineeringRuleSet & { strategy: 'price-optimization' }
|
|
90
|
+
): CompiledPriceOptimizationRuleSet {
|
|
91
|
+
if (!ruleSet.config || !ruleSet.config.priceChanges || ruleSet.config.priceChanges.length === 0) {
|
|
92
|
+
throw new CompilationError('Price-optimization strategy requires at least one price change');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Validate price changes reference existing items
|
|
96
|
+
const itemIds = new Set(ruleSet.items.map(i => i.id));
|
|
97
|
+
for (const change of ruleSet.config.priceChanges) {
|
|
98
|
+
if (!itemIds.has(change.itemId)) {
|
|
99
|
+
throw new CompilationError(`Price change references unknown item: '${change.itemId}'`);
|
|
100
|
+
}
|
|
101
|
+
if (change.newPrice < 0) {
|
|
102
|
+
throw new CompilationError(`Price change for '${change.itemId}' newPrice must be non-negative`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
id: ruleSet.id,
|
|
108
|
+
name: ruleSet.name,
|
|
109
|
+
mode: 'menu-engineering',
|
|
110
|
+
strategy: 'price-optimization',
|
|
111
|
+
items: ruleSet.items,
|
|
112
|
+
config: {
|
|
113
|
+
priceChanges: ruleSet.config.priceChanges,
|
|
114
|
+
elasticities: ruleSet.config.elasticities ?? [],
|
|
115
|
+
defaultElasticity: ruleSet.config.defaultElasticity ?? -1.0
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function compileMixAnalysis(
|
|
121
|
+
ruleSet: MenuEngineeringRuleSet & { strategy: 'mix-analysis' }
|
|
122
|
+
): CompiledMixAnalysisRuleSet {
|
|
123
|
+
const config = ruleSet.config ?? {};
|
|
124
|
+
const groupBy = config.groupBy ?? 'category';
|
|
125
|
+
|
|
126
|
+
if (groupBy === 'category') {
|
|
127
|
+
// Verify at least some items have categories
|
|
128
|
+
const hasCategories = ruleSet.items.some(i => i.category);
|
|
129
|
+
if (!hasCategories) {
|
|
130
|
+
throw new CompilationError('Mix-analysis with groupBy "category" requires items with category values');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
id: ruleSet.id,
|
|
136
|
+
name: ruleSet.name,
|
|
137
|
+
mode: 'menu-engineering',
|
|
138
|
+
strategy: 'mix-analysis',
|
|
139
|
+
items: ruleSet.items,
|
|
140
|
+
config: {
|
|
141
|
+
groupBy,
|
|
142
|
+
daypartField: config.daypartField ?? 'daypart'
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Menu Engineering Engine
|
|
3
|
+
*
|
|
4
|
+
* Classifies menu items into Stars/Plowhorses/Puzzles/Dogs based on
|
|
5
|
+
* sales mix percentage and contribution margin. Supports price optimization
|
|
6
|
+
* with elasticity modeling and category-level mix analysis.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const engine = new MenuEngineeringEngine();
|
|
11
|
+
*
|
|
12
|
+
* const result = engine.execute(compiledMenuEngineering);
|
|
13
|
+
* // result.items -> classified menu items with recommendations
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
CompiledMenuEngineeringRuleSet,
|
|
19
|
+
MenuEngineeringOptions,
|
|
20
|
+
MenuEngineeringResult
|
|
21
|
+
} from './types';
|
|
22
|
+
|
|
23
|
+
import { MenuEngineeringExecutor } from './strategy';
|
|
24
|
+
|
|
25
|
+
export class MenuEngineeringEngine {
|
|
26
|
+
private strategy: MenuEngineeringExecutor;
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
this.strategy = new MenuEngineeringExecutor();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Execute a menu engineering ruleset.
|
|
34
|
+
*
|
|
35
|
+
* Classifies menu items, optimizes prices, or analyzes category mix
|
|
36
|
+
* depending on the strategy.
|
|
37
|
+
*
|
|
38
|
+
* @param ruleSet - Compiled menu engineering ruleset
|
|
39
|
+
* @param options - Runtime options
|
|
40
|
+
* @returns Menu engineering result
|
|
41
|
+
*/
|
|
42
|
+
execute(
|
|
43
|
+
ruleSet: CompiledMenuEngineeringRuleSet,
|
|
44
|
+
options: MenuEngineeringOptions = {}
|
|
45
|
+
): MenuEngineeringResult {
|
|
46
|
+
return this.strategy.run(ruleSet, options);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Menu Engineering Engine -- Menu Item Classification & Optimization
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Types
|
|
6
|
+
export type {
|
|
7
|
+
MenuEngineeringStrategy,
|
|
8
|
+
MenuClassification,
|
|
9
|
+
MenuItem,
|
|
10
|
+
PriceElasticity,
|
|
11
|
+
PriceChange,
|
|
12
|
+
ClassifyConfig,
|
|
13
|
+
PriceOptimizationConfig,
|
|
14
|
+
MixAnalysisConfig,
|
|
15
|
+
ClassifyRuleSet,
|
|
16
|
+
PriceOptimizationRuleSet,
|
|
17
|
+
MixAnalysisRuleSet,
|
|
18
|
+
MenuEngineeringRuleSet,
|
|
19
|
+
CompiledClassifyRuleSet,
|
|
20
|
+
CompiledPriceOptimizationRuleSet,
|
|
21
|
+
CompiledMixAnalysisRuleSet,
|
|
22
|
+
CompiledMenuEngineeringRuleSet,
|
|
23
|
+
ClassifiedItem,
|
|
24
|
+
MenuSummary,
|
|
25
|
+
PriceOptimizationItem,
|
|
26
|
+
CategoryMixResult,
|
|
27
|
+
ClassifyResult,
|
|
28
|
+
PriceOptimizationResult,
|
|
29
|
+
MixAnalysisResult,
|
|
30
|
+
MenuEngineeringResult,
|
|
31
|
+
MenuEngineeringOptions
|
|
32
|
+
} from './types';
|
|
33
|
+
|
|
34
|
+
// Constants
|
|
35
|
+
export {
|
|
36
|
+
MenuEngineeringStrategies,
|
|
37
|
+
MenuClassifications
|
|
38
|
+
} from './types';
|
|
39
|
+
|
|
40
|
+
// Compiler
|
|
41
|
+
export { compileMenuEngineeringRuleSet } from './compiler';
|
|
42
|
+
|
|
43
|
+
// Strategy
|
|
44
|
+
export { MenuEngineeringExecutor, menuEngineeringStrategy } from './strategy';
|
|
45
|
+
|
|
46
|
+
// Engine
|
|
47
|
+
export { MenuEngineeringEngine } from './engine';
|