Skip to content

Perf #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Perf #24

Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/npm-publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:

- run: yarn && yarn tsc -d

- run: node lib/main.mjs
- run: node lib/test.mjs
name: run in Node tests

- run: npm publish
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/upload.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:

- run: yarn && yarn tsc

- run: node lib/main.mjs
- run: node lib/test.mjs
name: run in Node tests

- run: cp assets/index.html lib/
Expand Down
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function sameMapShape<K, T>(xs: TernaryTreeMap<K, T>, ys: TernaryTreeMap<K, T>):

List functions:

```ts
````ts
function makeTernaryTreeList<T>(size: number, offset: number, xs: /* var */ Array<TernaryTreeList<T>>): TernaryTreeList<T>;
function initTernaryTreeList<T>(xs: Array<T>): TernaryTreeList<T>;
function initEmptyTernaryTreeList<T>(): TernaryTreeList<T>;
Expand Down Expand Up @@ -75,17 +75,37 @@ function sameListShape<T>(xs: TernaryTreeList<T>, ys: TernaryTreeList<T>): boole
function getDepth<T>(tree: TernaryTreeList<T>): number;
function listToString<T>(tree: TernaryTreeList<T>): string;
function formatListInline<T>(tree: TernaryTreeList<T>): string;
function checkListStructure<T>(tree: TernaryTreeList<T>): boolean;
function checkList

### Development

```bash
# Install dependencies
yarn install

# Build TypeScript
yarn build

# Run all tests
yarn test

# Run specific test suites
yarn test:list # List-related tests only
yarn test:map # Map-related tests only
````

For detailed testing information, see [TESTING.md](./TESTING.md).Structure<T>(tree: TernaryTreeList<T>): boolean;
function forceListInplaceBalancing<T>(tree: TernaryTreeList<T>): void;
```

````

To overwrite internals behaviors:

```ts
overwriteHashGenerator(f);

overwriteComparator(f);
```
````

### License

Expand Down
155 changes: 155 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Testing Guide

## Overview

This project uses a custom lightweight testing framework that provides colored output, test organization, and detailed error reporting.

## Running Tests

### Basic Commands

```bash
# Build and run all tests
yarn test

# Only compile (useful for checking TypeScript errors)
yarn build

# Run tests manually after building
node lib/test.mjs
```

### Selective Testing

```bash
# Run only list tests (any test with "list" in the name)
yarn test:list

# Run only map tests (any test with "map" in the name)
yarn test:map

# Use environment variable for custom filtering
TARGET=specific-test-name yarn test
```

## Test Framework Features

### Test Organization

- **Test Suites**: Use `describe()` to group related tests
- **Individual Tests**: Use `test()` for specific test cases
- **Colored Output**: Green ✓ for passing tests, red ✗ for failing tests
- **Timing**: Shows execution time for each test

### Assertion Functions

#### Basic Assertions

```typescript
check(condition: boolean, message?: string)
```

#### Equality Checks

```typescript
checkEqual<T>(actual: T, expected: T, message?: string)
checkDeepEqual<T>(actual: T, expected: T, message?: string)
```

#### Array Comparisons

```typescript
checkArrayEqual<T>(actual: Array<T>, expected: Array<T>, message?: string)
arrayEqual<T>(xs: Array<T>, ys: Array<T>): boolean
```

#### Exception Testing

```typescript
checkThrows(fn: () => void, message?: string)
```

#### Debug Utilities

```typescript
justDisplay(actual: any, expected: any) // For comparing values visually
```

### Example Test Structure

```typescript
import { describe, test, check, checkEqual, checkArrayEqual } from "./test-utils.mjs";

