UNPKG

solver-core-compute

Version:

Shared solver library for floorplan optimization - compatible with Node.js and Deno

192 lines (164 loc) 5.57 kB
/** * IO Contract for Solver API * TypeScript types and validation for SolveRequest/SolveResponse */ import { z } from 'zod'; import type { Position, Constraint } from './types/index.js'; // ===== SOLVE REQUEST SCHEMA ===== export const PositionSchema = z.object({ x: z.number().finite().min(-10000).max(10000), y: z.number().finite().min(-10000).max(10000), width: z.number().positive().max(10000), height: z.number().positive().max(10000), rotation: z.number().min(0).max(360).optional() }); export const ConstraintSchema = z.object({ type: z.enum(['overlap', 'boundary', 'aspect_ratio', 'proximity', 'alignment', 'min_clearance', 'work_triangle'] as const), params: z.any(), id: z.string().optional(), weight: z.number().positive().max(1000).optional() }); export const SolveRequestSchema = z.object({ positions: z.array(PositionSchema).min(1).max(1000), constraints: z.array(ConstraintSchema).min(0).max(10000), options: z.object({ algorithm: z.enum(['parallel', 'hybrid', 'adaptive', 'sa', 'ga', 'ls'] as const).optional(), timeout: z.number().positive().max(300000).optional(), gridSize: z.number().positive().max(1000).optional(), maxIterations: z.number().positive().max(100000).optional(), useParallel: z.boolean().optional(), useMultiObjective: z.boolean().optional(), randomSeed: z.number().int().min(0).max(2147483647).optional() }).optional(), metadata: z.object({ requestId: z.string().uuid().optional(), timestamp: z.number().optional(), userId: z.string().optional() }).optional() }); export type SolveRequest = z.infer<typeof SolveRequestSchema>; // ===== SOLVE RESPONSE SCHEMA ===== export const ViolationSchema = z.object({ constraintId: z.string().optional(), constraintType: z.string(), positions: z.array(z.any()), penalty: z.number().min(0).max(10000), description: z.string().optional() }); export type Violation = z.infer<typeof ViolationSchema>; export const ConstraintEvaluationSchema = z.object({ totalConstraints: z.number().min(0), satisfied: z.number().min(0), violated: z.number().min(0), violations: z.array(ViolationSchema) }); export type ConstraintEvaluation = z.infer<typeof ConstraintEvaluationSchema>; export const SolutionSchema = z.object({ positions: z.array(PositionSchema), score: z.number().min(0).max(10000), violations: z.number().min(0).max(10000), algorithm: z.string(), executionTime: z.number().min(0).max(300000), iterations: z.number().min(0).max(100000), convergenceData: z.object({ initialScore: z.number(), finalScore: z.number(), improvement: z.number() }).optional() }); export type IOSolution = z.infer<typeof SolutionSchema>; export const SolveResponseSchema = z.object({ success: z.boolean(), solutions: z.array(SolutionSchema).min(0).max(100), bestSolution: SolutionSchema.optional(), metadata: z.object({ requestId: z.string().uuid().optional(), timestamp: z.number(), solver: z.string(), totalTime: z.number().min(0).max(300000), iterations: z.number().min(0).max(100000) }), constraintEvaluation: ConstraintEvaluationSchema.optional(), errors: z.array(z.object({ code: z.string(), message: z.string(), details: z.any().optional() })).optional(), warnings: z.array(z.string()).optional() }); export type { IOSolution as Solution }; export type SolveResponse = z.infer<typeof SolveResponseSchema>; // ===== VALIDATION FUNCTIONS ===== /** * Validate SolveRequest input * Throws ZodError if validation fails */ export function validateSolveRequest(input: unknown): SolveRequest { try { return SolveRequestSchema.parse(input); } catch (error) { if (error instanceof z.ZodError) { const errorMessages = error.issues.map(e => `${e.path.join('.')}: ${e.message}` ).join('; '); const validationError = new Error(`SolveRequest validation failed: ${errorMessages}`); (validationError as any).name = 'ValidationError'; (validationError as any).issues = error.issues; throw validationError; } throw error; } } /** * Validate SolveResponse output * Throws ZodError if validation fails */ export function validateSolveResponse(output: unknown): SolveResponse { try { return SolveResponseSchema.parse(output); } catch (error) { if (error instanceof z.ZodError) { const errorMessages = error.issues.map(e => `${e.path.join('.')}: ${e.message}` ).join('; '); const validationError = new Error(`SolveResponse validation failed: ${errorMessages}`); (validationError as any).name = 'ValidationError'; (validationError as any).issues = error.issues; throw validationError; } throw error; } } /** * Validate input and output around solver call */ export function validateIO<TInput, TOutput>( input: TInput, output: TOutput, context?: string ): { input: SolveRequest; output: SolveResponse } { const validatedInput = validateSolveRequest(input); const validatedOutput = validateSolveResponse(output); // Logging removed for Deno compatibility return { input: validatedInput, output: validatedOutput }; } // ===== TYPE GUARDS ===== export function isValidSolveRequest(obj: unknown): obj is SolveRequest { try { validateSolveRequest(obj); return true; } catch { return false; } } export function isValidSolveResponse(obj: unknown): obj is SolveResponse { try { validateSolveResponse(obj); return true; } catch { return false; } }