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.
Files changed (80) hide show
  1. package/CODING_RULES.md +161 -0
  2. package/LICENSE +22 -0
  3. package/README.md +807 -0
  4. package/dist/core/adjointGradientDescent.d.ts +61 -0
  5. package/dist/core/adjointGradientDescent.d.ts.map +1 -0
  6. package/dist/core/adjointGradientDescent.js +764 -0
  7. package/dist/core/adjointGradientDescent.js.map +1 -0
  8. package/dist/core/constrainedGaussNewton.d.ts +44 -0
  9. package/dist/core/constrainedGaussNewton.d.ts.map +1 -0
  10. package/dist/core/constrainedGaussNewton.js +314 -0
  11. package/dist/core/constrainedGaussNewton.js.map +1 -0
  12. package/dist/core/constrainedLevenbergMarquardt.d.ts +46 -0
  13. package/dist/core/constrainedLevenbergMarquardt.d.ts.map +1 -0
  14. package/dist/core/constrainedLevenbergMarquardt.js +469 -0
  15. package/dist/core/constrainedLevenbergMarquardt.js.map +1 -0
  16. package/dist/core/constrainedUtils.d.ts +92 -0
  17. package/dist/core/constrainedUtils.d.ts.map +1 -0
  18. package/dist/core/constrainedUtils.js +364 -0
  19. package/dist/core/constrainedUtils.js.map +1 -0
  20. package/dist/core/convergence.d.ts +35 -0
  21. package/dist/core/convergence.d.ts.map +1 -0
  22. package/dist/core/convergence.js +51 -0
  23. package/dist/core/convergence.js.map +1 -0
  24. package/dist/core/createGradientFunction.d.ts +85 -0
  25. package/dist/core/createGradientFunction.d.ts.map +1 -0
  26. package/dist/core/createGradientFunction.js +93 -0
  27. package/dist/core/createGradientFunction.js.map +1 -0
  28. package/dist/core/effectiveJacobian.d.ts +90 -0
  29. package/dist/core/effectiveJacobian.d.ts.map +1 -0
  30. package/dist/core/effectiveJacobian.js +128 -0
  31. package/dist/core/effectiveJacobian.js.map +1 -0
  32. package/dist/core/finiteDiff.d.ts +171 -0
  33. package/dist/core/finiteDiff.d.ts.map +1 -0
  34. package/dist/core/finiteDiff.js +363 -0
  35. package/dist/core/finiteDiff.js.map +1 -0
  36. package/dist/core/gaussNewton.d.ts +29 -0
  37. package/dist/core/gaussNewton.d.ts.map +1 -0
  38. package/dist/core/gaussNewton.js +151 -0
  39. package/dist/core/gaussNewton.js.map +1 -0
  40. package/dist/core/gradientDescent.d.ts +35 -0
  41. package/dist/core/gradientDescent.d.ts.map +1 -0
  42. package/dist/core/gradientDescent.js +204 -0
  43. package/dist/core/gradientDescent.js.map +1 -0
  44. package/dist/core/jacobianComputation.d.ts +24 -0
  45. package/dist/core/jacobianComputation.d.ts.map +1 -0
  46. package/dist/core/jacobianComputation.js +38 -0
  47. package/dist/core/jacobianComputation.js.map +1 -0
  48. package/dist/core/levenbergMarquardt.d.ts +36 -0
  49. package/dist/core/levenbergMarquardt.d.ts.map +1 -0
  50. package/dist/core/levenbergMarquardt.js +286 -0
  51. package/dist/core/levenbergMarquardt.js.map +1 -0
  52. package/dist/core/lineSearch.d.ts +42 -0
  53. package/dist/core/lineSearch.d.ts.map +1 -0
  54. package/dist/core/lineSearch.js +106 -0
  55. package/dist/core/lineSearch.js.map +1 -0
  56. package/dist/core/logger.d.ts +77 -0
  57. package/dist/core/logger.d.ts.map +1 -0
  58. package/dist/core/logger.js +162 -0
  59. package/dist/core/logger.js.map +1 -0
  60. package/dist/core/types.d.ts +427 -0
  61. package/dist/core/types.d.ts.map +1 -0
  62. package/dist/core/types.js +15 -0
  63. package/dist/core/types.js.map +1 -0
  64. package/dist/index.d.ts +26 -0
  65. package/dist/index.d.ts.map +1 -0
  66. package/dist/index.js +29 -0
  67. package/dist/index.js.map +1 -0
  68. package/dist/utils/formatting.d.ts +27 -0
  69. package/dist/utils/formatting.d.ts.map +1 -0
  70. package/dist/utils/formatting.js +54 -0
  71. package/dist/utils/formatting.js.map +1 -0
  72. package/dist/utils/matrix.d.ts +63 -0
  73. package/dist/utils/matrix.d.ts.map +1 -0
  74. package/dist/utils/matrix.js +129 -0
  75. package/dist/utils/matrix.js.map +1 -0
  76. package/dist/utils/resultFormatter.d.ts +122 -0
  77. package/dist/utils/resultFormatter.d.ts.map +1 -0
  78. package/dist/utils/resultFormatter.js +342 -0
  79. package/dist/utils/resultFormatter.js.map +1 -0
  80. 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":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAItD;;;GAGG;AACH,MAAM,kBAAkB,GAA6B;IACnD,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACT,CAAC;AAEF;;;GAGG;AACH,MAAM,eAAe,GAA6B;IAChD,KAAK,EAAE,IAAI;IACX,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,GAAG;CACX,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAA8B,EAC9B,OAA4B;IAE5B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CACvB,YAAsB,EACtB,iBAAuC;IAEvC,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,kBAAkB,CAAC,YAAY,CAAC,IAAI,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;AACnF,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,mBAAmB,CAAC,KAA4C;IACvE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,4CAA4C;IAC5C,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAEvE,uCAAuC;IACvC,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE;QACtB,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;QAC7C,MAAM,cAAc,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAC3C,OAAO,KAAK,SAAS,KAAK,cAAc,EAAE,CAAC;IAC7C,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,gBAAgB,CACvB,KAAe,EACf,SAAiB,EACjB,SAA6B,EAC7B,OAAe,EACf,OAA+C;IAE/C,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,UAAU,GAAG,IAAI,KAAK,GAAG,CAAC;IAEhC,MAAM,aAAa,GAAG,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,MAAM,MAAM,GAAG,GAAG,KAAK,KAAK,SAAS,KAAK,UAAU,KAAK,SAAS,IAAI,aAAa,CAAC,CAAC,CAAC,IAAI,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,EAAE,CAAC;IAE7H,IAAI,OAAO,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,gBAAgB,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACtD,OAAO,GAAG,MAAM,KAAK,gBAAgB,EAAE,CAAC;IAC1C,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,OAAO,MAAM;IAGjB,YAAY,QAA8B,EAAE,OAA4B;QACtE,IAAI,CAAC,iBAAiB,GAAG,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnE,CAAC;IAED;;;OAGG;IACK,GAAG,CACT,KAAe,EACf,SAAiB,EACjB,SAA6B,EAC7B,OAAe,EACf,OAA+C;QAE/C,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC9C,OAAO;QACT,CAAC;QACD,MAAM,SAAS,GAAG,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAElF,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CACH,SAAiB,EACjB,SAA6B,EAC7B,OAAe,EACf,OAA+C;QAE/C,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;IAED;;;OAGG;IACH,IAAI,CACF,SAAiB,EACjB,SAA6B,EAC7B,OAAe,EACf,OAA+C;QAE/C,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC;IAED;;;OAGG;IACH,IAAI,CACF,SAAiB,EACjB,SAA6B,EAC7B,OAAe,EACf,OAA+C;QAE/C,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3D,CAAC;IAED;;;OAGG;IACH,KAAK,CACH,SAAiB,EACjB,SAA6B,EAC7B,OAAe,EACf,OAA+C;QAE/C,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC;CACF"}