export function runMyTests() {
describe("My Component Tests", () => {
test("should do something basic", () => {
const result = myFunction();
check(result !== null, "Result should not be null");
checkEqual(result.status, "success");
});

test("should handle arrays correctly", () => {
const actual = [1, 2, 3];
const expected = [1, 2, 3];
checkArrayEqual(actual, expected);
});

test("should throw on invalid input", () => {
checkThrows(() => {
myFunction(null);
}, "Should throw on null input");
});
});
}
```

## Test Output

The framework provides:

- **Suite Organization**: Clear grouping with cyan headers
- **Individual Results**: Green checkmarks for passing tests
- **Timing Information**: Execution time for each test
- **Error Details**: Clear error messages with stack traces
- **Summary Statistics**: Total tests, passed, failed counts
- **Exit Codes**: Non-zero exit code on test failures

## Current Test Coverage

### TernaryTreeList Tests (15 tests)

- Initialization and basic operations
- List insertions and modifications
- Concatenation and merging
- Equality checking and comparison
- Balancing and structure integrity
- Iteration and traversal
- Slicing and reversal
- Index finding and mapping
- Stress testing

### TernaryTreeMap Tests (12 tests)

- Map initialization and creation
- Association and containment checking
- Structure integrity validation
- Dissociation operations
- Array conversion and iteration
- Equality and shape comparison
- Map merging with various strategies
- Value mapping transformations
- Large dataset handling

## Adding New Tests

1. Create test functions in existing or new test files
2. Use the `describe()` and `test()` structure
3. Import and call your test function in `test.mts`
4. Use appropriate assertion functions for validation
5. Run `yarn test` to verify everything works

## Performance Considerations

- Tests include timing information to identify slow operations
- Stress tests (like concat loop test) help identify performance regressions
- Structure integrity checks validate the internal tree consistency
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
"name": "@calcit/ternary-tree",
"version": "0.0.24",
"main": "./lib/index.mjs",
"scripts": {},
"scripts": {
"build": "tsc",
"test": "yarn build && node lib/test.mjs",
"test:watch": "yarn build && node lib/test.mjs",
"test:list": "TARGET=list yarn test",
"test:map": "TARGET=map yarn test",
"test:list-perf": "yarn build && node lib/test-list-perf.mjs",
"test:list-detailed-perf": "yarn build && node lib/test-list-detailed-perf.mjs"
},
"devDependencies": {
"@types/node": "^20.12.5",
"prettier": "^3.2.5",
Expand Down
96 changes: 96 additions & 0 deletions src/benchmark.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Performance comparison script
import {
initTernaryTreeMap,
initTernaryTreeMapFromArray,
assocMap,
contains,
mapGetDefault,
dissocMap,
toPairsArray,
initEmptyTernaryTreeMap,
} from "./map.mjs";

function createTestData(size: number): Array<[number, string]> {
const data: Array<[number, string]> = [];
for (let i = 0; i < size; i++) {
data.push([i, `value_${i}`]);
}
return data;
}

function measureTime<T>(fn: () => T, iterations: number = 1): number {
const start = performance.now();
for (let i = 0; i < iterations; i++) {
fn();
}
const end = performance.now();
return (end - start) / iterations;
}

function runComparison() {
console.log("=== Performance Optimization Results ===\n");

const sizes = [1000, 5000, 10000];
const iterations = 5; // Run multiple times for more accurate results

for (const size of sizes) {
console.log(`--- ${size} elements (averaged over ${iterations} runs) ---`);

const testData = createTestData(size);
const mapData = new Map(testData);

// Test initTernaryTreeMapFromArray performance
const arrayTime = measureTime(() => {
return initTernaryTreeMapFromArray(testData);
}, iterations);

const mapTime = measureTime(() => {
return initTernaryTreeMap(mapData);
}, iterations);

console.log(`initTernaryTreeMapFromArray: ${arrayTime.toFixed(2)}ms`);
console.log(`initTernaryTreeMap: ${mapTime.toFixed(2)}ms`);

// Create tree for lookup tests
const tree = initTernaryTreeMapFromArray(testData);

// Test lookup performance
const lookupKeys = testData.slice(0, 100).map(([k]) => k);
const lookupTime = measureTime(() => {
for (const key of lookupKeys) {
contains(tree, key);
mapGetDefault(tree, key, "default");
}
}, iterations);

console.log(`Lookups (100 operations): ${lookupTime.toFixed(2)}ms`);

// Test toPairsArray performance
const toPairsTime = measureTime(() => {
return toPairsArray(tree);
}, iterations);

console.log(`toPairsArray: ${toPairsTime.toFixed(2)}ms`);

console.log(`Array/Map init ratio: ${(arrayTime / mapTime).toFixed(2)}x`);
console.log("");
}

// Stress test
console.log("=== Stress Test ===");
const largeData = createTestData(50000);
const stressTime = measureTime(() => {
const tree = initTernaryTreeMapFromArray(largeData);

// Test some operations
for (let i = 0; i < 1000; i++) {
contains(tree, i);
}

return tree;
});

console.log(`Stress test (50k elements + 1k lookups): ${stressTime.toFixed(2)}ms`);
}

runComparison();
Loading