Something went wrong. Try again.
A functional toolkit for authoring resource-leveling algorithms — compose constraint and scoring blocks, enumerate feasible schedules
Something went wrong. Try again.
2.3 kB · 67 lines
TypeScript
at main
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768// PeakCap — Constraint block.//// Caps the summed fractional *unit* demand on a resource per working day —// the unit-summing companion to `MaxConcurrentResource`'s task-count cap.// An optional [fromDay, toDay) window scopes the cap to part of the horizon// (e.g. a seasonal crane embargo); omit it for the whole horizon.//// MiniZinc compile contract: harness supplies `active[t,d]`,// `tasks_demanding[r]`, `units[t,r]`, and `DAYS`.
import { z } from "zod";
import type { PeakCapConstraint } from "../level-core/types.ts";
import type { ConstraintBlock, MiniZincFragment } from "./types.ts";
export const PeakCapInputSchema = z.object({ resourceUniqueId: z.number().int(), cap: z.number().positive(), window: z .object({ fromDay: z.number().int().nonnegative(), toDay: z.number().int().nonnegative(), }) .optional(),});
export type PeakCapInput = z.infer<typeof PeakCapInputSchema>;
const PeakCapOutputSchema: z.ZodType<PeakCapConstraint> = z.object({ kind: z.literal("PeakCap"), resourceUniqueId: z.number().int(), cap: z.number().positive(), window: z .object({ fromDay: z.number().int().nonnegative(), toDay: z.number().int().nonnegative(), }) .optional(),});
export const PeakCapBlock: ConstraintBlock<PeakCapInput> = { id: "PeakCap", schema: { input: PeakCapInputSchema, output: PeakCapOutputSchema }, apply: ({ resourceUniqueId, cap, window }): PeakCapConstraint => ({ kind: "PeakCap", resourceUniqueId, cap, ...(window ? { window } : {}), }), toMiniZinc: ({ resourceUniqueId, cap, window }): MiniZincFragment => { const dayFilter = window ? `d in DAYS where d >= ${String(window.fromDay)} /\\ d < ${String(window.toDay)}` : `d in DAYS`; return { text: `constraint forall(${dayFilter}) ` + `( sum(t in tasks_demanding[${String(resourceUniqueId)}]) ` + `(bool2int(active[t,d]) * units[t,${String(resourceUniqueId)}]) <= ${String(cap)} );`, }; }, doc: { nl: "Summed fractional unit demand on the named resource may not exceed the cap on any working day (optionally within a day window).", pseudocode: "forall day d [in window]: sum(units of active tasks demanding r) <= cap", },};