solver-core-compute
Version:
Shared solver library for floorplan optimization - compatible with Node.js and Deno
154 lines (153 loc) • 5.16 kB
JavaScript
/**
* IO Contract for Solver API
* TypeScript types and validation for SolveRequest/SolveResponse
*/
import { z } from 'zod';
// ===== 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']),
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']).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()
});
// ===== 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 const ConstraintEvaluationSchema = z.object({
totalConstraints: z.number().min(0),
satisfied: z.number().min(0),
violated: z.number().min(0),
violations: z.array(ViolationSchema)
});
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 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()
});
// ===== VALIDATION FUNCTIONS =====
/**
* Validate SolveRequest input
* Throws ZodError if validation fails
*/
export function validateSolveRequest(input) {
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.name = 'ValidationError';
validationError.issues = error.issues;
throw validationError;
}
throw error;
}
}
/**
* Validate SolveResponse output
* Throws ZodError if validation fails
*/
export function validateSolveResponse(output) {
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.name = 'ValidationError';
validationError.issues = error.issues;
throw validationError;
}
throw error;
}
}
/**
* Validate input and output around solver call
*/
export function validateIO(input, output, context) {
const validatedInput = validateSolveRequest(input);
const validatedOutput = validateSolveResponse(output);
// Logging removed for Deno compatibility
return {
input: validatedInput,
output: validatedOutput
};
}
// ===== TYPE GUARDS =====
export function isValidSolveRequest(obj) {
try {
validateSolveRequest(obj);
return true;
}
catch {
return false;
}
}
export function isValidSolveResponse(obj) {
try {
validateSolveResponse(obj);
return true;
}
catch {
return false;
}
}