@softsky/utils 2.7.0 → 2.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/README.md CHANGED
@@ -84,6 +84,9 @@ Only deletes last encountered.
84
84
 
85
85
  Returns index of deleted value.
86
86
 
87
+ ---
88
+ __function__ `reverse` - Reverse part of array
89
+
87
90
  ---
88
91
 
89
92
 
@@ -201,6 +204,12 @@ semaphore.run(()=>{
201
204
  ---
202
205
  __async function__ `withTimeout` - Add timeout to a promise
203
206
 
207
+ ---
208
+ __function__ `promisify` - Promisify a function with callback
209
+
210
+ ---
211
+ __function__ `promisifyEventSource` - Create a promise out of EventSource
212
+
204
213
  ---
205
214
 
206
215
 
@@ -295,14 +304,16 @@ You can use `unfoldPathfindingResult()` to get array of nodes.
295
304
  __function__ `knapsack` - Knapsack find best way to get maximum value in limited capacity
296
305
 
297
306
  ---
298
- __function__ `tspHeldKarp` - Find min path between points. You need to supply 2-dim array
307
+ __function__ `hamiltonianCycle` - Find min path between points. You need to supply 2-dim array
299
308
  where first index is a point and second index is a distance from this point to another.
300
309
  Put infinity if where are no path. Returns cycle (start and end at the same point)
301
310
  Original: https://github.com/qntm/held-karp
302
311
 
303
312
  ---
304
- __function__ `tspHeldKarpPath` - Look for description of `tspHeldKarp`.
305
- Returns path without cycle
313
+ __function__ `traverseByNearestNeighbor` - Traverse all points by nearest neighbor. Should be able to go from any point to any other point.
314
+
315
+ ---
316
+ __function__ `twoOpt` - 2-opt improvement
306
317
 
307
318
  ---
308
319
 
package/dist/arrays.d.ts CHANGED
@@ -48,3 +48,5 @@ export declare function removeFromArray<T>(array: T[], value: T): number;
48
48
  * Returns index of deleted value.
49
49
  */
50
50
  export declare function removeLastFromArray<T>(array: T[], value: T): number;
51
+ /** Reverse part of array */
52
+ export declare function reverse<T>(array: T[], start: number, end: number): T[];
package/dist/arrays.js CHANGED
@@ -133,3 +133,14 @@ export function removeLastFromArray(array, value) {
133
133
  array.splice(index, 1);
134
134
  return index;
135
135
  }
136
+ /** Reverse part of array */
137
+ export function reverse(array, start, end) {
138
+ array = [...array];
139
+ const n = ((end - start + 1) / 2) | 0;
140
+ for (let index = 0; index < n; index++) {
141
+ const temporary = array[start + index];
142
+ array[start + index] = array[end - index];
143
+ array[end - index] = temporary;
144
+ }
145
+ return array;
146
+ }
package/dist/control.d.ts CHANGED
@@ -123,4 +123,8 @@ export declare class Semaphore {
123
123
  }
124
124
  /** Add timeout to a promise */
125
125
  export declare function withTimeout<T>(run: () => Promise<T>, ms: number): Promise<T>;
126
+ /** Promisify a function with callback */
127
+ export declare function promisify<A extends any[], R extends any[]>(handler: (...handlerArguments: [...A, (...results: R) => void]) => void): (...handlerArguments: A) => Promise<R extends [infer U] ? U : R>;
128
+ /** Create a promise out of EventSource */
129
+ export declare function promisifyEventSource<T = unknown>(target: EventSource, resolveEvents: string[], rejectEvents?: string[]): Promise<T>;
126
130
  export {};
package/dist/control.js CHANGED
@@ -288,3 +288,21 @@ export class Semaphore {
288
288
  export async function withTimeout(run, ms) {
289
289
  return Promise.race([run(), timeout(ms)]);
290
290
  }
291
+ /** Promisify a function with callback */
292
+ export function promisify(handler) {
293
+ return (...handlerArguments) => new Promise((resolve) => {
294
+ handler(...handlerArguments, (...results) => {
295
+ resolve(results.length > 1 ? results : results[0]);
296
+ });
297
+ });
298
+ }
299
+ /** Create a promise out of EventSource */
300
+ export function promisifyEventSource(target, resolveEvents, rejectEvents = ['error']) {
301
+ return new Promise((resolve, reject) => {
302
+ for (let index = 0; index < resolveEvents.length; index++)
303
+ // @ts-ignore
304
+ target.addEventListener(resolveEvents[index], resolve);
305
+ for (let index = 0; index < rejectEvents.length; index++)
306
+ target.addEventListener(rejectEvents[index], reject);
307
+ });
308
+ }
package/dist/graphs.d.ts CHANGED
@@ -70,15 +70,10 @@ export declare function knapsack(weights: number[], values: number[], capacity:
70
70
  * Put infinity if where are no path. Returns cycle (start and end at the same point)
71
71
  * Original: https://github.com/qntm/held-karp
72
72
  */
73
- export declare function tspHeldKarp(distribution: number[][]): {
74
- distance: number;
75
- path: number[];
76
- };
73
+ export declare function hamiltonianCycle(distribution: number[][]): number[];
77
74
  /**
78
- * Look for description of `tspHeldKarp`.
79
- * Returns path without cycle
75
+ * Traverse all points by nearest neighbor. Should be able to go from any point to any other point.
80
76
  */
81
- export declare function tspHeldKarpPath(d: number[][]): {
82
- distance: number;
83
- path: number[];
84
- };
77
+ export declare function traverseByNearestNeighbor(distribution: number[][]): number[];
78
+ /** 2-opt improvement */
79
+ export declare function twoOpt(tour: number[], distribution: number[][]): number[];
package/dist/graphs.js CHANGED
@@ -137,10 +137,10 @@ export function knapsack(weights, values, capacity) {
137
137
  * Put infinity if where are no path. Returns cycle (start and end at the same point)
138
138
  * Original: https://github.com/qntm/held-karp
139
139
  */
140
- export function tspHeldKarp(distribution) {
140
+ export function hamiltonianCycle(distribution) {
141
141
  const n = distribution.length;
142
142
  if (n === 1)
143
- return { distance: 0, path: [0, 0] };
143
+ return [0, 0];
144
144
  const all = (1 << (n - 1)) - 1;
145
145
  const length = new Float64Array((1 << (n - 1)) * (n - 1));
146
146
  const previous = new Uint8Array((1 << (n - 1)) * (n - 1));
@@ -198,20 +198,60 @@ export function tspHeldKarp(distribution) {
198
198
  S = S2;
199
199
  }
200
200
  const index = cycle.indexOf(0);
201
- return {
202
- distance: cycle.reduce((accumulator, u, index_, cycle) => accumulator +
203
- distribution[u][cycle[index_ + 1 in cycle ? index_ + 1 : 0]], 0),
204
- path: [...cycle.slice(index), ...cycle.slice(0, index), 0],
205
- };
201
+ return [...cycle.slice(index), ...cycle.slice(0, index), 0];
206
202
  }
207
203
  /**
208
- * Look for description of `tspHeldKarp`.
209
- * Returns path without cycle
204
+ * Traverse all points by nearest neighbor. Should be able to go from any point to any other point.
210
205
  */
211
- export function tspHeldKarpPath(d) {
212
- const { distance, path } = tspHeldKarp([
213
- [0, ...new Array(d.length).fill(0)],
214
- ...d.map((d2) => [0, ...d2]),
215
- ]);
216
- return { distance, path: path.slice(1, -1).map((u) => u - 1) };
206
+ export function traverseByNearestNeighbor(distribution) {
207
+ const n = distribution.length;
208
+ const toVisit = new Array(n).fill(true);
209
+ const path = [0];
210
+ let last = 0;
211
+ toVisit[0] = false;
212
+ for (let index = 1; index < n; index++) {
213
+ let nearest = -1;
214
+ let nearestDistribution = Infinity;
215
+ for (let index = 0; index < n; index++) {
216
+ if (toVisit[index] && distribution[last][index] < nearestDistribution) {
217
+ nearest = index;
218
+ nearestDistribution = distribution[last][index];
219
+ }
220
+ }
221
+ path.push(nearest);
222
+ last = nearest;
223
+ toVisit[nearest] = false;
224
+ }
225
+ return path;
226
+ }
227
+ /** 2-opt improvement */
228
+ export function twoOpt(tour, distribution) {
229
+ let improved = true;
230
+ const nStart = tour.length - 2;
231
+ const nEnd = tour.length - 1;
232
+ while (improved) {
233
+ improved = false;
234
+ for (let start = 1; start < nStart; start++) {
235
+ for (let end = start + 1; end < nEnd; end++) {
236
+ const t0 = distribution[tour[start - 1]];
237
+ const t1 = tour[start];
238
+ const tk1 = tour[end];
239
+ const tk2 = tour[end + 1];
240
+ if (t0[tk1] +
241
+ distribution[t1][tk2] -
242
+ t0[t1] -
243
+ distribution[tk1][tk2] <
244
+ -1e-9) {
245
+ const n = ((end - start + 1) / 2) | 0;
246
+ for (let index = 0; index < n; index++) {
247
+ const temporary = tour[start + index];
248
+ tour[start + index] = tour[end - index];
249
+ tour[end - index] = temporary;
250
+ }
251
+ improved = true;
252
+ }
253
+ }
254
+ }
255
+ }
256
+ return tour;
217
257
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softsky/utils",
3
- "version": "2.7.0",
3
+ "version": "2.7.2",
4
4
  "description": "JavaScript/TypeScript utilities",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -21,7 +21,7 @@
21
21
  "homepage": "https://github.com/SoundOfTheSky/utils#readme",
22
22
  "devDependencies": {
23
23
  "@softsky/configs": "^1.3.4",
24
- "@types/bun": "^1.2.19"
24
+ "@types/bun": "^1.2.21"
25
25
  },
26
26
  "files": ["dist/**/*"]
27
27
  }