Skip to main content

S3E: Semantic Symbolic State Estimation

License

Overview

s3e is a Python package for estimating grounded PDDL state predicates from images using vision-language models (VLMs).

It is designed for workflows that need to connect visual observations to symbolic planning. Given a PDDL domain and problem, s3e enumerates grounded predicates, translates them into model-friendly queries, and returns either boolean state assignments, per-predicate probabilities, or normalized model outputs suitable for inspection and debugging.

The package integrates naturally with Unified Planning / PDDL-based systems and supports both HuggingFace and OpenAI-backed VLMs, as well as custom backends.

For a longer tutorial, see the tutorial notebook.

Features

  • Estimate boolean symbolic states or probabilistic predicate values from one or more images.
  • Parse PDDL domains and problems from strings or .pddl files.
  • Automatically ground predicates over the current problem objects.
  • Translate predicates with pluggable strategies: IdentityTranslator, TemplateTranslator, PrewrittenTranslator, and LLMTranslator.
  • Use HuggingFace VLMs, OpenAI VLMs, or custom implementations via the VLMBackend interface.
  • Support multi-image estimation with either single-pass or per-image averaging.
  • Expose normalized VLMOutput objects for prompt tuning and backend inspection.
  • Convert estimated states back into Unified Planning-compatible state objects.
  • Cache LLM-generated predicate translations for reuse across runs.

Installation

Prerequisites

  • Python >=3.10
  • pip
  • git if installing from source
  • For larger HuggingFace VLMs, a GPU-capable PyTorch environment is recommended

Install from source

git clone https://github.com/CLAIR-LAB-TECHNION/s3e.git
cd s3e
pip install -e .

You can also install directly from the GitHub repository without cloning:

pip install "git+https://github.com/CLAIR-LAB-TECHNION/s3e.git"

Optional dependencies

Install OpenAI support:

pip install -e '.[openai]'

Install development dependencies:

pip install -e '.[dev]'

Optional acceleration for supported HuggingFace models:

FlashAttention installation is platform- and hardware-dependent. If your chosen model and environment support it, follow the installation guide to set it up.

Quick Start / Usage

The example below uses a small HuggingFace model and template-based predicate translation.

from PIL import Image

from s3e import SemanticStateEstimator, TemplateTranslator

domain_pddl = """
(define (domain blocksworld)
  (:requirements :typing)
  (:types block)
  (:predicates
    (on ?x - block ?y - block)
    (clear ?x - block)
  )
)
"""

problem_pddl = """
(define (problem bw-2)
  (:domain blocksworld)
  (:objects a b - block)
  (:init (on a b) (clear a))
  (:goal (on b a))
)
"""

translator = TemplateTranslator(
    {
        "on": "Is the {0} block on top of the {1} block?",
        "clear": "Is the {0} block clear?",
    }
)

estimator = SemanticStateEstimator(
    domain_pddl,
    problem_pddl,
    vlm="HuggingFaceTB/SmolVLM-256M-Instruct",
    query_translator=translator,
    user_prompt_template="Answer yes or no only: {query}",
)

images = [Image.open("scene.png")]

state = estimator(images)
probabilities = estimator.estimate_probabilities(images)

print(state)
print(probabilities)

You can also inspect normalized backend outputs directly:

raw_outputs = estimator.estimate_raw(images)
print(raw_outputs["on(a,b)"])

Reusing Platt calibration predictions

Platt scaling is available in probability_method="logprobs" mode when scikit-learn is installed:

pip install -e '.[calibration]'

The expensive part of calibration is querying the VLM on labeled examples. You can collect those prediction scores once, save them, and fit or refit the Platt profile later without querying the VLM again:

from s3e import CalibrationExample

examples = [
    CalibrationExample(
        images=[Image.open("calibration-scene-1.png")],
        state_dict={
            "on(a,b)": True,
            "clear(a)": True,
            "clear(b)": False,
        },
    )
]

calibration_data = estimator.collect_platt_scaling_data(examples)
estimator.save_platt_scaling_data(calibration_data, "platt-calibration-data.json")

reused_data = estimator.load_platt_scaling_data("platt-calibration-data.json")
estimator.fit_platt_scaling_from_data(reused_data, scope="global")
estimator.save_platt_scaling("platt-profile.json")

collect_platt_scaling_data() performs VLM inference. fit_platt_scaling_from_data() only consumes saved scores and labels. The convenience method fit_platt_scaling() still works and delegates through the same fit-from-data path internally, so both workflows produce profiles with the same grouping and validation behavior.

For scope="lifted" across multiple problem instances, include each CalibrationExample.problem so saved samples carry the problem string needed to recover the lifted predicate key.

To convert the boolean state back into a Unified Planning state object:

from s3e.pddl.up_utils import state_dict_to_up_state

up_state = state_dict_to_up_state(estimator.up_problem, state)

For OpenAI-backed models, install the optional dependency and use an OpenAI/-prefixed model ID, for example "OpenAI/gpt-4o".

API Reference / Configuration

Core estimator

SemanticStateEstimator(domain, problem, vlm, ...) is the main entry point.

