pddl-workspace
Version:
358 lines • 21.3 kB
JavaScript
"use strict";
/* --------------------------------------------------------------------------------------------
* Copyright (c) Jan Dolejsi. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
Object.defineProperty(exports, "__esModule", { value: true });
exports.JobSchedulingSyntaxInjector = void 0;
const Compilations_1 = require("../Compilations");
const expression_1 = require("../expression");
const language_1 = require("../language");
const parser_1 = require("../parser");
const SyntaxInjector_1 = require("./SyntaxInjector");
/** Injects auto-generated code triggered by the :job-scheduling requirement/ontology. */
class JobSchedulingSyntaxInjector extends SyntaxInjector_1.BaseSyntaxInjector {
process(domainInfo, positionResolver) {
if (!domainInfo.getRequirements().includes(JobSchedulingSyntaxInjector.JOB_SCHEDULING)) {
return;
}
this.replaceRequirement(domainInfo, positionResolver);
this.injectTypes(domainInfo, positionResolver);
this.injectPredicatesAndFunctions(domainInfo, positionResolver);
if (!domainInfo.getActions().find(a => a.name === 'move')) {
this.injectMoveAction(domainInfo, positionResolver);
}
}
replaceRequirement(domainInfo, positionResolver) {
const origRequirements = new Set(domainInfo.getRequirements());
const replacementRequirements = JobSchedulingSyntaxInjector.JOB_SCHEDULING_IMPLIED_REQS
.filter(r => !origRequirements.has(r))
.join(' ');
const requirementsNode = domainInfo.getRequirementsNode();
if (!requirementsNode) {
return;
}
const jobSchedulingNode = requirementsNode.getChildren()
.find(node => node.getToken().tokenText.toLowerCase() === ':job-scheduling');
if (!jobSchedulingNode) {
return;
}
const replacement = new Compilations_1.CodeReplacement({
origCode: jobSchedulingNode.getToken().tokenText,
newCode: replacementRequirements,
documentation: { title: 'Implied requirements' },
offset: this.getOffset(jobSchedulingNode, positionResolver, { position: SyntaxInjector_1.InjectionPosition.OutsideStart }),
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
});
domainInfo.getCompilations().add(replacement);
}
injectPredicatesAndFunctions(domainInfo, positionResolver) {
var _a, _b, _c, _d, _e, _f;
const predicates = [
JobSchedulingSyntaxInjector.IS_AVAILABLE_PREDICATE,
JobSchedulingSyntaxInjector.LOCATED_AT_PREDICATE,
JobSchedulingSyntaxInjector.CONTAINS_PREDICATE,
JobSchedulingSyntaxInjector.BUSY_PREDICATE
];
const functions = [
JobSchedulingSyntaxInjector.TRAVEL_TIME_FUNCTION,
JobSchedulingSyntaxInjector.TIME_STEPS_PER_DAY_FUNCTION,
JobSchedulingSyntaxInjector.TIME_STEP_IN_DAYS_FUNCTION,
];
const resourceTypes = new Set(domainInfo.getTypesInheritingFromPlusSelf(JobSchedulingSyntaxInjector.RESOURCE));
const locationTypes = new Set(domainInfo.getTypesInheritingFromPlusSelf(JobSchedulingSyntaxInjector.LOCATION));
const jobDecorations = ((_a = domainInfo.getJobs()) !== null && _a !== void 0 ? _a : [])
.map(j => this.compileJob(j, locationTypes, resourceTypes, positionResolver));
jobDecorations.forEach(jd => {
predicates.push(...jd.generatedPredicates);
functions.push(...jd.generatedFunctions);
});
// inject the accumulated predicates
this.injectVariables(domainInfo.getPredicatesNode(), (_c = (_b = domainInfo.getConstantsNode()) !== null && _b !== void 0 ? _b : domainInfo.getTypesNode()) !== null && _c !== void 0 ? _c : domainInfo.getRequirementsNode(), positionResolver, predicates, 'Predicates', 'predicates', (i) => domainInfo.injectPredicates(i));
// inject the accumulated functions
this.injectVariables(domainInfo.getFunctionsNode(), (_f = (_e = (_d = domainInfo.getPredicatesNode()) !== null && _d !== void 0 ? _d : domainInfo.getConstantsNode()) !== null && _e !== void 0 ? _e : domainInfo.getTypesNode()) !== null && _f !== void 0 ? _f : domainInfo.getRequirementsNode(), positionResolver, functions, 'Functions', 'functions', (i) => domainInfo.injectFunctions(i));
jobDecorations
.flatMap(jd => jd.injections)
.forEach(c => domainInfo.getCompilations().add(c));
}
injectVariables(variablesNode, precedingNode, positionResolver, variables, docTitle, pddlPrefix, injectionMethod) {
const doc = { title: this.createHoverTitle(docTitle) };
if (variablesNode) {
injectionMethod(new Compilations_1.VariableDeclarationsInjection({
documentation: doc,
offset: this.getOffset(variablesNode, positionResolver, { position: SyntaxInjector_1.InjectionPosition.InsideEnd }),
variables: variables,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING
}));
}
else if (precedingNode) {
injectionMethod(new Compilations_1.VariableDeclarationsInjection({
documentation: doc,
offset: this.getOffset(precedingNode, positionResolver, { position: SyntaxInjector_1.InjectionPosition.OutsideEnd }),
variables: variables,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
prefix: `(:${pddlPrefix} `,
suffix: ')',
}));
}
}
injectTypes(domainInfo, positionResolver) {
const types = domainInfo.getTypeInheritance();
types.addEdge(JobSchedulingSyntaxInjector.AVAILABLE, parser_1.PddlInheritanceParser.OBJECT);
types.addEdge(JobSchedulingSyntaxInjector.LOCATION, JobSchedulingSyntaxInjector.AVAILABLE);
types.addEdge(JobSchedulingSyntaxInjector.RESOURCE, JobSchedulingSyntaxInjector.AVAILABLE);
const typesNode = domainInfo.getTypesNode();
const hover = this.createHoverTitle('Types');
const injectedCode = `${JobSchedulingSyntaxInjector.LOCATION} ${JobSchedulingSyntaxInjector.RESOURCE} - ${JobSchedulingSyntaxInjector.AVAILABLE}`;
if (typesNode) {
domainInfo.getCompilations().add(new Compilations_1.PddlCodeInjection({
documentation: { title: hover },
offset: this.getOffset(typesNode, positionResolver, { position: SyntaxInjector_1.InjectionPosition.InsideStart }),
code: injectedCode,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
}));
}
else {
const precedingNode = domainInfo.getRequirementsNode();
precedingNode && domainInfo.getCompilations().add(new Compilations_1.PddlCodeInjection({
documentation: { title: hover },
offset: this.getOffset(precedingNode, positionResolver, { position: SyntaxInjector_1.InjectionPosition.OutsideEnd }),
code: `(:types ${injectedCode})`,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
}));
}
}
compileJob(job, locationTypes, resourceTypes, positionResolver) {
var _a, _b, _c;
const decoration = new JobDecoration();
const actionNode = job.actionNode;
const parametersNode = job.parametersNode;
if (!actionNode || !parametersNode) {
return decoration;
}
// replace :job by :durative-action
decoration.add(new Compilations_1.CodeReplacement({
origCode: actionNode.getToken().tokenText,
newCode: ':durative-action ',
offset: actionNode.getStart() + 1,
documentation: {
title: 'Job is a simplified durative action', codeblock: `:durative-action`,
},
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING
}));
if (!job.duration) {
const durationDef = ':duration ' + new expression_1.EqualityNode(new expression_1.DurationExpressionNode(), new expression_1.VariableNode(decoration.createDurationVariable(job, resourceTypes))).toPddlString();
decoration.add(new Compilations_1.PddlCodeInjection({
offset: this.getOffset(parametersNode, positionResolver, { position: SyntaxInjector_1.InjectionPosition.OutsideEnd }),
code: durationDef,
documentation: { title: 'Suggested job duration definition', codeblock: durationDef },
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
}));
}
const availabilityVariables = [];
// the location shall be available
const locationParameter = job.parameters.find(p => locationTypes.has(p.type));
if (locationParameter) {
const locationIsAvailable = JobSchedulingSyntaxInjector.IS_AVAILABLE_PREDICATE.bind([locationParameter]);
availabilityVariables.push(locationIsAvailable);
}
const resourcesAtLocation = [];
// all resources shall be available and at the location
job.parameters
.filter(p => resourceTypes.has(p.type))
.forEach(p => {
const resourceIsAvailable = JobSchedulingSyntaxInjector.IS_AVAILABLE_PREDICATE.bind([p]);
availabilityVariables.push(resourceIsAvailable);
if (locationParameter) {
const resourceAtLocation = JobSchedulingSyntaxInjector.LOCATED_AT_PREDICATE.bind([p, locationParameter]);
resourcesAtLocation.push(resourceAtLocation);
}
});
const conditions = [...availabilityVariables.map(v => (0, expression_1.overAll)((0, expression_1.expression)(v)))];
conditions.push(...resourcesAtLocation.map(p => (0, expression_1.overAll)((0, expression_1.expression)(p))));
const jobStarted = decoration.createActionPredicate(job, JobSchedulingSyntaxInjector.JOB_STARTED_SUFFIX, resourceTypes);
const jobDone = decoration.createActionPredicate(job, JobSchedulingSyntaxInjector.JOB_DONE_SUFFIX, resourceTypes);
conditions.push((0, expression_1.atStart)((0, expression_1.not)(jobStarted)), (0, expression_1.atStart)((0, expression_1.not)(jobDone)));
const effects = [];
effects.push((0, expression_1.atStart)((0, expression_1.expression)(jobStarted)), (0, expression_1.atEnd)((0, expression_1.expression)(jobDone)));
availabilityVariables.forEach(e => {
effects.push((0, expression_1.atStart)((0, expression_1.not)(e)));
effects.push((0, expression_1.atEnd)((0, expression_1.expression)(e)));
});
const conditionDocumentation = {
title: 'Auto-generated conditions',
codeblock: conditions.map(c => c.toPddlString()).join('\n'),
};
if (job.condition) {
const conjunction = job.condition.getFirstOpenBracket('and');
if (conjunction) {
// inject into the :condition (and ...) conjunction
decoration.add(new Compilations_1.PddlCodeInjection({
offset: this.getOffset(conjunction, positionResolver, { position: SyntaxInjector_1.InjectionPosition.InsideEnd }),
code: conditions.map(c => c.toPddlString()).join(' '),
documentation: conditionDocumentation,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
}));
}
else {
// inject into :condition
decoration.add(new Compilations_1.PddlCodeInjection({
offset: this.getOffset(job.condition, positionResolver, { position: SyntaxInjector_1.InjectionPosition.InsideEnd }),
code: (0, expression_1.and)(conditions).toPddlString(),
documentation: conditionDocumentation,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
}));
}
}
else {
// inject the :condition to the end of the action
decoration.add(new Compilations_1.PddlCodeInjection({
offset: this.getOffset((_a = job.duration) !== null && _a !== void 0 ? _a : parametersNode, positionResolver, { position: SyntaxInjector_1.InjectionPosition.OutsideEnd }),
code: ':condition ' + (0, expression_1.and)(conditions).toPddlString(),
documentation: conditionDocumentation,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
}));
}
const effectDocumentation = {
title: 'Auto-generated effect',
codeblock: effects.map(e => e.toPddlString()).join('\n'),
};
if (job.effect) {
const conjunction = job.effect.getFirstOpenBracket('and');
if (conjunction) {
// inject into the :effect (and ...) conjunction
decoration.add(new Compilations_1.PddlCodeInjection({
offset: this.getOffset(conjunction, positionResolver, { position: SyntaxInjector_1.InjectionPosition.InsideEnd }),
code: effects.map(c => c.toPddlString()).join(' '),
documentation: effectDocumentation,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
}));
}
else {
// inject into the :effect
decoration.add(new Compilations_1.PddlCodeInjection({
offset: this.getOffset(job.effect, positionResolver, { position: SyntaxInjector_1.InjectionPosition.InsideEnd }),
code: (0, expression_1.and)(effects).toPddlString(),
documentation: effectDocumentation,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
}));
}
}
else {
// inject the :effect to the end of the action
decoration.add(new Compilations_1.PddlCodeInjection({
offset: this.getOffset((_c = (_b = job.condition) !== null && _b !== void 0 ? _b : job.duration) !== null && _c !== void 0 ? _c : parametersNode, positionResolver, { position: SyntaxInjector_1.InjectionPosition.OutsideEnd }),
code: ':effect ' + (0, expression_1.and)(effects).toPddlString(),
documentation: effectDocumentation,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
}));
}
return decoration;
}
injectMoveAction(domainInfo, positionResolver) {
const resParam = new language_1.Parameter('res', JobSchedulingSyntaxInjector.RESOURCE);
const fromParam = new language_1.Parameter('from', JobSchedulingSyntaxInjector.LOCATION);
const toParam = new language_1.Parameter('to', JobSchedulingSyntaxInjector.LOCATION);
const params = `(${resParam.toPddlString()} ${language_1.Parameter.createPddlString(fromParam, toParam)})`;
const durationVar = JobSchedulingSyntaxInjector.TRAVEL_TIME_FUNCTION.bind([resParam, fromParam, toParam]);
const duration = new expression_1.EqualityNode(new expression_1.DurationExpressionNode(), new expression_1.VariableNode(durationVar)).toPddlString();
const condition = (0, expression_1.and)([
(0, expression_1.atStart)((0, expression_1.not)(JobSchedulingSyntaxInjector.BUSY_PREDICATE.bind([resParam]))),
(0, expression_1.atStart)((0, expression_1.expression)(JobSchedulingSyntaxInjector.LOCATED_AT_PREDICATE.bind([resParam, fromParam]))),
]).toPddlString();
const effect = (0, expression_1.and)([
(0, expression_1.atStart)((0, expression_1.not)(JobSchedulingSyntaxInjector.LOCATED_AT_PREDICATE.bind([resParam, fromParam]))),
(0, expression_1.atStart)((0, expression_1.expression)(JobSchedulingSyntaxInjector.LOCATED_AT_PREDICATE.bind([resParam, toParam]))),
]).toPddlString();
const moveAction = `(:durative-action move :parameters ${params} :duration ${duration} :condition ${condition} :effect ${effect})`;
domainInfo.getCompilations().add(new Compilations_1.CodeInjection({
offset: this.getOffset(domainInfo.syntaxTree.getDefineNode(), positionResolver, { position: SyntaxInjector_1.InjectionPosition.InsideEnd }),
code: moveAction,
documentation: {
title: this.createHoverTitle('Resource move action')
},
doesNotRequireWhitespaceSurrounding: true,
reason: JobSchedulingSyntaxInjector.JOB_SCHEDULING,
}));
}
createHoverTitle(generatedEntitiesName) {
return generatedEntitiesName + " auto-generated because of the `" + JobSchedulingSyntaxInjector.JOB_SCHEDULING + "` requirement:";
}
}
exports.JobSchedulingSyntaxInjector = JobSchedulingSyntaxInjector;
/* TYPES */
JobSchedulingSyntaxInjector.AVAILABLE = 'available';
JobSchedulingSyntaxInjector.RESOURCE = 'resource';
JobSchedulingSyntaxInjector.LOCATION = 'location';
/* PREDICATE NAMES */
JobSchedulingSyntaxInjector.IS_AVAILABLE_PREDICATE_NAME = 'is_available';
JobSchedulingSyntaxInjector.IS_AVAILABLE_PREDICATE = language_1.Variable.from(JobSchedulingSyntaxInjector.IS_AVAILABLE_PREDICATE_NAME, [
new language_1.Parameter('a', JobSchedulingSyntaxInjector.AVAILABLE)
]);
JobSchedulingSyntaxInjector.LOCATED_AT_PREDICATE_NAME = 'located_at';
/** (located_at ?r - resource ?l - location) */
JobSchedulingSyntaxInjector.LOCATED_AT_PREDICATE = language_1.Variable.from(JobSchedulingSyntaxInjector.LOCATED_AT_PREDICATE_NAME, [
new language_1.Parameter('r', JobSchedulingSyntaxInjector.RESOURCE),
new language_1.Parameter('l', JobSchedulingSyntaxInjector.LOCATION)
]);
JobSchedulingSyntaxInjector.BUSY_PREDICATE_NAME = 'busy';
/** (busy ?r - resource) */
JobSchedulingSyntaxInjector.BUSY_PREDICATE = language_1.Variable.from(JobSchedulingSyntaxInjector.BUSY_PREDICATE_NAME, [
new language_1.Parameter('r', JobSchedulingSyntaxInjector.RESOURCE)
]);
JobSchedulingSyntaxInjector.CONTAINS_PREDICATE_NAME = "contains";
/** (contains ?parent ?child - location) */
JobSchedulingSyntaxInjector.CONTAINS_PREDICATE = language_1.Variable.from(JobSchedulingSyntaxInjector.CONTAINS_PREDICATE_NAME, [
new language_1.Parameter('parent', JobSchedulingSyntaxInjector.LOCATION),
new language_1.Parameter('child', JobSchedulingSyntaxInjector.LOCATION),
]);
JobSchedulingSyntaxInjector.JOB_STARTED_SUFFIX = '_job_started';
JobSchedulingSyntaxInjector.JOB_DONE_SUFFIX = '_job_done';
/* FUNCTION NAMES */
JobSchedulingSyntaxInjector.JOB_DURATION_SUFFIX = '_job_duration';
JobSchedulingSyntaxInjector.TRAVEL_TIME = 'travel_time';
/** (travel_time ?r - resource ?from ?to - location) */
JobSchedulingSyntaxInjector.TRAVEL_TIME_FUNCTION = language_1.Variable.from(JobSchedulingSyntaxInjector.TRAVEL_TIME, [
new language_1.Parameter('r', JobSchedulingSyntaxInjector.RESOURCE),
new language_1.Parameter('from', JobSchedulingSyntaxInjector.LOCATION),
new language_1.Parameter('to', JobSchedulingSyntaxInjector.LOCATION)
]);
JobSchedulingSyntaxInjector.TIME_STEPS_PER_DAY = 'time_steps_per_day';
JobSchedulingSyntaxInjector.TIME_STEP_IN_DAYS = 'time_step_in_days';
/** (time_steps_per_day) ; number of time steps per day */
JobSchedulingSyntaxInjector.TIME_STEPS_PER_DAY_FUNCTION = language_1.Variable.from(JobSchedulingSyntaxInjector.TIME_STEPS_PER_DAY, []);
/** (time_step_in_days) ; time step length in [day] unit */
JobSchedulingSyntaxInjector.TIME_STEP_IN_DAYS_FUNCTION = language_1.Variable.from(JobSchedulingSyntaxInjector.TIME_STEP_IN_DAYS, []);
JobSchedulingSyntaxInjector.JOB_SCHEDULING = ':job-scheduling';
/** PDDL Requirements that are implied by the :job-scheduling and therefore should be inserted in its place */
JobSchedulingSyntaxInjector.JOB_SCHEDULING_IMPLIED_REQS = [
':strips', ':fluents', ':durative-actions', ':typing', ':negative-preconditions'
];
class JobDecoration {
constructor() {
this.injections = [];
this.generatedPredicates = [];
this.generatedFunctions = [];
}
add(injection) {
this.injections.push(injection);
}
createDurationVariable(action, resourceTypes) {
const suffix = JobSchedulingSyntaxInjector.JOB_DURATION_SUFFIX;
return this.createActionFunction(action, suffix, resourceTypes);
}
createActionFunction(action, suffix, resourceTypes) {
const newFunction = this.createActionVariable(action, suffix, resourceTypes);
this.generatedFunctions.push(newFunction);
return newFunction;
}
createActionPredicate(action, suffix, resourceTypes) {
const newPredicate = this.createActionVariable(action, suffix, resourceTypes);
this.generatedPredicates.push(newPredicate);
return newPredicate;
}
createActionVariable(action, suffix, resourceTypes) {
return language_1.Variable.from(action.name + suffix, action.parameters.filter(p => !resourceTypes.has(p.type)));
}
}
//# sourceMappingURL=JobSchedulingSyntaxInjector.js.map