Skip to content

jan-dolejsi/pddl-workspace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PDDL parsing and workspace

CI npm

Install this package using npm install pddl-workspace.

PDDL Parser

Disclaimer: this is not a full PDDL syntax parser. Its purpose is to provide language support in VS Code, so mode than a parser, it is a syntax tree builder. In other words, the parser does not give access to complete PDDL object model, but works even in incomplete or syntactically incorrect documents. You could however successfully use it to extract predicates, functions, actions from the PDDL files.

Example usage:

import { parser, DomainInfo, ProblemInfo, Plan, Happening, HappeningType, utils } from 'pddl-workspace';

const domain = parser.PddlDomainParser.parseText(domainText);
const problem = await parser.PddlProblemParser.parseText(problemText);
const epsilon = 0.001;

const planText = `
;;!domain: domain1
;;!problem: problem1

0.00100: (action p1 p2) [10.00]

; Makespan: 10.001
; Cost: 123.456
; States evaluated: 2`;

const plan = new parser.PddlPlanParser().parseText(planText, epsilon);

Many more usage scenarios are exercised in the unit tests in the test folder.

Plans may appear in number of different formats. Following forms are supported:

(action)
(action objects)
time: (action)
time: (action) [duration]
time: (action) [D:<duration>; C:<actionCost>]

PDDL Numeric Expression Parser

PDDL problem files support multiple (:metric ) elements (because VAL does as well). The numeric expression inside the metric is parsed to a syntax tree. The parser is available:

const expressionPddl = "(/ (- (cost) (minCost)) 2)";

const expression = createNumericExpressionParser(expressionPddl).getExpression();

const division = expression as Division;
division.getVariableNames(); // returns ['cost', 'minCost']

const context = new ValueMap("cost", 3, "minCost", 2);
division.evaluate(context); // returns 0.5

function createNumericExpressionParser(metricPddl: string): NumericExpressionParser {
    const syntaxTree = new PddlSyntaxTreeBuilder(metricPddl).getTree();
    return new NumericExpressionParser(
        syntaxTree.getRootNode().getSingleNonWhitespaceChild());
}

PDDL Workspace

The workspace groups features necessary for interactive authoring of PDDL files. And management of such files. The PddlWorkspace class is used by the VS Code PDDL extension.

import { URI } from 'vscode-uri';
const pddlWorkspace = new PddlWorkspace(1e-3);
const insertedFiles: FileInfo[] = [];

// get notified about new/updated files
pddlWorkspace.on(PddlWorkspace.INSERTED, (file: FileInfo) => {
    console.log(`Inserted: '${file.name}' from ${file.fileUri}.`);
})

pddlWorkspace.on(PddlWorkspace.UPDATED, (file: FileInfo) => {
    console.log(`Updated: '${file.name}' from ${file.fileUri}.`);
})

const pddlDomainText = `(define (domain domain_name) )`;
const pddlProblemText = `(define (problem p1) (:domain domain_name))`;

// WHEN
const domainInfo = await pddlWorkspace.upsertFile(
    URI.parse('file:///folder1/domain.pddl'),
    PddlLanguage.PDDL,
    1, // content version
    pddlDomainText,
    new SimpleDocumentPositionResolver(pddlDomainText));

const problemInfo = await pddlWorkspace.upsertFile(
    URI.parse('file:///folder1/problem.pddl'),
    PddlLanguage.PDDL,
    1, // content version
    pddlProblemText,
    new SimpleDocumentPositionResolver(pddlProblemText));

const correspondingDomain = pddlWorkspace.getDomainFileFor(problemInfo as ProblemInfo);

// now do something like `solve(correspondingDomain, problemInfo)`

Extending PDDL Workspace with custom syntaxes and functionality

Creators of non-standard PDDL syntaxes, parsers, planning enginens can inject their extensions to the PddlWorkspace. Here is how (full working code is in CustomPddlParserExtension.ts):

class CustomPddlFile extends FileInfo {
    getLanguage(): PddlLanguage {
        return PddlLanguage.PDDL;
    }
}

class CustomParser extends PddlFileParser<CustomPddlFile> {
    async tryParse(fileUri: URI, fileVersion: number, fileText: string, syntaxTree: PddlSyntaxTree, positionResolver: DocumentPositionResolver): Promise<CustomPddlFile | undefined> {
        if ('(:custom-pddl') {
            return new CustomPddlFile(fileUri, fileVersion, 'custom', syntaxTree, positionResolver);
        }
    }
}

class CustomExtension implements PddlWorkspaceExtension {
    getPddlParsers(): PddlFileParser<FileInfo>[] | undefined {
        return [new CustomParser()];
    }
}

const pddlWorkspace = new PddlWorkspace(1e-3);
pddlWorkspace.addExtension(new CustomExtension());
const pddlText = `(:custom-pddl)`;

// WHEN
const parsedFile = await pddlWorkspace.upsertFile(URI.parse('file:///test'), PddlLanguage.PDDL, 1, pddlText, new SimpleDocumentPositionResolver(pddlText));

Extending PDDL VS Code Extension with custom planner configuration providers

The pddl-workspace package is the external API of the PDDL VS Code extension. To make it convenient for your users to configure and use your planner in VS Code, implement the PlannerProvider interface (see full working code in CustomPlannerProvider.ts):

export const plannerKind = new planner.PlannerKind("my-planning-service");

export class SolveServicePlannerProvider implements planner.PlannerProvider {
    get kind(): planner.PlannerKind {
        return plannerKind;
    }
    getNewPlannerLabel(): string {
        return "$(cloud-upload) Input a planning service URL...";
    }

    async configurePlanner(previousConfiguration?: planner.PlannerConfiguration): Promise<planner.PlannerConfiguration | undefined> {
        const existingValue = previousConfiguration?.url ?? "http://solver.planning.domains/solve";

        const previouslyUsedUri = URI.parse(existingValue);

        console.log(`Previously, you configured ${previouslyUsedUri.toString()}, what do you want to change it to?`);

        // let's pretend the user entered 'http://solver.planning.domains/solve'
        const newPlannerUrl = 'http://solver.planning.domains/solve';

        return this.createPlannerConfiguration(newPlannerUrl);
    }

    createPlannerConfiguration(newPlannerUrl: string): planner.PlannerConfiguration {
        return {
            kind: this.kind.kind,
            url: newPlannerUrl,
            title: newPlannerUrl,
            canConfigure: true
        };
    }
}


/**
 * Example custom Planner Provider extension.
 */
export class CustomPlannerProviderExtension implements PddlWorkspaceExtension {
    getPlannerProvider(): PlannerProvider[] | undefined {
        return [new SolveServicePlannerProvider()];
    }
}

Starting from version 3.5.0, the PlannerProvider may optionally also implement custom creation of the Planner. Here is an example for composing java -jar xyz.jar command-line:

    createPlanner(configuration: planner.PlannerConfiguration, , plannerInvocationOptions: planner.PlannerRunConfiguration): planner.Planner {
        return new PlannerExecutable(`java -jar ${configuration.path}`, plannerInvocationOptions.options, configuration.syntax, plannerInvocationOptions.workingDirectory);
    }

Compiling and contributing

Install node.js 18.16.

About

PDDL parsing and multi-file work-space logic

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published