Key arguments:

  • domain, problem: PDDL domain and problem, provided either as strings or file paths.
  • vlm: a VLMBackend instance or a model string. Strings prefixed with OpenAI/ select the OpenAI backend; all other strings select the HuggingFace backend by default. For non-OpenAI model strings, pass use_vllm=True to select the vLLM backend instead.
  • query_translator: translation strategy used to convert grounded predicates into queries.
  • confidence: default threshold used when converting probabilities into booleans.
  • multi_image_strategy: either "single" or "average".
  • probability_method: either "logprobs" or "text_match".
  • true_tokens, false_tokens: optional token groups used for probability extraction.
  • batch_size: number of predicate queries grouped into each backend batch.
  • user_prompt_template: format string for each translated query; must contain {query}.
  • additional_instructions: additional text appended to the system prompt.
  • vlm_kwargs: keyword arguments forwarded when vlm is provided as a model string.
  • inference_kwargs: per-query inference arguments forwarded to backend query/query_batch calls.
    • For OpenAI models, these are request arguments for chat.completions.create (for example temperature, max_completion_tokens).
    • For HuggingFace models, these are forwarded to model(...) in logprobs mode and model.generate(...) in generation mode.
    • For vLLM models, these are forwarded to vllm.SamplingParams (for example temperature, max_tokens).
  • use_vllm: route a non-OpenAI model string through vLLM instead of HuggingFace. Ignored when vlm is already a backend instance; ignored (with a warning) for OpenAI/ model strings.

vlm_kwargs and inference_kwargs are intentionally different:

  • vlm_kwargs configure backend/client construction.
    • OpenAI backend: forwarded to openai.OpenAI(...) (for example api_key, base_url, timeout).
    • HuggingFace backend: forwarded to backend/model construction (for example device_map, torch_dtype, attn_implementation).
    • vLLM backend (use_vllm=True): forwarded to vllm.LLM(...) (for example tensor_parallel_size, gpu_memory_utilization, max_model_len).
  • inference_kwargs configure runtime inference and are forwarded on every query.

Example:

estimator = SemanticStateEstimator(
    domain_pddl,
    problem_pddl,
    vlm="OpenAI/gpt-4o",
    vlm_kwargs={"api_key": "..."},
    inference_kwargs={"temperature": 0.2, "max_completion_tokens": 200},
)

For HuggingFace generation mode (probability_method="text_match"), s3e applies a deterministic default (do_sample=False) unless overridden via inference_kwargs. No default generation cap is imposed; set max_new_tokens in inference_kwargs if you want an explicit cap.

Common methods:

  • estimator(images) -> dict[str, bool]: return a boolean symbolic state.
  • estimate_probabilities(images) -> dict[str, float]: return per-predicate probabilities.
  • estimate_raw(images) -> dict[str, VLMOutput]: return normalized backend outputs.
  • swap_problem(domain, problem): rebuild the estimator for a new planning problem.

Translators

  • IdentityTranslator: use grounded predicates as-is.
  • TemplateTranslator: format grounded predicates with per-predicate templates.
  • PrewrittenTranslator: provide explicit prompts for each grounded predicate.
  • LLMTranslator: generate natural-language prompts with an LLM and optionally cache them.

Environment variables and optional configuration

  • OPENAI_API_KEY: required for OpenAIVLM and OpenAI-backed LLMTranslator usage.
  • cache_dir on LLMTranslator: enables on-disk caching of generated predicate translations.

Contributing

Install development dependencies:

pip install -e '.[dev]'

Run the fast test loop:

pytest -m "not slow"

Run the full test suite:

pytest

To contribute:

  1. Fork the repository and create a feature branch.
  2. Add or update tests for behavioral changes.
  3. Run the relevant test commands before submitting.
  4. Open a pull request with a concise description of the change and its motivation.

License

This project is licensed under the MIT License. See LICENSE for details.

Citation

@inproceedings{azranS3ESemanticSymbolic2025,
  title = {{{S3E}}: {{Semantic Symbolic State Estimation With Vision-Language Foundation Models}}},
  shorttitle = {{{S3E}}},
  booktitle = {{{AAAI}} 2025 {{Workshop LM4Plan}}},
  author = {Azran, Guy and Goshen, Yuval and Yuan, Kai and Keren, Sarah},
  year = 2025,
}

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

s3e-0.3.2.tar.gz (69.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

s3e-0.3.2-py3-none-any.whl (46.0 kB view details)

Uploaded Python 3

File details

Details for the file s3e-0.3.2.tar.gz.

File metadata

  • Download URL: s3e-0.3.2.tar.gz
  • Upload date:
  • Size: 69.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.20

File hashes

Hashes for s3e-0.3.2.tar.gz
Algorithm Hash digest
SHA256 9ea229d0702c08b8de8163d277c91f2c2abfa510f99e52f3cdf42c3454f0cf71
MD5 324097e7f60d275c0d5154482b365e38
BLAKE2b-256 003b530a9cb66b3913e23f00ef6486f911dd4e1dd09148bb7141d4272ef09d8e

See more details on using hashes here.

File details

Details for the file s3e-0.3.2-py3-none-any.whl.

File metadata

  • Download URL: s3e-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 46.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.20

File hashes

Hashes for s3e-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 dc442abe93315ad8ecb2b61961d3cf4a5e2a7d48bd193efa3e4c4a20280d4cbf
MD5 cd9ebe9b8a5b489d5477fa0e460b0fff
BLAKE2b-256 73f68c45f9796aa462875949c90121d53bfc61f3ac11f9c878b8ebfcd481c2f7

See more details on using hashes here.

Release history Release notifications | RSS feed

0.4.1

2 files

This release

0.3.2 This release

2 files

0.3.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page