@anonympins/fingerprint 0.7.0 → 0.7.2
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/CHANGELOG.md +29 -0
- package/README.md +1 -1
- package/composer.json +8 -1
- package/package.json +1 -1
- package/public/fingerprint-wordpress.zip +0 -0
- package/src/js/build-client.js +8 -10
- package/src/js/fingerprint.builder.js +37 -38
- package/src/js/fingerprint.client.js +1531 -1463
- package/src/js/fingerprint.client.obfuscated.js +1 -0
- package/src/js/fingerprint.js +190 -16
- package/src/js/fingerprint.utils.js +213 -213
- package/src/js/library.js +340 -376
- package/src/js/mongodb-store.js +1 -1
- package/src/js/optimization.worker.js +27 -27
- package/src/js/pow.solver.inline.js +154 -56
- package/src/js/pow.solver.js +180 -92
- package/src/js/pow.worker.js +48 -48
- package/src/js/redis-store.js +1 -1
- package/src/js/tests/fingerprint.client.init.test.js +146 -143
- package/src/js/tests/fingerprint.test.js +124 -10
- package/src/js/tests/ip-reputation.test.js +1 -0
- package/src/js/upow-model-task.js +14 -15
- package/src/php/AutoTuner.php +34 -34
- package/src/php/Challenge/ChallengeUtils.php +57 -11
- package/src/php/Config/SecurityProfiles.php +20 -0
- package/src/php/DirectFingerprint.php +190 -145
- package/src/php/FingerprintBuilder.php +29 -30
- package/src/php/FingerprintClient.php +147 -148
- package/src/php/FingerprintEngine.php +44 -17
- package/src/php/Ja3AnomalyDetector.php +33 -32
- package/src/php/Optimization/FunctionRegistry.php +7 -7
- package/src/php/Optimization/Optimization.php +24 -24
- package/src/php/Optimization/OptimizationOperators.php +26 -25
- package/src/php/Optimization/ProblemInitializers.php +52 -52
- package/src/php/ProblemManager.php +31 -34
- package/src/php/RequestContext.php +8 -1
- package/src/php/Store/IStore.php +7 -8
- package/src/php/Store/InMemoryStore.php +66 -66
- package/src/php/Store/MongoDbStore.php +5 -5
- package/src/php/Store/RedisStore.php +5 -5
- package/src/php/Store/StoreManager.php +35 -35
- package/src/php/Tests/ChallengeUtilsTest.php +453 -453
- package/src/php/Tests/DnsCircuitBreakerTest.php +105 -105
- package/src/php/Tests/FingerprintEngineTest.php +38 -0
- package/src/php/Tests/IpReputationTest.php +10 -0
- package/src/php/Tests/MaliciousPatternsTest.php +103 -103
- package/src/php/Tests/MetricsTest.php +97 -97
- package/src/php/Tests/ProblemManagerTest.php +376 -376
- package/src/php/Tests/QuicFingerprintTest.php +53 -53
- package/src/php/Tests/RequestUtilsTest.php +471 -471
- package/src/php/Tests/TLSClientHelloParserTest.php +177 -177
- package/src/php/Tests/config/ed25519_key.json +3 -3
- package/src/php/Utils/BlockList.php +99 -99
- package/src/php/Utils/Env.php +49 -49
- package/src/php/Utils/MaliciousPatterns.php +74 -74
- package/src/php/Utils/MetricsManager.php +209 -209
- package/src/php/Utils/RequestUtils.php +129 -7
- package/src/php/Utils/TLSClientHelloParser.php +369 -369
- package/src/php/WordPress/WpDbStore.php +155 -0
- package/src/php/WordPress/fingerprint-wordpress.php +554 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.mo +0 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.po +262 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.mo +0 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.po +268 -0
- package/src/php/WordPress/package.php +218 -0
- package/src/php/bin/auto-tune.php +118 -118
|
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
|
|
5
5
|
namespace Anonympins\Fingerprint\Optimization;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Registry to safely expose optimization library routines to task runners.
|
|
9
9
|
*/
|
|
10
10
|
class FunctionRegistry
|
|
11
11
|
{
|
|
@@ -13,17 +13,17 @@ class FunctionRegistry
|
|
|
13
13
|
private static array $functions = [];
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Initializes registry with built-in solvers and evaluators.
|
|
17
17
|
*/
|
|
18
18
|
private static function initialize(): void
|
|
19
19
|
{
|
|
20
20
|
if (empty(self::$functions)) {
|
|
21
|
-
//
|
|
21
|
+
// Evaluators & Scoring Adapters
|
|
22
22
|
self::$functions['tsp.calculateEnergy'] = [OptimizationUtils::class, 'evaluatePathDistance'];
|
|
23
23
|
self::$functions['portfolio.calculateMetrics'] = [OptimizationOperators::class, 'calculatePortfolioMetrics'];
|
|
24
24
|
self::$functions['facility.calculateEnergy'] = [OptimizationOperators::class, 'evaluateFacilityLocation'];
|
|
25
25
|
|
|
26
|
-
//
|
|
26
|
+
// Full Optimization Solvers
|
|
27
27
|
self::$functions['tsp.solve'] = [OptimizationOperators::class, 'solveTSP'];
|
|
28
28
|
self::$functions['portfolio.solve'] = [OptimizationOperators::class, 'solvePortfolio'];
|
|
29
29
|
self::$functions['fraud.solve'] = [OptimizationOperators::class, 'solveFraudDetection'];
|
|
@@ -33,7 +33,7 @@ class FunctionRegistry
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* Retrieves a function from the registry.
|
|
37
37
|
*/
|
|
38
38
|
public static function get(string $name): ?callable
|
|
39
39
|
{
|
|
@@ -41,7 +41,7 @@ class FunctionRegistry
|
|
|
41
41
|
return self::$functions[$name] ?? null;
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
44
|
+
* Registers a custom function. Primarily intended for testing.
|
|
45
45
|
* @internal
|
|
46
46
|
* @param string $name
|
|
47
47
|
* @param callable $function
|
|
@@ -54,7 +54,7 @@ class FunctionRegistry
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
*
|
|
57
|
+
* Resets function registry. Intended for testing.
|
|
58
58
|
* @internal
|
|
59
59
|
*/
|
|
60
60
|
public static function __internal_resetRegistry(): void
|
|
@@ -5,12 +5,12 @@ declare(strict_types=1);
|
|
|
5
5
|
namespace Anonympins\Fingerprint\Optimization;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Optimization algorithms library.
|
|
9
9
|
*/
|
|
10
10
|
class Optimization
|
|
11
11
|
{
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Generates a cryptographically secure random float in [0, 1).
|
|
14
14
|
*/
|
|
15
15
|
private static function secureRandom(): float
|
|
16
16
|
{
|
|
@@ -22,12 +22,12 @@ class Optimization
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
*
|
|
25
|
+
* Multi-objective genetic algorithm (inspired by NSGA-II).
|
|
26
26
|
* @param callable $createIndividual
|
|
27
27
|
* @param callable $fitnessFunction
|
|
28
28
|
* @param callable $crossover
|
|
29
29
|
* @param callable $mutate
|
|
30
|
-
* @param array|null $currentConfig
|
|
30
|
+
* @param array|null $currentConfig Reference baseline configuration.
|
|
31
31
|
* @param array $options
|
|
32
32
|
* @return array<int, array{solution: mixed, objectives: array<float>}>
|
|
33
33
|
*/
|
|
@@ -35,8 +35,8 @@ class Optimization
|
|
|
35
35
|
callable $createIndividual,
|
|
36
36
|
callable $fitnessFunction,
|
|
37
37
|
callable $crossover,
|
|
38
|
-
callable $mutate, //
|
|
39
|
-
?array $currentConfig = null, //
|
|
38
|
+
callable $mutate, // The mutate function must accept $currentConfig
|
|
39
|
+
?array $currentConfig = null, // Reference baseline configuration
|
|
40
40
|
array $options = []
|
|
41
41
|
): array {
|
|
42
42
|
$generations = $options['generations'] ?? 150;
|
|
@@ -53,14 +53,14 @@ class Optimization
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
for ($gen = 0; $gen < $generations; $gen++) {
|
|
56
|
-
// 1.
|
|
56
|
+
// 1. Generate offspring population
|
|
57
57
|
$offspring = [];
|
|
58
58
|
for ($i = 0; $i < $populationSize; $i++) {
|
|
59
59
|
$parent1 = $population[random_int(0, count($population) - 1)];
|
|
60
60
|
$parent2 = $population[random_int(0, count($population) - 1)];
|
|
61
61
|
$childIndividual = $crossover($parent1['individual'], $parent2['individual']);
|
|
62
62
|
if (self::secureRandom() < $mutationRate) {
|
|
63
|
-
$childIndividual = $mutate($childIndividual, $currentConfig);
|
|
63
|
+
$childIndividual = $mutate($childIndividual, $currentConfig);
|
|
64
64
|
}
|
|
65
65
|
$offspring[] = [
|
|
66
66
|
'individual' => $childIndividual,
|
|
@@ -68,20 +68,20 @@ class Optimization
|
|
|
68
68
|
];
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// 2.
|
|
71
|
+
// 2. Combine parent and offspring populations
|
|
72
72
|
$combinedPopulation = array_merge($population, $offspring);
|
|
73
73
|
|
|
74
|
-
// 3.
|
|
74
|
+
// 3. Sort into non-dominated Pareto fronts
|
|
75
75
|
$fronts = self::nonDominatedSort($combinedPopulation);
|
|
76
76
|
|
|
77
|
-
// 4.
|
|
77
|
+
// 4. Build next generation
|
|
78
78
|
$newPopulation = [];
|
|
79
79
|
foreach ($fronts as $front) {
|
|
80
80
|
if (count($newPopulation) + count($front) <= $populationSize) {
|
|
81
81
|
$newPopulation = array_merge($newPopulation, $front);
|
|
82
82
|
} else {
|
|
83
83
|
self::calculateCrowdingDistance($front);
|
|
84
|
-
//
|
|
84
|
+
// Sort by crowding distance descending
|
|
85
85
|
usort($front, fn ($a, $b) => $b['crowdingDistance'] <=> $a['crowdingDistance']);
|
|
86
86
|
$remaining = $populationSize - count($newPopulation);
|
|
87
87
|
$newPopulation = array_merge($newPopulation, array_slice($front, 0, $remaining));
|
|
@@ -91,11 +91,11 @@ class Optimization
|
|
|
91
91
|
$population = $newPopulation;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
//
|
|
94
|
+
// Return the first non-dominated front of the final population
|
|
95
95
|
$finalFronts = self::nonDominatedSort($population);
|
|
96
96
|
$bestFront = $finalFronts[0] ?? [];
|
|
97
97
|
|
|
98
|
-
//
|
|
98
|
+
// Deduplicate solutions with identical objective scores
|
|
99
99
|
$uniqueSolutionsMap = [];
|
|
100
100
|
foreach ($bestFront as $p) {
|
|
101
101
|
$key = json_encode($p['objectives']);
|
|
@@ -110,7 +110,7 @@ class Optimization
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
|
-
*
|
|
113
|
+
* Determines whether solution A Pareto-dominates solution B (minimization).
|
|
114
114
|
* @param array<float> $objectivesA
|
|
115
115
|
* @param array<float> $objectivesB
|
|
116
116
|
*/
|
|
@@ -119,17 +119,17 @@ class Optimization
|
|
|
119
119
|
$aIsBetterInOne = false;
|
|
120
120
|
for ($i = 0; $i < count($objectivesA); $i++) {
|
|
121
121
|
if ($objectivesA[$i] > $objectivesB[$i]) {
|
|
122
|
-
return false; // A
|
|
122
|
+
return false; // A is worse on at least one objective
|
|
123
123
|
}
|
|
124
124
|
if ($objectivesA[$i] < $objectivesB[$i]) {
|
|
125
|
-
$aIsBetterInOne = true; // A
|
|
125
|
+
$aIsBetterInOne = true; // A is strictly better on at least one objective
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
return $aIsBetterInOne;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
|
-
*
|
|
132
|
+
* Sorts population into non-dominated Pareto fronts (NSGA-II).
|
|
133
133
|
* @param array<int, array> &$populationWithObjectives
|
|
134
134
|
* @return array<int, array>
|
|
135
135
|
*/
|
|
@@ -182,7 +182,7 @@ class Optimization
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
/**
|
|
185
|
-
*
|
|
185
|
+
* Computes crowding distance for a front to preserve diversity.
|
|
186
186
|
* @param array<int, array> &$front
|
|
187
187
|
*/
|
|
188
188
|
private static function calculateCrowdingDistance(array &$front): void
|
|
@@ -197,13 +197,13 @@ class Optimization
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
for ($i = 0; $i < $numObjectives; $i++) {
|
|
200
|
-
//
|
|
200
|
+
// Sort front by current objective
|
|
201
201
|
usort($front, fn ($a, $b) => $a['objectives'][$i] <=> $b['objectives'][$i]);
|
|
202
202
|
|
|
203
203
|
$minObj = $front[0]['objectives'][$i];
|
|
204
204
|
$maxObj = $front[$l - 1]['objectives'][$i];
|
|
205
205
|
|
|
206
|
-
//
|
|
206
|
+
// Boundary solutions receive infinite distance to encourage spread
|
|
207
207
|
$front[0]['crowdingDistance'] = INF;
|
|
208
208
|
$front[$l - 1]['crowdingDistance'] = INF;
|
|
209
209
|
|
|
@@ -218,11 +218,11 @@ class Optimization
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
/**
|
|
221
|
-
*
|
|
222
|
-
*
|
|
221
|
+
* Calculates deviation from Benford's Law distribution.
|
|
222
|
+
* Elevated values indicate synthetic or automated intervals.
|
|
223
223
|
* @param array<int|float> $numbers
|
|
224
224
|
*/
|
|
225
|
-
public static function benfordTest(array $numbers): float //
|
|
225
|
+
public static function benfordTest(array $numbers): float // Public static helper for digit distribution test
|
|
226
226
|
{
|
|
227
227
|
$counts = array_fill(1, 9, 0);
|
|
228
228
|
$validCount = 0;
|
|
@@ -5,14 +5,14 @@ declare(strict_types=1);
|
|
|
5
5
|
namespace Anonympins\Fingerprint\Optimization;
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Operators and objective function factories for optimization problems.
|
|
9
9
|
*/
|
|
10
10
|
class OptimizationOperators
|
|
11
11
|
{
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
* @param array $options
|
|
15
|
-
* @return callable
|
|
13
|
+
* Creates a tournament selection operator for genetic algorithms.
|
|
14
|
+
* @param array $options Tournament configuration options.
|
|
15
|
+
* @return callable Selection operator function.
|
|
16
16
|
*/
|
|
17
17
|
public static function createTournamentSelection(array $options = []): callable
|
|
18
18
|
{
|
|
@@ -37,7 +37,7 @@ class OptimizationOperators
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
*
|
|
40
|
+
* Generates a cryptographically secure random float in [0, 1).
|
|
41
41
|
*/
|
|
42
42
|
private static function secureRandom(): float
|
|
43
43
|
{
|
|
@@ -49,7 +49,7 @@ class OptimizationOperators
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
*
|
|
52
|
+
* Evaluates a portfolio for a given payload.
|
|
53
53
|
*
|
|
54
54
|
* @param array $weights
|
|
55
55
|
* @param array $payload
|
|
@@ -62,22 +62,21 @@ class OptimizationOperators
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
65
|
+
* Creates a portfolio allocation evaluator.
|
|
66
66
|
* @param array $config
|
|
67
67
|
* @return callable
|
|
68
68
|
*/
|
|
69
69
|
public static function createPortfolioAllocator(array $config): callable
|
|
70
70
|
{
|
|
71
|
-
//
|
|
72
|
-
// une logique de calcul de rendement et de volatilité de portefeuille.
|
|
71
|
+
// Baseline portfolio evaluator minimizing negative expected return
|
|
73
72
|
return function (array $weights) use ($config): float {
|
|
74
|
-
//
|
|
73
|
+
// Minimize negative return (maximizes positive return)
|
|
75
74
|
return -array_sum($weights);
|
|
76
75
|
};
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
/**
|
|
80
|
-
*
|
|
79
|
+
* Creates an evaluator for full security configuration auto-tuning.
|
|
81
80
|
* @param array $context
|
|
82
81
|
* @return callable
|
|
83
82
|
*/
|
|
@@ -145,6 +144,7 @@ class OptimizationOperators
|
|
|
145
144
|
];
|
|
146
145
|
|
|
147
146
|
// 1. Évaluation sur les logs de trafic réels
|
|
147
|
+
// 1. Evaluate on real traffic logs
|
|
148
148
|
foreach ($trafficData as $log) {
|
|
149
149
|
$weight = (float)($log['weight'] ?? 1.0);
|
|
150
150
|
$confidence = ($confidenceWeights[$log['type'] ?? ''] ?? 1.0) * $weight;
|
|
@@ -206,6 +206,7 @@ class OptimizationOperators
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
// 3. Pénalité de dérive d'échelle (L2 Regularization par rapport au profil d'origine)
|
|
209
|
+
// 3. Scale drift penalty (L2 regularization against baseline profile)
|
|
209
210
|
$regularizationPenalty = 0.0;
|
|
210
211
|
if ($currentConfig && isset($currentConfig['weights'])) {
|
|
211
212
|
foreach ($config['weights'] as $key => $val) {
|
|
@@ -215,6 +216,7 @@ class OptimizationOperators
|
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
// 4. Maximisation de la marge
|
|
219
|
+
// 4. Margin separation maximization
|
|
218
220
|
$marginOverlap = max(0.0, $maxHumanScore - $minBotScore);
|
|
219
221
|
$marginPenalty = $marginOverlap / 100.0;
|
|
220
222
|
|
|
@@ -226,7 +228,7 @@ class OptimizationOperators
|
|
|
226
228
|
}
|
|
227
229
|
|
|
228
230
|
/**
|
|
229
|
-
*
|
|
231
|
+
* Solves end-to-end security configuration auto-tuning.
|
|
230
232
|
* @param array $context
|
|
231
233
|
* @param array $options
|
|
232
234
|
* @return array
|
|
@@ -256,7 +258,7 @@ class OptimizationOperators
|
|
|
256
258
|
if (isset($config[$section]) && is_array($config[$section])) {
|
|
257
259
|
foreach ($config[$section] as $k => $v) {
|
|
258
260
|
if (is_numeric($v)) {
|
|
259
|
-
$randomVariation = 1.0 + (self::secureRandom() - 0.5) * 0.5; //
|
|
261
|
+
$randomVariation = 1.0 + (self::secureRandom() - 0.5) * 0.5; // +/- 25% variation
|
|
260
262
|
$ind[$section][$k] = $v * $randomVariation;
|
|
261
263
|
} else {
|
|
262
264
|
$ind[$section][$k] = $v;
|
|
@@ -330,7 +332,7 @@ class OptimizationOperators
|
|
|
330
332
|
}
|
|
331
333
|
|
|
332
334
|
/**
|
|
333
|
-
*
|
|
335
|
+
* Creates an evaluator to find optimal fraud detection thresholds.
|
|
334
336
|
* @param array $context
|
|
335
337
|
* @return callable
|
|
336
338
|
*/
|
|
@@ -374,7 +376,7 @@ class OptimizationOperators
|
|
|
374
376
|
}
|
|
375
377
|
|
|
376
378
|
/**
|
|
377
|
-
*
|
|
379
|
+
* Solves fraud detection threshold optimization.
|
|
378
380
|
* @param array $context
|
|
379
381
|
* @param array $options
|
|
380
382
|
* @return array
|
|
@@ -411,19 +413,18 @@ class OptimizationOperators
|
|
|
411
413
|
}
|
|
412
414
|
|
|
413
415
|
/**
|
|
414
|
-
*
|
|
416
|
+
* TSP solver baseline implementation.
|
|
415
417
|
* @param array $cities
|
|
416
418
|
* @param array $options
|
|
417
419
|
* @return array
|
|
418
420
|
*/
|
|
419
421
|
public static function solveTSP(array $cities, array $options = []): array
|
|
420
422
|
{
|
|
421
|
-
// Implémentation factice pour la complétude
|
|
422
423
|
return ['solution' => array_keys($cities), 'energy' => 100];
|
|
423
424
|
}
|
|
424
425
|
|
|
425
426
|
/**
|
|
426
|
-
*
|
|
427
|
+
* Portfolio allocator baseline implementation.
|
|
427
428
|
* @param array $assets
|
|
428
429
|
* @param float $maxVolatility
|
|
429
430
|
* @param array $options
|
|
@@ -431,7 +432,6 @@ class OptimizationOperators
|
|
|
431
432
|
*/
|
|
432
433
|
public static function solvePortfolio(array $assets, float $maxVolatility, array $options = []): array
|
|
433
434
|
{
|
|
434
|
-
// Implémentation factice pour la complétude
|
|
435
435
|
return ['solution' => array_fill(0, count($assets), 1 / count($assets)), 'fitness' => -0.1];
|
|
436
436
|
}
|
|
437
437
|
|
|
@@ -440,7 +440,7 @@ class OptimizationOperators
|
|
|
440
440
|
$fixedCostPerFacility = $options['fixedCostPerFacility'] ?? 0;
|
|
441
441
|
$initialTemperature = $options['initialTemperature'] ?? 100000.0;
|
|
442
442
|
$coolingRate = $options['coolingRate'] ?? 0.999;
|
|
443
|
-
$maxIterations = $options['maxIterations'] ?? 15000;
|
|
443
|
+
$maxIterations = $options['maxIterations'] ?? 15000;
|
|
444
444
|
|
|
445
445
|
$evaluator = function (array $facilities) use ($customers, $fixedCostPerFacility): float {
|
|
446
446
|
$totalConnectionCost = 0.0;
|
|
@@ -473,6 +473,7 @@ class OptimizationOperators
|
|
|
473
473
|
};
|
|
474
474
|
|
|
475
475
|
// Génération d'une solution initiale aléatoire
|
|
476
|
+
// Random initial placement
|
|
476
477
|
$currentSolution = [];
|
|
477
478
|
for ($i = 0; $i < $numFacilities; $i++) {
|
|
478
479
|
$currentSolution[] = [
|
|
@@ -509,12 +510,12 @@ class OptimizationOperators
|
|
|
509
510
|
}
|
|
510
511
|
|
|
511
512
|
/**
|
|
512
|
-
*
|
|
513
|
-
*
|
|
513
|
+
* Independently evaluates total cost of a facility placement proposal.
|
|
514
|
+
* Invoked server-side to verify client-submitted solutions.
|
|
514
515
|
*
|
|
515
|
-
* @param array $facilities
|
|
516
|
-
* @param array $payload
|
|
517
|
-
* @return float
|
|
516
|
+
* @param array $facilities Facility coordinates proposed by client.
|
|
517
|
+
* @param array $payload Base payload containing customer coordinates and fixed costs.
|
|
518
|
+
* @return float Verified total connection and maintenance cost.
|
|
518
519
|
*/
|
|
519
520
|
public static function evaluateFacilityLocation(array $facilities, array $payload): float
|
|
520
521
|
{
|
|
@@ -1,53 +1,53 @@
|
|
|
1
|
-
<?php
|
|
2
|
-
|
|
3
|
-
declare(strict_types=1);
|
|
4
|
-
|
|
5
|
-
namespace Anonympins\Fingerprint\Optimization;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
*
|
|
9
|
-
*/
|
|
10
|
-
class ProblemInitializers
|
|
11
|
-
{
|
|
12
|
-
/** @var array<string, callable> */
|
|
13
|
-
private static array $initializers = [];
|
|
14
|
-
|
|
15
|
-
private static function initialize(): void
|
|
16
|
-
{
|
|
17
|
-
if (empty(self::$initializers)) {
|
|
18
|
-
self::$initializers['generate:randomPoints'] = function (array $params): array {
|
|
19
|
-
$count = $params['count'] ?? 0;
|
|
20
|
-
$bounds = $params['bounds'] ?? ['x' => 1000, 'y' => 1000];
|
|
21
|
-
if (!is_numeric($count)) return [];
|
|
22
|
-
$points = [];
|
|
23
|
-
for ($i = 0; $i < $count; $i++) {
|
|
24
|
-
$points[] = [
|
|
25
|
-
'x' => mt_rand() / mt_getrandmax() * $bounds['x'],
|
|
26
|
-
'y' => mt_rand() / mt_getrandmax() * $bounds['y']
|
|
27
|
-
];
|
|
28
|
-
}
|
|
29
|
-
return $points;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
self::$initializers['generate:randomAssets'] = function (array $params): array {
|
|
33
|
-
$count = $params['count'] ?? 0;
|
|
34
|
-
if (!is_numeric($count)) return [];
|
|
35
|
-
$assets = [];
|
|
36
|
-
for ($i = 0; $i < $count; $i++) {
|
|
37
|
-
$assets[] = [
|
|
38
|
-
'name' => 'Asset ' . ($i + 1),
|
|
39
|
-
'expectedReturn' => mt_rand() / mt_getrandmax() * 0.2,
|
|
40
|
-
'volatility' => 0.1 + mt_rand() / mt_getrandmax() * 0.3
|
|
41
|
-
];
|
|
42
|
-
}
|
|
43
|
-
return $assets;
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
public static function get(string $name): ?callable
|
|
49
|
-
{
|
|
50
|
-
self::initialize();
|
|
51
|
-
return self::$initializers[$name] ?? null;
|
|
52
|
-
}
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
declare(strict_types=1);
|
|
4
|
+
|
|
5
|
+
namespace Anonympins\Fingerprint\Optimization;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generators for dynamically seeding problem instance datasets.
|
|
9
|
+
*/
|
|
10
|
+
class ProblemInitializers
|
|
11
|
+
{
|
|
12
|
+
/** @var array<string, callable> */
|
|
13
|
+
private static array $initializers = [];
|
|
14
|
+
|
|
15
|
+
private static function initialize(): void
|
|
16
|
+
{
|
|
17
|
+
if (empty(self::$initializers)) {
|
|
18
|
+
self::$initializers['generate:randomPoints'] = function (array $params): array {
|
|
19
|
+
$count = $params['count'] ?? 0;
|
|
20
|
+
$bounds = $params['bounds'] ?? ['x' => 1000, 'y' => 1000];
|
|
21
|
+
if (!is_numeric($count)) return [];
|
|
22
|
+
$points = [];
|
|
23
|
+
for ($i = 0; $i < $count; $i++) {
|
|
24
|
+
$points[] = [
|
|
25
|
+
'x' => mt_rand() / mt_getrandmax() * $bounds['x'],
|
|
26
|
+
'y' => mt_rand() / mt_getrandmax() * $bounds['y']
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
return $points;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
self::$initializers['generate:randomAssets'] = function (array $params): array {
|
|
33
|
+
$count = $params['count'] ?? 0;
|
|
34
|
+
if (!is_numeric($count)) return [];
|
|
35
|
+
$assets = [];
|
|
36
|
+
for ($i = 0; $i < $count; $i++) {
|
|
37
|
+
$assets[] = [
|
|
38
|
+
'name' => 'Asset ' . ($i + 1),
|
|
39
|
+
'expectedReturn' => mt_rand() / mt_getrandmax() * 0.2,
|
|
40
|
+
'volatility' => 0.1 + mt_rand() / mt_getrandmax() * 0.3
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
return $assets;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public static function get(string $name): ?callable
|
|
49
|
+
{
|
|
50
|
+
self::initialize();
|
|
51
|
+
return self::$initializers[$name] ?? null;
|
|
52
|
+
}
|
|
53
53
|
}
|