import { Stream } from "../data"; import { ArrayType, BooleanType, DateTimeType, DictType, EastFunction, EastType, IntegerType, NonNullable, Nullable, SetType, StringType, StructType, ValueTypeOf, Variable, VariantType, AstType, SubType } from "../east"; import { GenericPipelineBuilder, PipelineBuilder, TabularPipelineBuilder } from "../pipeline"; import { Builder } from "../template/Template"; import { SimulationResourceBuilder } from "./ResourceBuilder"; import { MLDescription, MLEvaluator, Statement } from './SimulationTaskDescription'; import { AbstractMLBuilder, MLModel } from '../ml'; import { ModuleBuilder } from '../template/ModuleBuilder'; import { ModulePath } from '../template'; import { ProcedureDescription, ProcedureEvaluator } from '../function/FunctionTaskDescription'; import { ProcedureFinalizer } from '../function/Procedure'; /** @internal */ export declare abstract class AbstractProcessBuilder, Properties extends Record, Resources extends Record, MLs extends Record, Procs extends Record> extends Builder { protected name: Name; protected uniqueName: string; protected description: string | null; protected values: Values; protected properties: Properties; protected resources: Resources; protected statements: Statement[]; protected mls: MLs; protected procedures: Procs; constructor(name: Name, module: ModulePath, uniqueName: string, description: string | null, values: Values, properties: Properties, resources: Resources, statements: Statement[], mls: MLs, procedures: Procs); abstract processStream(): null | Stream>>; } /** * A builder to define a process for simulation. * * @category Process * * @example * ```typescript * const cash = new ResourceBuilder("cash") * .mapFromValue(1.0) * .assert({ * predicate: x => GreaterEqual(x, 0), * message: "Cash must be positive", * }); * * const sales = new ProcessBuilder("sales") * .resource(cash) * .value("amount", FloatType) * .set("cash", (props, resources) => Add(resources.cash, props.amount)) * .mapFromValue({ date: new Date(0), amount: 42.0, }); * * const scenario = new ScenarioBuilder('my_scenario') * .resource(cash) * .process(sales); * ``` * */ export declare class ProcessBuilder = {}, Properties extends Record = { date: Variable; }, Resources extends Record = {}, Processes extends Record> = {}, MLs extends Record = {}, Procs extends Record = {}> extends AbstractProcessBuilder { protected name: Name; private processes; private hasEndStatement; private n_blocks; /** * Construct a process with a given name. * * @param name the name for the {@link ProcessBuilder} * * @category Process * * @example * ```typescript * const cash = new ResourceBuilder("cash") * .mapFromValue(1.0) * .assert({ * predicate: x => GreaterEqual(x, 0), * message: "Cash must be positive", * }); * * const sales = new ProcessBuilder("sales") * .resource(cash) * .value("amount", FloatType) * .set("cash", (props, resources) => Add(resources.cash, props.amount)) * .mapFromValue({ date: new Date(0), amount: 42.0, }); * * const scenario = new ScenarioBuilder('my_scenario') * .resource(cash) * .process(sales); * ``` * */ constructor(name: Name, module?: ModuleBuilder | ModulePath); /** @internal */ constructor(name: Name, module: ModulePath, uniqueName: string, description: string | null, values: Values, properties: Properties, resources: Resources, processes: Processes, mls: MLs, procedures: Procs, statements: Statement[], hasEndStatement: boolean, n_blocks: number); /** Add a human-readable description of the process (as a whole). * * @param description the description string. * * @category Process * * @example * ```typescript * // create the sales process with some properties * const sales = new ProcessBuilder("sales") * .describe("Process a sale event, determining the profit from revenue and cost") * .let("revenue", () => Const(5)) * .let("cost", () => Const(6)) * .let("profit", (props) => Subtract(props.revenue, props.cost)) * .mapFromValue({ date: new Date(0) }); * ``` */ describe(description: string): this; /** * Override an existing process, inheriting its name (for the purposes of simulation) and * input {@link value} properties. Any computed properties, imports or other statements * are not inherited. * * The resulting process can then be used to override the process in a scenario that has * been constructed with {@link ScenarioBuilder.copyScenario} or {@link ScenarioBuilder.continueScenario} * using the {@link ScenarioBuilder.overrideProcess} method. Given that the name and input * value properties match, any {@link execute} statements or queued processes throughout * the scenario will be executed by the new process. * * @param process - a process builder to copy the name and input value properties * * @category Process */ overrides>(process: AbstractProcessBuilder, Record>, Record, Record>): ProcessBuilder; } & { [K in keyof NewValues]: Variable; }, Resources, Processes, MLs, Procs>; /** * Include a resource that this process can read or modify. * * @param resource the {@link ResourceBuilder} to add to the {@link ProcessBuilder}\ * * @category Process * * @example * ```typescript * // create a resource * const cash = new ResourceBuilder("cash") * .mapFromValue(0) * * // create the sale process * const sales = new ProcessBuilder("sales") * .resource(cash) * // set the cash balance * .set("cash", () => Const(5)) * // simulate from a date * .mapFromValue({ date: new Date(0) }); * ``` */ resource(resource: SimulationResourceBuilder): ProcessBuilder; }, Processes, MLs, Procs>; /** * Include another process that this process can execute. * * @param process the {@link ProcessBuilder} to add to the {@link ProcessBuilder} * * @category Process * * @example * ```typescript * // create the process to be added * const receive_items = new ProcessBuilder("receive items") * .value("qty", FloatType) * .log({ * message: (props) => StringJoin`Recieved ${props.qty} items` * }) * * // add a process to another and execute an hour after * const sales = new ProcessBuilder("sales") * .process(receive_items) * .execute("receive items", (props) => Struct({ * date: AddDuration(props.date, 1, 'hour'), * qty: Const(5) * })) * .mapFromValue({ date: new Date(0) }); * ``` * */ process>(process: AbstractProcessBuilder, Record, Record, Record>): ProcessBuilder; /** * Include a ML function that this process can evaluate as a kind of "procedure". * * @param ml the {@link MLModelBuilder} model add to the {@link ProcessBuilder} * * @category Process * * @example * ```typescript * // create the ML function of the amount * const amount = new MLModelBuilder("amount") * // the output is amount which is FloatType * .output(FloatType) * * // create the sales process and add the ML function * // which is evaluated in each sale * const sales = new ProcessBuilder("sales") * .resource(cash) * // the ML function can be added * .ml(demand) * // the ML can be evaluated similarly to a procedure * // (note, this ML function has no input features) * .let( * "amount", * (_props, _resources, procs) => mls.demand(Struct({})) * ) * // ... * ``` * */ ml, T extends EastType>(ml: AbstractMLBuilder): ProcessBuilder, T>; }, Procs>; /** * Include a sub-procedure that this process can evaluate. * * @param procedure the {@link Procedure} model add to the {@link ProcessBuilder} * * @category Process * * @example * ```typescript * // create a procedure to calculate the tax to apply to a sale * const apply_tax = new Procedure("apply_tax") * // the input parameter * .input("amount", FloatType) * // the output is a FloatType * .output(FloatType) * // the body of the procedure * .body(b => b * // add a 10% tax and return the value * .return(vars => Multiply(vars.amount, 1.1)) * ) * * // create the sales process and add the ml function * // which is evaluated in each sale * const sales = new ProcessBuilder("sales") * .resource(cash) * // import the procedure * .procedure(apply_tax) * // the pre-tax sale amount * .value("amount", FloatType) * // the procedure can be accessed and evaluated inside expressions within the function * .let( * "tax_adjusted_amount", * (vars, _resources, procs) => procs.apply_tax(Struct({ amount: vars.amount })) * ) * // ... * ``` * */ procedure, T extends EastType>(procedure: ProcedureFinalizer): ProcessBuilder, T>; }>; /** * Define an input value property for the process. * * @param name the name of the property * @param type the type of the property * * @category Process * * @example * ```typescript * // create a simple process with an input value * const sales = new ProcessBuilder("sales") * .value("amount", FloatType) * .mapFromValue({ date: new Date(0), amount: 1 }); * ``` * */ value(name: PropertyName, type: T): ProcessBuilder; }, Resources, Processes, MLs, Procs>; /** * Compute a property as an expression of existing properties. * * @param name the name of the property * @param expression the function of defining the property * * @remarks you may overwrite an existing property of the same name with a new value of any type. * * @category Process * * @example * ```typescript * // create the sales process with some properties * const sales = new ProcessBuilder("sales") * .let("revenue", () => Const(5)) * .let("cost", () => Const(6)) * .let("profit", (props) => Subtract(props.revenue, props.cost)) * .mapFromValue({ date: new Date(0) }); * ``` */ let; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(name: PropertyName, expression: Expr): ProcessBuilder : Properties) & { [K in PropertyName]: Variable["type"]>; }, Resources, Processes, MLs, Procs>; /** * Reassign an existing property value with the result of an expression of existing properties. * * @param name the name of the property * @param expression the function of defining the new property value * * @remarks You must overwrite an existing property, and the value must be of the same type as that property. The `"date"` property cannot be modified. * * @category Process * * @example * ```typescript * const my_process = new ProcessBuilder("my_process") * // let x = 5 * .let("x", () => Const(5)) * // x = x + 1 * .assign("x", props => Add(props.x, 1)) * ``` */ assign; } & { [K in keyof Procs]: ProcedureEvaluator; }) => { type: SubType; ast_type: AstType; }>(name: PropertyName, expression: Expr): ProcessBuilder; /** * Throw an error with a provided error message. * * @param message the error message * * @category Process * * @example * ```typescript * // create the sales process with some properties * const sales = new ProcessBuilder("sales") * // create random qty * .let("qty", () => RandomUniform(0, 1)) * .if( * (props) => Less(props.qty, 0.5), * block => block * .error((props) => StringJoin`value ${props.qty} <= 0.5`) * ) * .mapFromValue({ date: new Date(0) }); * ``` * */ error(message: ((properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction) | string): ProcessBuilder; /** * Produce a warning with a message. * * @param message the error message * * @category Process * * @example * ```typescript * // create the sales process with some properties * const sales = new ProcessBuilder("sales") * // create random qty * .let("qty", () => RandomUniform(0, 1)) * .if( * (props) => Less(props.qty, 0.5), * block => block * .warn((props) => StringJoin`value ${props.qty} <= 0.5`) * ) * .mapFromValue({ date: new Date(0) }); * ``` * */ warn(message: ((properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction) | string): ProcessBuilder; /** * Produce a log message. * * @param message the error message * * @category Process * * @example * ```typescript * // create the sales process with some properties * const sales = new ProcessBuilder("sales") * // create random qty * .let("qty", () => RandomUniform(0, 1)) * .if( * (props) => Less(props.qty, 0.5), * block => block * .log((props) => StringJoin`value ${props.qty} <= 0.5`) * ) * .mapFromValue({ date: new Date(0) }); * ``` * */ log(message: ((properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction) | string): ProcessBuilder; /** * Set a resource value. * * @param name the {@link ResourceBuilder} name to set * @param value the function defining the value * * @remarks this overwrites the existing resource value in it's entirety, even if it is a collection. Use the `update`, `insert` or `delete` methods to modify just part of a resource. * * @category Process * * @example * ```typescript * // create a resource * const cash = new ResourceBuilder("cash") * .mapFromValue(0) * * // create the sale process * const sales = new ProcessBuilder("sales") * .resource(cash) * // set the cash balance * .set("cash", () => Const(5)) * // simulate from a date * .mapFromValue({ date: new Date(0) }); * ``` */ set; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(name: ResourceName, value: V & (Resources[ResourceName]["type"] extends ReturnType["type"] ? unknown : never)): ProcessBuilder; /** * Insert a new entry into an array, set or dictionary. * * For arrays, you can insert the `"first"` or `"last"` element (i.e. push to the front or end of the array). * For sets, you can insert a new key. If the key already exists an error will result. * For dictionaries, you can insert a new key and associated value. If the key already exists an error will result (see also {@link update}). * * @param collection a function returning the array, set or dictionary to insert into * @param key the key of the item to insert * @param value the value to insert (for arrays and dictionaries only) * * @category Process * * @example * ```typescript * // create a resource * const inventory = new ResourceBuilder("inventory") * .mapFromValue(new Map([ * ["socks", { qty: 1n }], * ["chairs", { qty: 3n }] * ])) * * // add the inventory resource and insert a value * const delivery = new ProcessBuilder("delivery") * .resource(inventory) * .value("qty", IntegerType) * .value("item", StringType) * .insert( * (props, resources) => resources.inventory, * (props) => props.item, * (props) => Struct({ qty: props.qty }), * ) * .mapFromValue({ * date: new Date(0), * item: "frame", * qty: 54n * }); * ``` */ insert; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction["type"]["value"]["key"]>, value: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => { type: SubType["type"]["value"]["value"]>; ast_type: AstType; }): ProcessBuilder; insert; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction["type"]["value"]>): ProcessBuilder; insert; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: 'first' | 'last', value: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => { type: SubType["type"]["value"]>; ast_type: AstType; }): ProcessBuilder; /** * Update an existing value in an array or dictionary. The collection will be mutated in place. * * For arrays, you can update any element by integer index (the first element has index `0n`). If the index is out of bounds an error will result. * For dictionaries, you can update any existing key to a new associated value. If the key does not exist an error will result (see also {@link insert}). * In both cases, you are given access the existing value when computing the new value. * * @param collection a function returning the array, set or dictionary to update * @param key the key of the item to update * @param value the value to update to * * @category Process * * @example * ```typescript * // create a resource * const inventory = new ResourceBuilder("inventory") * .mapFromValue(new Map([ * ["socks", { qty: 1n }], * ["chairs", { qty: 3n }] * ])) * * // subtract the appropriate qty from inventory * const dispatch = new ProcessBuilder("dispatch") * .resource(inventory) * .value("qty", IntegerType) * .value("item", StringType) * .update( * (props, resources) => resources.inventory, * (props) => props.item, * (props, _, _, old_value) => Struct({ qty: Subtract(GetField(old_value, "qty"), props.qty) }), * ) * .mapFromValue({ * date: new Date(0), * item: "chair", * qty: 2n * }); * ``` **/ update; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction["type"]["value"]["key"]>, value: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }, old_value: Variable["type"]["value"]["value"]>) => { type: SubType["type"]["value"]["value"]>; ast_type: AstType; }): ProcessBuilder; update; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction, value: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }, old_value: Variable["type"]["value"]>) => { type: SubType["type"]["value"]>; ast_type: AstType; }): ProcessBuilder; /** * Delete an existing element from an array, set or dictionary. The collection will be mutated in place. * * For arrays, you can delete the `"first"` or `"last"` element (i.e. pop the front or end of the array). * For sets, you can delete an existing key. If the key doesn't exist an error will result. * For dictionaries, you can delete an existing key (and associated value). If the key doesn't exist an error will result. * * @param collection a function returning the array, set or dictionary to update * @param key the key of the item to delete * * @category Process * * @example * ```typescript * // create a resource * const inventory = new ResourceBuilder("inventory") * .mapFromValue(new Map([ * ["socks", { qty: 1n }], * ["chairs", { qty: 3n }] * ])) * * // unlist an item from inventory * const unlist = new ProcessBuilder("unlist") * .resource(inventory) * .value("qty", IntegerType) * .value("item", StringType) * .delete( * (props, resources) => resources.inventory, * (props) => props.item, * ) * .mapFromValue({ * date: new Date(0), * item: "socks", * }); * ``` **/ delete; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction["type"]["value"]["key"]>): ProcessBuilder; delete; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction["type"]["value"]>): ProcessBuilder; delete; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: 'first' | 'last'): ProcessBuilder; /** * Delete all elements from an array, set or dictionary. The collection will be mutated in place. * * @param collection a function returning the array, set or dictionary to clear * * @category Function * * @example * ```typescript * // create a resource for inventory items * const inventory = new ResourceBuilder("inventory") * .mapFromValue(new Map([ * ["socks", { qty: 1n }], * ["chairs", { qty: 3n }] * ])) * * // add the inventory resource and clear all values * const dump_inventory = new ProcessBuilder("dump_inventory") * .resource(inventory) * .clear((props, resources) => resources.inventory) * .mapFromValue({ * date: new Date(0), * }); * ``` */ clear(collection: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction): ProcessBuilder; /** * Execute a new process instance at a specified date. * * @param name the {@link ProcessBuilder} name to execute * @param values the values to execute the {@link ProcessBuilder} with * * @remarks The `values` must be an object with at least `date`, but also any `value` property define in the {@link ProcessBuilder} being executed * * @remarks It is valid to execute another process that has been added, or call this process recursively * * @category Process * * @example * ```typescript * // create the process to be added * const receive_items = new ProcessBuilder("receive items") * .value("qty", FloatType) * .log({ * message: (props) => StringJoin`Recieved ${props.qty} items` * }) * * // add a process to another and execute an hour after * const sales = new ProcessBuilder("sales") * .process(receive_items) * .execute("receive items", (props) => Struct({ * date: AddDuration(props.date, 1, 'hour'), * qty: Const(5) * })) * .mapFromValue({ date: new Date(0) }); * ``` * * @example * ```typescript * * // execute the sales process recursively every minute until an hour passes * const sales = new ProcessBuilder("sales") * .execute("sales", (props) => Struct({ * date: AddDuration(props.date, 1, 'minute'), * })) * // note that `new Date(3600000)` will be constant in the simulation * .endSimulation((props) => Greater(props.date, new Date(3600000))) * .mapFromValue({ date: new Date(0) }); * ``` */ execute; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>>(name: Name, values: V & (StructType<{ date: DateTimeType; } & Values> extends ReturnType["type"] ? unknown : never)): ProcessBuilder; execute; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>>(name: ProcessName, values: V & (StructType<{ date: DateTimeType; } & Processes[ProcessName]> extends ReturnType["type"] ? unknown : never)): ProcessBuilder; /** * Perform blocks of statements conditional on some predicate (Boolean) expression. * * @param predicate a function that returns a `BooleanType` expression of properties and resources * @param true_block a function that returns a block of statements to be executed if the `predicate` is `true`. * @param false_block an optional function that returns a block of statements to be executed if the `predicate` is `false`. * * @category Process * * @example * ```typescript * // stock level of products to sell * const stock = new ResourceBuilder("stock") * .fromValue(100.0) * * // sales reduces stock level * const sales = new ProcessBuilder("sales") * .resource(stock) * .value("qty", FloatType) * // only deduct stock if qty is non-zero * .if( * props => Greater(qty, 0.0), * block => block * .set("stock", (props, resources) => Subtract(resources.stock, props.qty)) * ) * ``` */ if(predicate: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction, true_block: (block: ProcessBlockBuilder) => ProcessBlockBuilder, Resources, Processes & { [K in Name]: Values; }, MLs, Procs>, false_block?: (block: ProcessBlockBuilder) => ProcessBlockBuilder, Resources, Processes & { [K in Name]: Values; }, MLs, Procs>): ProcessBuilder; /** * Execute blocks of statements conditional on some input being null or not. * * @param input a function that returns a `Nullable` expression of properties and resources * @param null_block a function that returns a block of statements to be executed if the `input` is `null`. * @param value_block an optional function that returns a block of statements to be executed if the `input` is not `null`. The input value is available as a non-nullable variable. * * @category Process * * @example * ```typescript * // stock level of products to sell * const stock = new ResourceBuilder("stock") * .fromValue(100.0) * * // sales reduces stock level (but only qty is not null) * const sales = new ProcessBuilder("sales") * .resource(stock) * .value("qty", Nullable(FloatType)) * // only deduct stock if qty is non-zero * .ifNull( * props => qty, * block => block, * block => block, * .set("stock", (props, resources) => Subtract(resources.stock, props.qty)) * ) * ``` */ ifNull; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(input: I, null_block: (block: ProcessBlockBuilder) => ProcessBlockBuilder, Resources, Processes & { [K in Name]: Values; }, MLs, Procs>, value_block?: (block: ProcessBlockBuilder, value: Variable["type"]>>) => ProcessBlockBuilder, Resources, Processes & { [K in Name]: Values; }, MLs, Procs>): ProcessBuilder; /** * Perform blocks of statements matched on the cases of some variant expression. * * @param variant a function that returns a `VariantType` expression of properties and resources * @param cases an object containing functions that return a block of statements to be executed for the given variant case * * @category Process * * @example * ```typescript * // sales produes a log message about the buyer * const sales = new ProcessBuilder("sales") * .value("buyer_name", MaybeType(StringType)) * .let("message", _ => Const("")) * .match( * (_, resources) => resources.buyer, * { * Some: (block, name) => block.assign("message", _ => StringJoin`Initiating sale to ${name}`), * None: (block) => block.assign("message", _ => StringJoin`Initiating sale to unknown buyer`), * } * ) * ``` */ match; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction, T extends { [K in keyof ReturnType["type"]["value"]]: (block: ProcessBlockBuilder, data: Variable["type"]["value"][K]>) => ProcessBlockBuilder, Resources, Processes & { [K in Name]: Values; }, MLs, Procs>; }>(variant: V, cases: T): ProcessBuilder; /** * Repeatedly perform a block of statements, conditional on some predicate (Boolean) expression. * * @param predicate a function that returns a `BooleanType` expression of properties and resources * @param loop_block a function that returns a block of statements to be executed repeatedly until the `predicate` is `false`. * * @category Process * * @example * ```typescript * // perform a loop from i = 0 to 10 * new ProcessBuilder("my_process") * .let("i", 0n) * .while( * props => LessEqual(props.i, 10n), * block => block * .assign("i", props => Add(props.i, 1n)) * ) * ``` */ while(predicate: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction, loop_block: (block: ProcessBlockBuilder) => ProcessBlockBuilder, Resources, Processes & { [K in Name]: Values; }, MLs, Procs>): ProcessBuilder; /** * Perform a block of statements for each item in an array. * * @param collection a function that returns an array expression of properties and resources * @param loop_block a function that returns a block of statements to be executed for each element of a collection. * * @category Process * * @example * ```typescript * // log out all indices and values of an array * new ProcessBuilder("my_process") * .let("array", _ => Const(["a", "b", "c"])) * .forArray( * props => props.array, * (block, value, key) => block * .log({ * message: () => StringJoin`Index ${key} contains string ${value}` * }) * ) * ``` */ forArray; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: Collection, loop_block: (block: ProcessBlockBuilder, value: Variable["type"]["value"]>, key: Variable) => ProcessBlockBuilder, Resources, Processes & { [K in Name]: Values; }, MLs, Procs>): ProcessBuilder; /** * Perform a block of statements for each item in a set. * * @param collection a function that returns an set expression of properties and resources * @param loop_block a function that returns a block of statements to be executed for each element of a collection. * * @category Process * * @example * ```typescript * // log out all keys of a set * new ProcessBuilder("my_process") * .let("set", _ => Const(new Set(["a", "b", "c"]))) * .forSet( * props => props.set, * (block, key) => block * .log({ * message: () => StringJoin`Key ${key}` * }) * ) * ``` */ forSet; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: Collection, loop_block: (block: ProcessBlockBuilder, key: Variable["type"]["value"]>) => ProcessBlockBuilder, Resources, Processes & { [K in Name]: Values; }, MLs, Procs>): ProcessBuilder; /** * Perform a block of statements for each item in a dictionary. * * @param collection a function that returns a dictionary expression of properties and resources * @param loop_block a function that returns a block of statements to be executed for each element of a collection. * * @category Process * * @example * ```typescript * // log out all keys and values of an dictionary * new ProcessBuilder("my_process") * .let("dict", _ => Const(new Map([["a", 1n], ["b", 2n], ["c", 3n]])) * .forDict( * props => props.dict, * (block, value, key) => block * .log({ * message: () => StringJoin`Key ${key} contains value ${value}` * }) * ) * ``` */ forDict; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: Collection, loop_block: (block: ProcessBlockBuilder, value: Variable["type"]["value"]["value"]>, key: Variable["type"]["value"]["key"]>) => ProcessBlockBuilder, Resources, Processes & { [K in Name]: Values; }, MLs, Procs>): ProcessBuilder; /** * End the **entire** simulation immediately. A user-defined predicate may be provided to control when this does or does not occur. * * @param predicate a function if set to true will end the **entire** simulation * * @remarks Any later statements in this process instance will not be executed. * * @remarks Once triggered this will end the **entire** simulation. * * @category Process * * @example * ```typescript * // create the sale process * const sales = new ProcessBuilder("sales") * // create another sale * .execute( * "sales", * (props) => Struct({ * date: AddDuration( * props.date, * RandomExponential(), * 'hour' * ), * }) * ) * // end after an hour * .endSimulation((props) => Greater(props.date, new Date(3600000))) * // start simulating from a date * .mapFromValue({ date: new Date(0) }); * ``` */ endSimulation(predicate?: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction): ProcessBuilder; /** * Create a single instance of a process from a {@link Value}. * * @param value the value to map from. * * @remarks The `value` must be an {@link StructValue} typed **object** with at least a `date` value, but also any `value` property define in the {@link ProcessBuilder} * * @category Process * * @example * ```typescript * // map a process from a value * const receive_items = new ProcessBuilder("receive items") * .value("qty", FloatType) * .mapFromValue({ * date: new Date(0), * qty: 10 * }); * ``` */ mapFromValue(value: ValueTypeOf>): MappedProcessBuilder; /** * Create an instance of a process from a {@link Stream}. * * @param stream the stream to map from. * * @remarks The `stream` must be a {@link StructType} stream with a `date` value, but also any `value` property define in the {@link ProcessBuilder} * * @category Process * * @example * ```typescript * // a stream to map from * const data = new SourceBuilder("receive items data") * .value({ * value: { * date: new Date(0), * qty: 3 * } * }) * * // create the process to map * const receive_items = new ProcessBuilder("receive items") * .value("qty", FloatType) * .mapFromStream(data.outputStream()); * ``` */ mapFromStream(stream: Stream>): MappedProcessBuilder; /** * Create a instance of a process from a {@link PipelineBuilder}. * * @param builder a function with a {@link PipelineBuilder} outputing a stream to map a value from. * * @remarks The `pipeline` must output a {@link StructType} stream with a `date` value, but also any `value` property define in the {@link ProcessBuilder} * * @category Process * * @example * ```typescript * // a stream to map from * const data = new SourceBuilder("receive items data") * .value({ * value: { * date: new Date(0), * qty: 3 * } * }) * * // create the process to map * const receive_items = new ProcessBuilder("receive items") * .value("qty", FloatType) * .mapFromPipeline(builder => builder * .from(data.outputStream()) * ); * ``` */ mapFromPipeline(pipeline: (builder: PipelineBuilder) => GenericPipelineBuilder, Record>): MappedProcessBuilder; /** * Create many instances of a process from a {@link Value}. * * @param value the Map object containing values to map from. * * @remarks The `value` must be {@link DictValue} with {@link StructValue} entries containing at least a `date` value, but also any `value` property define in the {@link ProcessBuilder} * * @category Process * * @example * ```typescript * // create the process to map * const receive_items = new ProcessBuilder("receive items") * .value("qty", FloatType) * .mapManyFromValue( * new Map([ * ["one", { * date: new Date(0), * qty: 10 * }], * ["two", { * date: new Date(0), * qty: 5 * }] * ])); * ``` */ mapManyFromValue(value: ValueTypeOf>>): MappedProcessBuilder; /** * Create many instances of a process from a {@link Stream}. * * @param stream the stream to map from. * * @remarks The `stream` must be a {@link DictType} stream with {@link StructType} value with a `date` value, but also any `value` property define in the {@link ProcessBuilder} * * @category Process * * @example * ```typescript * // a stream to map from * const data = new SourceBuilder("receive items data") * .value({ * value: new Map([ * ["one", { * date: new Date(0), * qty: 10 * }], * ["two", { * date: new Date(0), * qty: 5 * }] * ]) * }) * * // create the process to map * const receive_items = new ProcessBuilder("receive items") * .value("qty", FloatType) * .mapManyFromStream(data.outputStream()); * ``` */ mapManyFromStream(stream: Stream>>): MappedProcessBuilder; /** * Create many instances of a process from a {@link Pipeline}. * * @param builder a function with a {@link PipelineBuilder} outputing a stream to map values from. * * @remarks The `pipeline` must output {@link DictType} stream with a {@link StructType} value with a `date` value, but also any `value` property define in the {@link ProcessBuilder} * * @category Process * * @example * ```typescript * // a stream to map from * const data = new SourceBuilder("receive items data") * .value({ * value: new Map([ * ["one", { * date: new Date(0), * qty: 10 * }], * ["two", { * date: new Date(0), * qty: 5 * }] * ]) * }) * * // create the process to map * const receive_items = new ProcessBuilder("receive items") * .value("qty", FloatType) * .mapManyFromPipeline(builder => builder * .from(data.outputStream()) * ); * ``` */ mapManyFromPipeline(pipeline: (builder: PipelineBuilder) => TabularPipelineBuilder>, Record>): MappedProcessBuilder; /** @internal */ processStream(): null; /** @internal */ toTemplate(): {}; } /** @internal */ type ProcessMapping> = { mapping_type: 'value'; value: ValueTypeOf>; } | { mapping_type: 'stream'; stream: Stream>; } | { mapping_type: 'pipeline'; pipeline: GenericPipelineBuilder, Record>; } | { mapping_type: 'valueMany'; value: ValueTypeOf>>; } | { mapping_type: 'streamMany'; stream: Stream>>; } | { mapping_type: 'pipelineMany'; pipeline: TabularPipelineBuilder>, Record>; }; /** * {@inheritDoc ProcessBuilder} * * @category Process * */ declare class MappedProcessBuilder, Properties extends Record, Resources extends Record, MLs extends Record, Procs extends Record> extends AbstractProcessBuilder { private mapping; constructor(name: Name, module: ModulePath, uniqueName: string, description: string | null, values: Values, properties: Properties, resources: Resources, statements: Statement[], mls: MLs, procedures: Procs, mapping: ProcessMapping<{ date: DateTimeType; } & Values>); /** * Get the {@link Stream} continaing the process data. * * @returns a {@link Stream} * * @category Scenario * */ processStream(): Stream>>; /** * Convert the built process into an {@link Template}, for usage in * an EDK project. * * @returns a {@link Template} * * @category Scenario * */ toTemplate(): import("../template").Template; } declare class ProcessBlockBuilder, Resources extends Record, Processes extends Record>, MLs extends Record, Procs extends Record> { private label; private loop_labels; private properties; private resources; private processes; private mls; private procedures; private statements; private hasEndStatement; private n_blocks; constructor(label: string, loop_labels: string[], properties: Properties, resources: Resources, processes: Processes, mls: MLs, procedures: Procs, statements: Statement[], hasEndStatement: boolean, n_blocks: number); /** * Compute a property as an expression of existing properties. * * @param name the name of the property * @param expression the function of defining the property * * @remarks you may overwrite an existing property of the same name with a new value of any type. * * @category Process * * @example * ```typescript * // create the sales process with some properties * const sales = new ProcessBuilder("sales") * .let("revenue", () => Const(5)) * .let("cost", () => Const(6)) * .let("profit", (props) => Subtract(props.revenue, props.cost)) * .mapFromValue({ date: new Date(0) }); * ``` */ let; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(name: PropertyName, expression: Expr): ProcessBlockBuilder<(PropertyName extends keyof Properties ? Omit : Properties) & { [K in PropertyName]: Variable["type"]>; }, Resources, Processes, MLs, Procs>; /** * Reassign an existing property value with the result of an expression of existing properties. * * @param name the name of the property * @param expression the function of defining the new property value * * @remarks You must overwrite an existing property, and the value must be of the same type as that property. The `"date"` property cannot be modified. * * @category Process * * @example * ```typescript * const my_process = new ProcessBuilder("my_process") * // let x = 5 * .let("x", () => Const(5)) * // x = x + 1 * .assign("x", props => Add(props.x, 1)) * ``` */ assign; } & { [K in keyof Procs]: ProcedureEvaluator; }) => { type: SubType; ast_type: AstType; }>(name: PropertyName, expression: Expr): ProcessBlockBuilder; /** * Throw an error with a provided error message. * * @param message the error message * * @category Process * * @example * ```typescript * // create the sales process with some properties * const sales = new ProcessBuilder("sales") * // create random qty * .let("qty", () => RandomUniform(0, 1)) * .if( * (props) => Less(props.qty, 0.5), * block => block * .error((props) => StringJoin`value ${props.qty} <= 0.5`) * ) * .mapFromValue({ date: new Date(0) }); * ``` * */ error(message: ((properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction) | string): ProcessBlockBuilder; /** * Produce a warning with a message. * * @param message the error message * * @category Process * * @example * ```typescript * // create the sales process with some properties * const sales = new ProcessBuilder("sales") * // create random qty * .let("qty", () => RandomUniform(0, 1)) * .if( * (props) => Less(props.qty, 0.5), * block => block * .warn((props) => StringJoin`value ${props.qty} <= 0.5`) * ) * .mapFromValue({ date: new Date(0) }); * ``` * */ warn(message: ((properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction) | string): ProcessBlockBuilder; /** * Produce a log message. * * @param message the error message * * @category Process * * @example * ```typescript * // create the sales process with some properties * const sales = new ProcessBuilder("sales") * // create random qty * .let("qty", () => RandomUniform(0, 1)) * .if( * (props) => Less(props.qty, 0.5), * block => block * .log((props) => StringJoin`value ${props.qty} <= 0.5`) * ) * .mapFromValue({ date: new Date(0) }); * ``` * */ log(message: ((properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction) | string): ProcessBlockBuilder; /** * Set a resource value. * * @param name the {@link ResourceBuilder} name to set * @param value the function defining the value * * @remarks this overwrites the existing resource value in it's entirety, even if it is a collection. Use the`update`,`insert` or`delete` methods to modify just part of a resource. * * @category Process * * @example * ```typescript * // create a resource * const cash = new ResourceBuilder("cash") * .mapFromValue(0) * * // create the sale process * const sales = new ProcessBuilder("sales") * .resource(cash) * // set the cash balance * .set("cash", () => Const(5)) * // simulate from a date * .mapFromValue({ date: new Date(0) }); * ``` */ set; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(name: ResourceName, value: V & (Resources[ResourceName]["type"] extends ReturnType["type"] ? unknown : never)): ProcessBlockBuilder; /** * Insert a new entry into an array, set or dictionary. * * For arrays, you can insert the `"first"` or `"last"` element (i.e. push to the front or end of the array). * For sets, you can insert a new key. If the key already exists an error will result. * For dictionaries, you can insert a new key and associated value. If the key already exists an error will result (see also {@link update}). * * @param collection a function returning the array, set or dictionary to insert into * @param key the key of the item to insert * @param value the value to insert (for arrays and dictionaries only) * * @category Process * * @example * ```typescript * // create a resource * const inventory = new ResourceBuilder("inventory") * .mapFromValue(new Map([ * ["socks", { qty: 1n }], * ["chairs", { qty: 3n }] * ])) * * // add the inventory resource and insert a value * const delivery = new ProcessBuilder("delivery") * .resource(inventory) * .value("qty", IntegerType) * .value("item", StringType) * .insert( * (props, resources) => resources.inventory, * (props) => props.item, * (props) => Struct({ qty: props.qty }), * ) * .mapFromValue({ * date: new Date(0), * item: "frame", * qty: 54n * }); * ``` */ insert; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction["type"]["value"]["key"]>, value: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => { type: SubType["type"]["value"]["value"]>; ast_type: AstType; }): ProcessBlockBuilder; insert; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction["type"]["value"]>): ProcessBlockBuilder; insert; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: 'first' | 'last', value: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => { type: SubType["type"]["value"]>; ast_type: AstType; }): ProcessBlockBuilder; /** * Update an existing value in an array or dictionary. The collection will be mutated in place. * * For arrays, you can update any element by integer index (the first element has index `0n`). If the index is out of bounds an error will result. * For dictionaries, you can update any existing key to a new associated value. If the key does not exist an error will result (see also {@link `insert`}). * In both cases, you are given access the existing value when computing the new value. * * @param collection a function returning the array, set or dictionary to update * @param key the key of the item to update * @param value the value to update to * * @category Process * * @example * ```typescript * // create a resource * const inventory = new ResourceBuilder("inventory") * .mapFromValue(new Map([ * ["socks", { qty: 1n }], * ["chairs", { qty: 3n }] * ])) * * // subtract the appropriate qty from inventory * const dispatch = new ProcessBuilder("dispatch") * .resource(inventory) * .value("qty", IntegerType) * .value("item", StringType) * .update( * (props, resources) => resources.inventory, * (props) => props.item, * (props, _, _, old_value) => Struct({ qty: Subtract(GetField(old_value, "qty"), props.qty) }), * ) * .mapFromValue({ * date: new Date(0), * item: "chairs", * qty: 2n * }); * ``` **/ update; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction["type"]["value"]["key"]>, value: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }, old_value: Variable["type"]["value"]["value"]>) => { type: SubType["type"]["value"]["value"]>; ast_type: AstType; }): ProcessBlockBuilder; update; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction, value: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }, old_value: Variable["type"]["value"]>) => { type: SubType["type"]["value"]>; ast_type: AstType; }): ProcessBlockBuilder; /** * Delete an existing element from an array, set or dictionary. The collection will be mutated in place. * * For arrays, you can delete the `"first"` or `"last"` element (i.e. pop the front or end of the array). * For sets, you can delete an existing key. If the key doesn't exist an error will result. * For dictionaries, you can delete an existing key (and associated value). If the key doesn't exist an error will result. * * @param collection a function returning the array, set or dictionary to update * @param key the key of the item to delete * * @category Process * * @example * ```typescript * // create a resource * const inventory = new ResourceBuilder("inventory") * .mapFromValue(new Map([ * ["socks", { qty: 1n }], * ["chairs", { qty: 3n }] * ])) * * // unlist an item from inventory * const unlist = new ProcessBuilder("unlist") * .resource(inventory) * .value("qty", IntegerType) * .value("item", StringType) * .delete( * (props, resources) => resources.inventory, * (props) => props.item, * ) * .mapFromValue({ * date: new Date(0), * item: "socks", * }); * ``` **/ delete; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction["type"]["value"]["key"]>): ProcessBlockBuilder; delete; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction["type"]["value"]>): ProcessBlockBuilder; delete; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: C, key: 'first' | 'last'): ProcessBlockBuilder; /** * Delete all elements from an array, set or dictionary. The collection will be mutated in place. * * @param collection a function returning the array, set or dictionary to clear * * @category Function * * @example * ```typescript * // create a resource for inventory items * const inventory = new ResourceBuilder("inventory") * .mapFromValue(new Map([ * ["socks", { qty: 1n }], * ["chairs", { qty: 3n }] * ])) * * // add the inventory resource and clear all values * const dump_inventory = new ProcessBuilder("dump_inventory") * .resource(inventory) * .clear((props, resources) => resources.inventory) * .mapFromValue({ * date: new Date(0), * }); * ``` */ clear(collection: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction): ProcessBlockBuilder; /** * Execute a new process instance at a specified date. * * @param name the {@link ProcessBuilder} name to execute * @param values the values to execute the {@link ProcessBuilder} with * @param active a function if set to false will not execute the {@link ProcessBuilder} * * @remarks The `values` must be an object with at least `date`, but also any `value` property define in the {@link ProcessBuilder} being executed * * @remarks It is valid to execute another process that has been added, or call this process recursively * * @category Process * * @example * ```typescript * // create the process to be added * const receive_items = new ProcessBuilder("receive items") * .value("qty", FloatType) * .log({ * message: (props) => StringJoin`Recieved ${props.qty} items` * }) * * // add a process to another and execute an hour after * const sales = new ProcessBuilder("sales") * .process(receive_items) * .execute("receive items", (props) => Struct({ * date: AddDuration(props.date, 1, 'hour'), * qty: Const(5) * })) * .mapFromValue({ date: new Date(0) }); * ``` * * @example * ```typescript * * // execute the sales process recursively every minute until an hour passes * const sales = new ProcessBuilder("sales") * .execute("sales", (props) => Struct({ * date: AddDuration(props.date, 1, 'minute'), * })) * // note that `new Date(3600000)` will be constant in the simulation * .endSimulation((props) => Greater(props.date, new Date(3600000))) * .mapFromValue({ date: new Date(0) }); * ``` */ execute; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>>(name: ProcessName, values: V & (StructType<{ date: DateTimeType; } & Processes[ProcessName]> extends ReturnType["type"] ? unknown : never)): ProcessBlockBuilder; /** * Execute blocks of statements conditional on some predicate (Boolean) expression. * * @param predicate a function that returns a `BooleanType` expression of properties and resources * @param true_block a function that returns a block of statements to be executed if the `predicate` is `true`. * @param false_block an optional function that returns a block of statements to be executed if the `predicate` is `false`. * * @category Process * * @example * ```typescript * // stock level of products to sell * const stock = new ResourceBuilder("stock") * .fromValue(100.0) * * // sales reduces stock level * const sales = new ProcessBuilder("sales") * .resource(stock) * .value("qty", FloatType) * // only deduct stock if qty is non-zero * .if( * props => Greater(qty, 0.0), * block => block * .set("stock", (props, resources) => Subtract(resources.stock, props.qty)) * ) * ``` */ if(predicate: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction, true_block: (block: ProcessBlockBuilder) => ProcessBlockBuilder, Resources, Processes, MLs, Procs>, false_block?: (block: ProcessBlockBuilder) => ProcessBlockBuilder, Resources, Processes, MLs, Procs>): ProcessBlockBuilder; /** * Execute blocks of statements conditional on some input being null or not. * * @param input a function that returns a `Nullable` expression of properties and resources * @param null_block a function that returns a block of statements to be executed if the `input` is `null`. * @param value_block an optional function that returns a block of statements to be executed if the `input` is not `null`. The input value is available as a non-nullable variable. * * @category Process * * @example * ```typescript * // stock level of products to sell * const stock = new ResourceBuilder("stock") * .fromValue(100.0) * * // sales reduces stock level (but only qty is not null) * const sales = new ProcessBuilder("sales") * .resource(stock) * .value("qty", Nullable(FloatType)) * // only deduct stock if qty is non-zero * .ifNull( * props => qty, * block => block, * block => block, * .set("stock", (props, resources) => Subtract(resources.stock, props.qty)) * ) * ``` */ ifNull; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(input: I, null_block: (block: ProcessBlockBuilder) => ProcessBlockBuilder, Resources, Processes, MLs, Procs>, value_block?: (block: ProcessBlockBuilder, value: Variable["type"]>>) => ProcessBlockBuilder, Resources, Processes, MLs, Procs>): ProcessBlockBuilder; /** * Perform blocks of statements matched on the cases of some variant expression. * * @param variant a function that returns a `VariantType` expression of properties and resources * @param cases an object containing functions that return a block of statements to be executed for the given variant case * * @category Process * * @example * ```typescript * // sales produes a log message about the buyer * const sales = new ProcessBuilder("sales") * .value("buyer_name", MaybeType(StringType)) * .let("message", _ => Const("")) * .match( * (_, resources) => resources.buyer, * { * Some: (block, name) => block.assign("message", _ => StringJoin`Initiating sale to ${name}`), * None: (block) => block.assign("message", _ => StringJoin`Initiating sale to unknown buyer`), * } * ) * ``` */ match; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction, T extends { [K in keyof ReturnType["type"]["value"]]: (block: ProcessBlockBuilder, data: Variable["type"]["value"][K]>) => ProcessBlockBuilder, Resources, Processes, MLs, Procs>; }>(variant: V, cases: T): ProcessBlockBuilder; /** * Repeatedly perform a block of statements, conditional on some predicate (Boolean) expression. * * @param predicate a function that returns a `BooleanType` expression of properties and resources * @param loop_block a function that returns a block of statements to be executed repeatedly until the `predicate` is `false`. * * @category Process * * @example * ```typescript * // perform a loop from i = 0 to 10 * new ProcessBuilder("my_process") * .let("i", 0n) * .while( * props => LessEqual(props.i, 10n), * block => block * .assign("i", props => Add(props.i, 1n)) * ) * ``` */ while(predicate: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction, loop_block: (block: ProcessBlockBuilder) => ProcessBlockBuilder, Resources, Processes, MLs, Procs>): ProcessBlockBuilder; /** * Perform a block of statements for each item in an array. * * @param collection a function that returns an array expression of properties and resources * @param loop_block a function that returns a block of statements to be executed for each element of a collection. * * @category Process * * @example * ```typescript * // log out all indices and values of an array * new ProcessBuilder("my_process") * .let("array", _ => Const(["a", "b", "c"])) * .forArray( * props => props.array, * (block, value, key) => block * .log({ * message: () => StringJoin`Index ${key} contains string ${value}` * }) * ) * ``` */ forArray; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: Collection, loop_block: (block: ProcessBlockBuilder, value: Variable["type"]["value"]>, key: Variable) => ProcessBlockBuilder, Resources, Processes, MLs, Procs>): ProcessBlockBuilder; /** * Perform a block of statements for each item in a set. * * @param collection a function that returns an set expression of properties and resources * @param loop_block a function that returns a block of statements to be executed for each element of a collection. * * @category Process * * @example * ```typescript * // log out all keys of a set * new ProcessBuilder("my_process") * .let("set", _ => Const(new Set(["a", "b", "c"]))) * .forSet( * props => props.set, * (block, key) => block * .log({ * message: () => StringJoin`Key ${key}` * }) * ) * ``` */ forSet; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: Collection, loop_block: (block: ProcessBlockBuilder, key: Variable["type"]["value"]>) => ProcessBlockBuilder, Resources, Processes, MLs, Procs>): ProcessBlockBuilder; /** * Perform a block of statements for each item in a dictionary. * * @param collection a function that returns a dictionary expression of properties and resources * @param loop_block a function that returns a block of statements to be executed for each element of a collection. * * @category Process * * @example * ```typescript * // log out all keys and values of an dictionary * new ProcessBuilder("my_process") * .let("dict", _ => Const(new Map([["a", 1n], ["b", 2n], ["c", 3n]])) * .forDict( * props => props.dict, * (block, value, key) => block * .log({ * message: () => StringJoin`Key ${key} contains value ${value}` * }) * ) * ``` */ forDict; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction>(collection: Collection, loop_block: (block: ProcessBlockBuilder, value: Variable["type"]["value"]["value"]>, key: Variable["type"]["value"]["key"]>) => ProcessBlockBuilder, Resources, Processes, MLs, Procs>): ProcessBlockBuilder; /** * Continue with the next iteration of a while or for loop, skipping the rest of this iteration. * * @param block the builder for the block to break from * * @category Process * * @example * ```typescript * // perform a loop from i = 0 to 10 and log the even numbers * new ProcessBuilder("my_process") * .let("i", 0n) * .while( * props => Const(LessEqual(i, 10)), * while_block => while_block * .assign("i", props => Add(props.i, 1n)) * .if( * props => Equal(Modulo(props.i, 2n), 1n) * if_block => if_block.continue(while_block) * ) * .log({ * message: props => StringJoin`Found even integer ${props.i}`, * }) * ) * ``` */ continue(block: ProcessBlockBuilder): ProcessBlockBuilder; /** * Break from a while or for loop. * * @param block the builder for the block to break from * * @category Process * * @example * ```typescript * // perform a loop from i = 0 to 10 * new ProcessBuilder("my_process") * .let("i", 0n) * .while( * props => Const(true), * while_block => while_block * .assign("i", props => Add(props.i, 1n)) * .if( * props => GreaterEqual(props.i, 10n) * if_block => if_block.break(while_block) * ) * ) * ``` */ break(block: ProcessBlockBuilder): ProcessBlockBuilder; /** * End the **entire** simulation immediately. A user-defined predicate may be provided to control when this does or does not occur. * * @param predicate a function if set to true will end the **entire** simulation * * @remarks Any later statements in this process instance will not be executed. * * @remarks Once triggered this will end the **entire** simulation. * * @category Process * * @example * ```typescript * // create the sale process * const sales = new ProcessBuilder("sales") * // create another sale * .execute( * "sales", * (props) => Struct({ * date: AddDuration( * props.date, * RandomExponential(), * 'hour' * ), * }) * ) * // end after an hour * .endSimulation((props) => Greater(props.date, new Date(3600000))) * // start simulating from a date * .mapFromValue({ date: new Date(0) }); * ``` */ endSimulation(predicate?: (properties: Properties, resources: Resources, procs: { [K in keyof MLs]: MLEvaluator; } & { [K in keyof Procs]: ProcedureEvaluator; }) => EastFunction): ProcessBlockBuilder; } export {};