Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
21 changes: 21 additions & 0 deletions core/precision/modular/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,27 @@ const [g, x, y] = extendedGcd(35n, 15n);
clearCache();
```

### Model Interface

```typescript
import { createModular, createAndInitializeModular } from '@primeos/core/precision/modular';

// Create and initialize separately
const modular = createModular({ debug: true });
await modular.initialize();

// Or create and initialize in one step
const modular2 = await createAndInitializeModular();

// Use instance methods via process
const result = await modular2.process({
operation: 'mod',
params: [10n, 3n]
});

await modular2.terminate();
```

## Creating Custom Instances

You can create a customized modular arithmetic module with specific options:
Expand Down
5 changes: 5 additions & 0 deletions core/precision/modular/__mocks__/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from './os-model-mock';
export * from './os-logging-mock';
export * from './test-mock';
export { createMockModular as default } from './test-mock';
export function runModularMockTests() { require('./mock.test'); }
12 changes: 12 additions & 0 deletions core/precision/modular/__mocks__/mock.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { createMockModular } from './test-mock';
import { ModelLifecycleState } from './os-model-mock';

describe('Modular Mocks', () => {
it('creates a mock modular instance', async () => {
const mock = createMockModular();
expect(mock).toBeDefined();
expect(typeof mock.mod).toBe('function');
const state = mock.getState();
expect(state.lifecycle).toBe(ModelLifecycleState.Ready);
});
});
1 change: 1 addition & 0 deletions core/precision/modular/__mocks__/os-logging-mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../../../../os/logging/__mocks__';
1 change: 1 addition & 0 deletions core/precision/modular/__mocks__/os-model-mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from '../../../../os/model/__mocks__';
40 changes: 40 additions & 0 deletions core/precision/modular/__mocks__/test-mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { ModularInterface, ModularOptions, ModularState } from '../types';
import { ModelLifecycleState } from './os-model-mock';

export function createMockModular(options: ModularOptions = {}): ModularInterface {
const config = {
pythonCompatible: options.pythonCompatible ?? true,
useCache: options.useCache ?? true,
useOptimized: options.useOptimized ?? true,
nativeThreshold: options.nativeThreshold ?? 50,
strict: options.strict ?? false,
debug: options.debug ?? false
} as Required<ModularOptions>;

const state: ModularState = {
lifecycle: ModelLifecycleState.Ready,
lastStateChangeTime: Date.now(),
uptime: 0,
operationCount: { total: 0, success: 0, failed: 0 },
config
};

const result = (success: boolean) => ({ success, timestamp: Date.now(), source: options.name || 'mock-modular' });

return {
mod: () => 0n,
modPow: () => 0n,
modInverse: () => 0n,
extendedGcd: () => [1n, 0n, 0n],
gcd: () => 1n,
lcm: () => 1n,
modMul: () => 0n,
clearCache: () => {},
initialize: async () => result(true),
process: async () => 0 as any,
getState: () => ({ ...state }),
reset: async () => result(true),
terminate: async () => result(true),
createResult: <T>(s: boolean, d?: T, e?: string) => ({ success: s, data: d, error: e, timestamp: Date.now(), source: options.name || 'mock-modular' })
} as ModularInterface;
}
8 changes: 8 additions & 0 deletions core/precision/modular/__mocks__/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/// <reference types="jest" />
import './mock.test';

describe('Modular Mocks Test Runner', () => {
test('runs mock tests', () => {
expect(true).toBe(true);
});
});
9 changes: 9 additions & 0 deletions core/precision/modular/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript'
],
plugins: [
'@babel/plugin-syntax-bigint'
]
};
120 changes: 116 additions & 4 deletions core/precision/modular/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@
* Implementation of Python-compatible modular arithmetic operations.
*/

import {
import {
ModularOptions,
ModularOperations,
ModFunction,
ModPowFunction,
ModInverseFunction,
MODULAR_CONSTANTS
MODULAR_CONSTANTS,
ModularInterface,
ModularProcessInput,
ModularState
} from './types';

import { PRECISION_CONSTANTS } from '../types';
import { bitLength as bigintBitLength } from '../bigint';
import { BaseModel } from '../../../os/model';
import { createLogging } from '../../../os/logging';

/**
* Create modular arithmetic operations with the specified options
Expand Down Expand Up @@ -561,6 +566,106 @@ function createModularOperations(options: ModularOptions = {}): ModularOperation
};
}

/**
* Modular model implementation
*/
class ModularImplementation extends BaseModel implements ModularInterface {
private impl: ModularOperations;
private config: Required<ModularOptions>;

constructor(options: ModularOptions = {}) {
const processed = {
pythonCompatible: options.pythonCompatible ?? true,
useCache: options.useCache ?? true,
useOptimized: options.useOptimized ?? true,
nativeThreshold: options.nativeThreshold ?? MODULAR_CONSTANTS.MAX_NATIVE_BITS,
strict: options.strict ?? false,
debug: options.debug ?? false
} as Required<ModularOptions>;

super({ debug: processed.debug, name: options.name || 'precision-modular', version: options.version || '1.0.0' });

this.config = processed;
this.impl = createModularOperations(processed);

// bind methods
this.mod = this.impl.mod;
this.modPow = this.impl.modPow;
this.modInverse = this.impl.modInverse;
this.extendedGcd = this.impl.extendedGcd;
this.gcd = this.impl.gcd;
this.lcm = this.impl.lcm;
this.modMul = this.impl.modMul;
this.clearCache = this.impl.clearCache;
}

protected async onInitialize(): Promise<void> {
this.logger = createLogging();
this.state.custom = { config: this.config };
}

protected async onProcess<T = ModularProcessInput, R = unknown>(input: T): Promise<R> {
const req = input as unknown as ModularProcessInput;
switch (req.operation) {
case 'mod':
return this.impl.mod(req.params[0], req.params[1]) as unknown as R;
case 'modPow':
return this.impl.modPow(req.params[0], req.params[1], req.params[2]) as unknown as R;
case 'modInverse':
return this.impl.modInverse(req.params[0], req.params[1]) as unknown as R;
case 'extendedGcd':
return this.impl.extendedGcd(req.params[0], req.params[1]) as unknown as R;
case 'gcd':
return this.impl.gcd(req.params[0], req.params[1]) as unknown as R;
case 'lcm':
return this.impl.lcm(req.params[0], req.params[1]) as unknown as R;
case 'modMul':
return this.impl.modMul(req.params[0], req.params[1], req.params[2]) as unknown as R;
case 'clearCache':
this.impl.clearCache();
return undefined as unknown as R;
default:
throw new Error(`Unknown operation: ${req.operation}`);
}
}

protected async onReset(): Promise<void> {
this.impl.clearCache();
}

protected async onTerminate(): Promise<void> {
// nothing extra
}

getState(): ModularState {
const base = super.getState();
return { ...base, config: this.config } as ModularState;
}

// placeholder properties overwritten in constructor
mod!: ModFunction;
modPow!: ModPowFunction;
modInverse!: ModInverseFunction;
extendedGcd!: (a: bigint, b: bigint) => [bigint, bigint, bigint];
gcd!: (a: bigint, b: bigint) => bigint;
lcm!: (a: bigint, b: bigint) => bigint;
modMul!: ModMulFunction;
clearCache!: () => void;
}

export function createModular(options: ModularOptions = {}): ModularInterface {
return new ModularImplementation(options);
}

export async function createAndInitializeModular(options: ModularOptions = {}): Promise<ModularInterface> {
const instance = createModular(options);
const result = await instance.initialize();
if (!result.success) {
throw new Error(`Failed to initialize modular module: ${result.error}`);
}
return instance;
}

// Create default instance with standard options
const defaultOperations = createModularOperations();

Expand All @@ -577,10 +682,17 @@ export const {
} = defaultOperations;

// Export types and interfaces
export type { ModularOperations };
export type {
ModularOperations,
ModularOptions,
ModularInterface,
ModularProcessInput,
ModularState,
ModularFactory
};

// Export the factory function
export { createModularOperations };
export { createModularOperations, createModular, createAndInitializeModular, ModularImplementation };

// Export constants
export { MODULAR_CONSTANTS };
23 changes: 23 additions & 0 deletions core/precision/modular/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
transform: {
'^.+\\.tsx?$': 'ts-jest'
},
testMatch: ['**/*.test.ts', '**/*.spec.ts', '**/test.ts'],
// Add babel support for BigInt literals
globals: {
'ts-jest': {
babelConfig: {
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
'@babel/preset-typescript'
],
plugins: [
"@babel/plugin-syntax-bigint"
]
}
}
}
};
31 changes: 30 additions & 1 deletion core/precision/modular/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Test suite for the modular arithmetic precision module.
*/

import {
import {
mod,
modPow,
modInverse,
Expand All @@ -15,8 +15,15 @@ import {
lcm,
clearCache,
createModularOperations,
createModular,
createAndInitializeModular,
ModularInterface,
MODULAR_CONSTANTS
} from './index';
import { ModelLifecycleState } from './__mocks__/os-model-mock';

jest.mock('../../../os/model', () => require('./__mocks__/os-model-mock'));
jest.mock('../../../os/logging', () => require('./__mocks__/os-logging-mock'));

describe('Modular Arithmetic Module', () => {
describe('mod function', () => {
Expand Down Expand Up @@ -225,6 +232,28 @@ describe('Modular Arithmetic Module', () => {
expect(operations.modPow(2, 10, 1000)).toBe(24);
});
});

describe('Model Interface', () => {
test('createModular returns a model implementing the interface', () => {
const model = createModular();
expect(model).toBeDefined();
expect(typeof model.initialize).toBe('function');
expect(typeof model.process).toBe('function');
expect(typeof model.getState).toBe('function');
});

test('createAndInitializeModular yields a ready instance', async () => {
const model = await createAndInitializeModular({ name: 'test-mod' });
const state = model.getState();
expect(state.lifecycle).toBe(ModelLifecycleState.Ready);
});

test('process correctly handles ModularProcessInput', async () => {
const model = await createAndInitializeModular();
const result = await model.process({ operation: 'mod', params: [10n, 3n] });
expect(result).toBe(1n);
});
});

describe('Constants', () => {
test('MODULAR_CONSTANTS are defined', () => {
Expand Down
22 changes: 22 additions & 0 deletions core/precision/modular/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "es2020",
"module": "commonjs",
"declaration": true,
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"baseUrl": ".",
"paths": {
"*": ["node_modules/*"]
},
"lib": ["es2020", "DOM"],
"types": ["node", "jest"]
},
"include": ["*.ts"],
"exclude": ["node_modules", "dist"]
}
Loading