numopt-js 0.1.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/CODING_RULES.md +161 -0
- package/LICENSE +22 -0
- package/README.md +807 -0
- package/dist/core/adjointGradientDescent.d.ts +61 -0
- package/dist/core/adjointGradientDescent.d.ts.map +1 -0
- package/dist/core/adjointGradientDescent.js +764 -0
- package/dist/core/adjointGradientDescent.js.map +1 -0
- package/dist/core/constrainedGaussNewton.d.ts +44 -0
- package/dist/core/constrainedGaussNewton.d.ts.map +1 -0
- package/dist/core/constrainedGaussNewton.js +314 -0
- package/dist/core/constrainedGaussNewton.js.map +1 -0
- package/dist/core/constrainedLevenbergMarquardt.d.ts +46 -0
- package/dist/core/constrainedLevenbergMarquardt.d.ts.map +1 -0
- package/dist/core/constrainedLevenbergMarquardt.js +469 -0
- package/dist/core/constrainedLevenbergMarquardt.js.map +1 -0
- package/dist/core/constrainedUtils.d.ts +92 -0
- package/dist/core/constrainedUtils.d.ts.map +1 -0
- package/dist/core/constrainedUtils.js +364 -0
- package/dist/core/constrainedUtils.js.map +1 -0
- package/dist/core/convergence.d.ts +35 -0
- package/dist/core/convergence.d.ts.map +1 -0
- package/dist/core/convergence.js +51 -0
- package/dist/core/convergence.js.map +1 -0
- package/dist/core/createGradientFunction.d.ts +85 -0
- package/dist/core/createGradientFunction.d.ts.map +1 -0
- package/dist/core/createGradientFunction.js +93 -0
- package/dist/core/createGradientFunction.js.map +1 -0
- package/dist/core/effectiveJacobian.d.ts +90 -0
- package/dist/core/effectiveJacobian.d.ts.map +1 -0
- package/dist/core/effectiveJacobian.js +128 -0
- package/dist/core/effectiveJacobian.js.map +1 -0
- package/dist/core/finiteDiff.d.ts +171 -0
- package/dist/core/finiteDiff.d.ts.map +1 -0
- package/dist/core/finiteDiff.js +363 -0
- package/dist/core/finiteDiff.js.map +1 -0
- package/dist/core/gaussNewton.d.ts +29 -0
- package/dist/core/gaussNewton.d.ts.map +1 -0
- package/dist/core/gaussNewton.js +151 -0
- package/dist/core/gaussNewton.js.map +1 -0
- package/dist/core/gradientDescent.d.ts +35 -0
- package/dist/core/gradientDescent.d.ts.map +1 -0
- package/dist/core/gradientDescent.js +204 -0
- package/dist/core/gradientDescent.js.map +1 -0
- package/dist/core/jacobianComputation.d.ts +24 -0
- package/dist/core/jacobianComputation.d.ts.map +1 -0
- package/dist/core/jacobianComputation.js +38 -0
- package/dist/core/jacobianComputation.js.map +1 -0
- package/dist/core/levenbergMarquardt.d.ts +36 -0
- package/dist/core/levenbergMarquardt.d.ts.map +1 -0
- package/dist/core/levenbergMarquardt.js +286 -0
- package/dist/core/levenbergMarquardt.js.map +1 -0
- package/dist/core/lineSearch.d.ts +42 -0
- package/dist/core/lineSearch.d.ts.map +1 -0
- package/dist/core/lineSearch.js +106 -0
- package/dist/core/lineSearch.js.map +1 -0
- package/dist/core/logger.d.ts +77 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +162 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/types.d.ts +427 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +15 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/formatting.d.ts +27 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/formatting.js +54 -0
- package/dist/utils/formatting.js.map +1 -0
- package/dist/utils/matrix.d.ts +63 -0
- package/dist/utils/matrix.d.ts.map +1 -0
- package/dist/utils/matrix.js +129 -0
- package/dist/utils/matrix.js.map +1 -0
- package/dist/utils/resultFormatter.d.ts +122 -0
- package/dist/utils/resultFormatter.d.ts.map +1 -0
- package/dist/utils/resultFormatter.js +342 -0
- package/dist/utils/resultFormatter.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file implements line search algorithms for determining optimal step sizes
|
|
3
|
+
* in optimization algorithms. The implementation follows the backtracking
|
|
4
|
+
* Armijo line search described in Nocedal & Wright, "Numerical Optimization"
|
|
5
|
+
* (2nd ed.), Algorithm 3.1.
|
|
6
|
+
*
|
|
7
|
+
* Role in system:
|
|
8
|
+
* - Used by gradient descent to find appropriate step sizes
|
|
9
|
+
* - Implements backtracking line search with Armijo condition
|
|
10
|
+
* - Critical for convergence of gradient-based methods
|
|
11
|
+
*
|
|
12
|
+
* For first-time readers:
|
|
13
|
+
* - Start with backtrackingLineSearch function
|
|
14
|
+
* - Understand Armijo condition (sufficient decrease)
|
|
15
|
+
* - Line search prevents overshooting the minimum
|
|
16
|
+
*/
|
|
17
|
+
import type { CostFn, GradientFn, LineSearchOptions } from './types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Performs backtracking line search to find a step size that satisfies
|
|
20
|
+
* the Armijo condition (sufficient decrease). This follows the textbook
|
|
21
|
+
* backtracking scheme in Nocedal & Wright, "Numerical Optimization"
|
|
22
|
+
* (2nd ed.), Algorithm 3.1.
|
|
23
|
+
*
|
|
24
|
+
* The Armijo condition ensures that the function value decreases sufficiently:
|
|
25
|
+
* f(x + α * d) <= f(x) + c * α * ∇f(x)^T * d
|
|
26
|
+
*
|
|
27
|
+
* where:
|
|
28
|
+
* - α is the step size
|
|
29
|
+
* - d is the search direction (typically -gradient)
|
|
30
|
+
* - c is the Armijo parameter (typically chosen around 1e-4 per Nocedal & Wright)
|
|
31
|
+
* - β is the backtracking contraction factor (Algorithm 3.1 suggests β = 0.5)
|
|
32
|
+
*
|
|
33
|
+
* Initial step size selection:
|
|
34
|
+
* - If `initialStepSize` is explicitly provided in options, it is used as-is.
|
|
35
|
+
* - Otherwise, the initial step size is automatically scaled by the gradient norm:
|
|
36
|
+
* α₀ = 1.0 / ||∇f(x)||
|
|
37
|
+
* This prevents steps from being too large when gradients are large, improving
|
|
38
|
+
* convergence performance. If the gradient norm is very small (< 1e-10) or the
|
|
39
|
+
* computed step size is not finite, the default value of 1.0 is used.
|
|
40
|
+
*/
|
|
41
|
+
export declare function backtrackingLineSearch(costFunction: CostFn, gradientFunction: GradientFn, currentParameters: Float64Array, searchDirection: Float64Array, options?: LineSearchOptions): number;
|
|
42
|
+
//# sourceMappingURL=lineSearch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lineSearch.d.ts","sourceRoot":"","sources":["../../src/core/lineSearch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAYxE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,UAAU,EAC5B,iBAAiB,EAAE,YAAY,EAC/B,eAAe,EAAE,YAAY,EAC7B,OAAO,GAAE,iBAAsB,GAC9B,MAAM,CAmER"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file implements line search algorithms for determining optimal step sizes
|
|
3
|
+
* in optimization algorithms. The implementation follows the backtracking
|
|
4
|
+
* Armijo line search described in Nocedal & Wright, "Numerical Optimization"
|
|
5
|
+
* (2nd ed.), Algorithm 3.1.
|
|
6
|
+
*
|
|
7
|
+
* Role in system:
|
|
8
|
+
* - Used by gradient descent to find appropriate step sizes
|
|
9
|
+
* - Implements backtracking line search with Armijo condition
|
|
10
|
+
* - Critical for convergence of gradient-based methods
|
|
11
|
+
*
|
|
12
|
+
* For first-time readers:
|
|
13
|
+
* - Start with backtrackingLineSearch function
|
|
14
|
+
* - Understand Armijo condition (sufficient decrease)
|
|
15
|
+
* - Line search prevents overshooting the minimum
|
|
16
|
+
*/
|
|
17
|
+
import { vectorNorm } from '../utils/matrix.js';
|
|
18
|
+
const DEFAULT_INITIAL_STEP_SIZE = 1.0;
|
|
19
|
+
const GRADIENT_NORM_THRESHOLD = 1e-10; // Threshold below which we use default step size to avoid numerical instability
|
|
20
|
+
// Typical values recommended in Nocedal & Wright (Algorithm 3.1) are β = 0.5 and c = 1e-4.
|
|
21
|
+
const DEFAULT_CONTRACTION_FACTOR = 0.5;
|
|
22
|
+
const DEFAULT_ARMIJO_PARAMETER = 1e-4;
|
|
23
|
+
const DEFAULT_MAX_LINE_SEARCH_ITERATIONS = 50;
|
|
24
|
+
const INVALID_STEP_SIZE = 0.0; // Returned when search direction is not a descent direction
|
|
25
|
+
const NON_DESCENT_DIRECTION_THRESHOLD = 0.0; // Threshold for directional derivative: >= 0 means not a descent direction
|
|
26
|
+
/**
|
|
27
|
+
* Performs backtracking line search to find a step size that satisfies
|
|
28
|
+
* the Armijo condition (sufficient decrease). This follows the textbook
|
|
29
|
+
* backtracking scheme in Nocedal & Wright, "Numerical Optimization"
|
|
30
|
+
* (2nd ed.), Algorithm 3.1.
|
|
31
|
+
*
|
|
32
|
+
* The Armijo condition ensures that the function value decreases sufficiently:
|
|
33
|
+
* f(x + α * d) <= f(x) + c * α * ∇f(x)^T * d
|
|
34
|
+
*
|
|
35
|
+
* where:
|
|
36
|
+
* - α is the step size
|
|
37
|
+
* - d is the search direction (typically -gradient)
|
|
38
|
+
* - c is the Armijo parameter (typically chosen around 1e-4 per Nocedal & Wright)
|
|
39
|
+
* - β is the backtracking contraction factor (Algorithm 3.1 suggests β = 0.5)
|
|
40
|
+
*
|
|
41
|
+
* Initial step size selection:
|
|
42
|
+
* - If `initialStepSize` is explicitly provided in options, it is used as-is.
|
|
43
|
+
* - Otherwise, the initial step size is automatically scaled by the gradient norm:
|
|
44
|
+
* α₀ = 1.0 / ||∇f(x)||
|
|
45
|
+
* This prevents steps from being too large when gradients are large, improving
|
|
46
|
+
* convergence performance. If the gradient norm is very small (< 1e-10) or the
|
|
47
|
+
* computed step size is not finite, the default value of 1.0 is used.
|
|
48
|
+
*/
|
|
49
|
+
export function backtrackingLineSearch(costFunction, gradientFunction, currentParameters, searchDirection, options = {}) {
|
|
50
|
+
const contractionFactor = options.contractionFactor ?? DEFAULT_CONTRACTION_FACTOR;
|
|
51
|
+
const armijoParameter = options.armijoParameter ?? DEFAULT_ARMIJO_PARAMETER;
|
|
52
|
+
const maxIterations = options.maxIterations ?? DEFAULT_MAX_LINE_SEARCH_ITERATIONS;
|
|
53
|
+
const currentCost = costFunction(currentParameters);
|
|
54
|
+
const currentGradient = gradientFunction(currentParameters);
|
|
55
|
+
// Determine initial step size: use provided value, or scale by gradient norm if not provided
|
|
56
|
+
let initialStepSize;
|
|
57
|
+
if (options.initialStepSize !== undefined) {
|
|
58
|
+
// Use explicitly provided initial step size (maintains backward compatibility)
|
|
59
|
+
initialStepSize = options.initialStepSize;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Scale initial step size by gradient norm: 1.0 / ||gradient||
|
|
63
|
+
// This prevents steps from being too large when gradients are large
|
|
64
|
+
const gradientNorm = vectorNorm(currentGradient);
|
|
65
|
+
// Handle edge cases: very small or zero gradient norm
|
|
66
|
+
if (gradientNorm < GRADIENT_NORM_THRESHOLD) {
|
|
67
|
+
initialStepSize = DEFAULT_INITIAL_STEP_SIZE;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
initialStepSize = 1.0 / gradientNorm;
|
|
71
|
+
// Additional safety check for NaN or Infinity
|
|
72
|
+
if (!isFinite(initialStepSize)) {
|
|
73
|
+
initialStepSize = DEFAULT_INITIAL_STEP_SIZE;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Compute directional derivative: ∇f(x)^T * d
|
|
78
|
+
let directionalDerivative = 0.0;
|
|
79
|
+
for (let i = 0; i < currentGradient.length; i++) {
|
|
80
|
+
directionalDerivative += currentGradient[i] * searchDirection[i];
|
|
81
|
+
}
|
|
82
|
+
// Early return if search direction is not a descent direction
|
|
83
|
+
// Directional derivative >= 0 means moving in this direction increases the cost
|
|
84
|
+
if (directionalDerivative >= NON_DESCENT_DIRECTION_THRESHOLD) {
|
|
85
|
+
return INVALID_STEP_SIZE;
|
|
86
|
+
}
|
|
87
|
+
let stepSize = initialStepSize;
|
|
88
|
+
for (let iteration = 0; iteration < maxIterations; iteration++) {
|
|
89
|
+
// Compute trial point: x + α * d
|
|
90
|
+
const trialParameters = new Float64Array(currentParameters.length);
|
|
91
|
+
for (let i = 0; i < currentParameters.length; i++) {
|
|
92
|
+
trialParameters[i] = currentParameters[i] + stepSize * searchDirection[i];
|
|
93
|
+
}
|
|
94
|
+
const trialCost = costFunction(trialParameters);
|
|
95
|
+
// Armijo condition: f(x + αd) <= f(x) + c * α * ∇f(x)^T * d
|
|
96
|
+
const armijoThreshold = currentCost + armijoParameter * stepSize * directionalDerivative;
|
|
97
|
+
if (trialCost <= armijoThreshold) {
|
|
98
|
+
return stepSize;
|
|
99
|
+
}
|
|
100
|
+
// Reduce step size and try again
|
|
101
|
+
stepSize *= contractionFactor;
|
|
102
|
+
}
|
|
103
|
+
// If we couldn't find a suitable step size, return a very small value
|
|
104
|
+
return stepSize;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=lineSearch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lineSearch.js","sourceRoot":"","sources":["../../src/core/lineSearch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file implements a user-friendly and trackable logging system for optimization algorithms.
|
|
3
|
+
*
|
|
4
|
+
* Role in system:
|
|
5
|
+
* - Provides structured logging with log levels (DEBUG, INFO, WARN, ERROR)
|
|
6
|
+
* - Formats logs with timestamps, emojis, and aligned indentation
|
|
7
|
+
* - Optimized for performance when logging is disabled
|
|
8
|
+
*
|
|
9
|
+
* For first-time readers:
|
|
10
|
+
* - Start with LogLevel enum and Logger class
|
|
11
|
+
* - Understand how logLevel and verbose options work together
|
|
12
|
+
* - Check formatLogMessage for formatting details
|
|
13
|
+
*/
|
|
14
|
+
export type LogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
|
|
15
|
+
/**
|
|
16
|
+
* Determines the effective log level from options.
|
|
17
|
+
* Handles backward compatibility with verbose option.
|
|
18
|
+
*
|
|
19
|
+
* Priority: logLevel > verbose
|
|
20
|
+
* - If logLevel is specified, use it
|
|
21
|
+
* - If verbose is true, treat as INFO level
|
|
22
|
+
* - Otherwise, logging is disabled (returns undefined)
|
|
23
|
+
*/
|
|
24
|
+
export declare function getEffectiveLogLevel(logLevel: LogLevel | undefined, verbose: boolean | undefined): LogLevel | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Checks if a log message should be displayed based on the effective log level.
|
|
27
|
+
*
|
|
28
|
+
* A message is displayed if its level priority is >= the effective log level priority.
|
|
29
|
+
* For example, if effective level is INFO, then INFO, WARN, and ERROR are shown, but DEBUG is not.
|
|
30
|
+
*/
|
|
31
|
+
export declare function shouldLog(messageLevel: LogLevel, effectiveLogLevel: LogLevel | undefined): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Logger class for optimization algorithms.
|
|
34
|
+
* Provides structured logging with log levels and formatted output.
|
|
35
|
+
*/
|
|
36
|
+
export declare class Logger {
|
|
37
|
+
private effectiveLogLevel;
|
|
38
|
+
constructor(logLevel: LogLevel | undefined, verbose: boolean | undefined);
|
|
39
|
+
/**
|
|
40
|
+
* Internal log method to handle common logging logic.
|
|
41
|
+
* Checks log level, formats message, and outputs to console.
|
|
42
|
+
*/
|
|
43
|
+
private log;
|
|
44
|
+
/**
|
|
45
|
+
* Logs a DEBUG level message.
|
|
46
|
+
* Used for detailed progress information (cost, gradient norm, step size, etc.).
|
|
47
|
+
*/
|
|
48
|
+
debug(algorithm: string, iteration: number | undefined, message: string, details?: Array<{
|
|
49
|
+
key: string;
|
|
50
|
+
value: number;
|
|
51
|
+
}>): void;
|
|
52
|
+
/**
|
|
53
|
+
* Logs an INFO level message.
|
|
54
|
+
* Used for convergence messages and important state changes.
|
|
55
|
+
*/
|
|
56
|
+
info(algorithm: string, iteration: number | undefined, message: string, details?: Array<{
|
|
57
|
+
key: string;
|
|
58
|
+
value: number;
|
|
59
|
+
}>): void;
|
|
60
|
+
/**
|
|
61
|
+
* Logs a WARN level message.
|
|
62
|
+
* Used for warnings (singular matrix, max iterations reached, line search failure, etc.).
|
|
63
|
+
*/
|
|
64
|
+
warn(algorithm: string, iteration: number | undefined, message: string, details?: Array<{
|
|
65
|
+
key: string;
|
|
66
|
+
value: number;
|
|
67
|
+
}>): void;
|
|
68
|
+
/**
|
|
69
|
+
* Logs an ERROR level message.
|
|
70
|
+
* Used for fatal errors (currently not used, reserved for future extensions).
|
|
71
|
+
*/
|
|
72
|
+
error(algorithm: string, iteration: number | undefined, message: string, details?: Array<{
|
|
73
|
+
key: string;
|
|
74
|
+
value: number;
|
|
75
|
+
}>): void;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAwB3D;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAC9B,OAAO,EAAE,OAAO,GAAG,SAAS,GAC3B,QAAQ,GAAG,SAAS,CAQtB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,YAAY,EAAE,QAAQ,EACtB,iBAAiB,EAAE,QAAQ,GAAG,SAAS,GACtC,OAAO,CAKT;AA2DD;;;GAGG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,iBAAiB,CAAuB;gBAEpC,QAAQ,EAAE,QAAQ,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS;IAIxE;;;OAGG;IACH,OAAO,CAAC,GAAG;IAmBX;;;OAGG;IACH,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,GAC9C,IAAI;IAIP;;;OAGG;IACH,IAAI,CACF,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,GAC9C,IAAI;IAIP;;;OAGG;IACH,IAAI,CACF,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,GAC9C,IAAI;IAIP;;;OAGG;IACH,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,GAC9C,IAAI;CAGR"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file implements a user-friendly and trackable logging system for optimization algorithms.
|
|
3
|
+
*
|
|
4
|
+
* Role in system:
|
|
5
|
+
* - Provides structured logging with log levels (DEBUG, INFO, WARN, ERROR)
|
|
6
|
+
* - Formats logs with timestamps, emojis, and aligned indentation
|
|
7
|
+
* - Optimized for performance when logging is disabled
|
|
8
|
+
*
|
|
9
|
+
* For first-time readers:
|
|
10
|
+
* - Start with LogLevel enum and Logger class
|
|
11
|
+
* - Understand how logLevel and verbose options work together
|
|
12
|
+
* - Check formatLogMessage for formatting details
|
|
13
|
+
*/
|
|
14
|
+
import { formatNumber } from '../utils/formatting.js';
|
|
15
|
+
/**
|
|
16
|
+
* Log level priority order (higher number = higher priority).
|
|
17
|
+
* Used to determine if a log message should be displayed.
|
|
18
|
+
*/
|
|
19
|
+
const LOG_LEVEL_PRIORITY = {
|
|
20
|
+
DEBUG: 0,
|
|
21
|
+
INFO: 1,
|
|
22
|
+
WARN: 2,
|
|
23
|
+
ERROR: 3
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Emoji symbols for each log level.
|
|
27
|
+
* Used to provide visual distinction while maintaining academic tone.
|
|
28
|
+
*/
|
|
29
|
+
const LOG_LEVEL_EMOJI = {
|
|
30
|
+
DEBUG: '🔍',
|
|
31
|
+
INFO: '✅',
|
|
32
|
+
WARN: '⚠️',
|
|
33
|
+
ERROR: '❌'
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Determines the effective log level from options.
|
|
37
|
+
* Handles backward compatibility with verbose option.
|
|
38
|
+
*
|
|
39
|
+
* Priority: logLevel > verbose
|
|
40
|
+
* - If logLevel is specified, use it
|
|
41
|
+
* - If verbose is true, treat as INFO level
|
|
42
|
+
* - Otherwise, logging is disabled (returns undefined)
|
|
43
|
+
*/
|
|
44
|
+
export function getEffectiveLogLevel(logLevel, verbose) {
|
|
45
|
+
if (logLevel !== undefined) {
|
|
46
|
+
return logLevel;
|
|
47
|
+
}
|
|
48
|
+
if (verbose === true) {
|
|
49
|
+
return 'INFO';
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Checks if a log message should be displayed based on the effective log level.
|
|
55
|
+
*
|
|
56
|
+
* A message is displayed if its level priority is >= the effective log level priority.
|
|
57
|
+
* For example, if effective level is INFO, then INFO, WARN, and ERROR are shown, but DEBUG is not.
|
|
58
|
+
*/
|
|
59
|
+
export function shouldLog(messageLevel, effectiveLogLevel) {
|
|
60
|
+
if (effectiveLogLevel === undefined) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return LOG_LEVEL_PRIORITY[messageLevel] >= LOG_LEVEL_PRIORITY[effectiveLogLevel];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Formats key-value pairs with aligned indentation.
|
|
67
|
+
* All labels are padded to the same width so values align vertically.
|
|
68
|
+
*
|
|
69
|
+
* Example:
|
|
70
|
+
* Cost: 1.234e-6
|
|
71
|
+
* Gradient norm: 9.876e-7
|
|
72
|
+
* Step size: 1.234e-8
|
|
73
|
+
*/
|
|
74
|
+
function formatKeyValuePairs(pairs) {
|
|
75
|
+
if (pairs.length === 0) {
|
|
76
|
+
return '';
|
|
77
|
+
}
|
|
78
|
+
// Find maximum label length to align values
|
|
79
|
+
const maxLabelLength = Math.max(...pairs.map(pair => pair.key.length));
|
|
80
|
+
// Format each pair with aligned labels
|
|
81
|
+
return pairs
|
|
82
|
+
.map(({ key, value }) => {
|
|
83
|
+
const paddedKey = key.padEnd(maxLabelLength);
|
|
84
|
+
const formattedValue = formatNumber(value);
|
|
85
|
+
return ` ${paddedKey} ${formattedValue}`;
|
|
86
|
+
})
|
|
87
|
+
.join('\n');
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Formats a log message with timestamp, level, algorithm, iteration, and details.
|
|
91
|
+
*
|
|
92
|
+
* Format: emoji [timestamp] [LEVEL] [algorithm] [iteration] message
|
|
93
|
+
*
|
|
94
|
+
* Emoji is placed at the beginning for better visual scanning.
|
|
95
|
+
* If details are provided as key-value pairs, they are formatted with aligned indentation.
|
|
96
|
+
*/
|
|
97
|
+
function formatLogMessage(level, algorithm, iteration, message, details) {
|
|
98
|
+
const timestamp = new Date().toISOString();
|
|
99
|
+
const emoji = LOG_LEVEL_EMOJI[level];
|
|
100
|
+
const levelLabel = `[${level}]`;
|
|
101
|
+
const iterationPart = iteration !== undefined ? `Iteration ${iteration}` : '';
|
|
102
|
+
const header = `${emoji} [${timestamp}] ${levelLabel} [${algorithm}]${iterationPart ? ` ${iterationPart}` : ''}: ${message}`;
|
|
103
|
+
if (details && details.length > 0) {
|
|
104
|
+
const detailsFormatted = formatKeyValuePairs(details);
|
|
105
|
+
return `${header}\n${detailsFormatted}`;
|
|
106
|
+
}
|
|
107
|
+
return header;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Logger class for optimization algorithms.
|
|
111
|
+
* Provides structured logging with log levels and formatted output.
|
|
112
|
+
*/
|
|
113
|
+
export class Logger {
|
|
114
|
+
constructor(logLevel, verbose) {
|
|
115
|
+
this.effectiveLogLevel = getEffectiveLogLevel(logLevel, verbose);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Internal log method to handle common logging logic.
|
|
119
|
+
* Checks log level, formats message, and outputs to console.
|
|
120
|
+
*/
|
|
121
|
+
log(level, algorithm, iteration, message, details) {
|
|
122
|
+
if (!shouldLog(level, this.effectiveLogLevel)) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const formatted = formatLogMessage(level, algorithm, iteration, message, details);
|
|
126
|
+
if (level === 'ERROR') {
|
|
127
|
+
console.error(formatted);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
console.log(formatted);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Logs a DEBUG level message.
|
|
135
|
+
* Used for detailed progress information (cost, gradient norm, step size, etc.).
|
|
136
|
+
*/
|
|
137
|
+
debug(algorithm, iteration, message, details) {
|
|
138
|
+
this.log('DEBUG', algorithm, iteration, message, details);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Logs an INFO level message.
|
|
142
|
+
* Used for convergence messages and important state changes.
|
|
143
|
+
*/
|
|
144
|
+
info(algorithm, iteration, message, details) {
|
|
145
|
+
this.log('INFO', algorithm, iteration, message, details);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Logs a WARN level message.
|
|
149
|
+
* Used for warnings (singular matrix, max iterations reached, line search failure, etc.).
|
|
150
|
+
*/
|
|
151
|
+
warn(algorithm, iteration, message, details) {
|
|
152
|
+
this.log('WARN', algorithm, iteration, message, details);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Logs an ERROR level message.
|
|
156
|
+
* Used for fatal errors (currently not used, reserved for future extensions).
|
|
157
|
+
*/
|
|
158
|
+
error(algorithm, iteration, message, details) {
|
|
159
|
+
this.log('ERROR', algorithm, iteration, message, details);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/core/logger.ts"],"names":[],"mappings":"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"}
|