Skip to main content

Generalized Numerical P Systems simulator package

Project description

GNPS Project

GNPS (Generalized Numerical P Systems) is a Python package for parsing and simulating numerical P systems, and for exporting them to generated code.

Current Capabilities

  • Python simulation of standalone and import-composed GNPS YAML systems
  • Python source export through gnps-transform -t python, including import-composed systems as a single generated file
  • Verilog/SystemVerilog export through gnps-transform -t verilog
  • Webots Python controller export through gnps-transform -t webots
  • Optional import/composition metadata for Verilog generation

CLI

Simulator

python -m gnps <gnps_file.yaml> [input.csv] [output.csv] [options]

Options:

  • -c, --compute_mode: run in continuous compute mode
  • -s, --steps N: number of steps to run
  • --csv: emit CSV output in compute mode

Mode behavior:

  • IO mode is the default. It reads CSV input rows and writes CSV output rows.
  • In IO mode, the simulator always expects CSV input and produces CSV output.
  • Compute mode does not consume CSV input. It runs the system for a fixed number of steps and prints the output state.
  • --csv only affects compute mode and makes the output CSV-formatted.

The simulator supports standalone GNPS YAML and import-composed GNPS systems. Files using externals still fail clearly in the Python runtime.

Transformer

gnps-transform <gnps_file.yaml> -t {python,verilog,webots} [options]

Options:

  • -o, --output-dir DIR: output directory
  • --output-suffix SUFFIX: suffix inserted before the generated file extension
  • --import-path DIR: extra import search path, may be repeated
  • --import-paths LIST: path-separated import search list
  • -v, --verbose: verbose logging

Import resolution order:

  1. relative to the importing YAML file
  2. --import-path / --import-paths directories in the order provided

YAML Schema

Standalone GNPS YAML files are still supported:

cells:
  - id: 1
    contents:
      - x = 0
      - y = 1
    input: [x]
    output: [y]

rules:
  - x + 1 -> y

Verilog/SystemVerilog-oriented extensions are optional:

module:
  name: controller_top
  zero_reset_mode: false

constants:
  CLOCK_HZ: 27000000
  BLINK_HZ: 2
  THRESHOLD: 5
  HALF_PERIOD: CLOCK_HZ / (2 * BLINK_HZ)

aliases:
  sensed: sensor0.level

imports:
  - module: sensor.yaml
    as: sensor0
    connections:
      raw: sample

verilog:
  clock: clk
  reset: rst
  real_encoding:
    kind: fixed_point
    signed: true
    width: 32
    frac_bits: 16
  ports:
    sample:
      direction: input
      width: 16
    alarm:
      direction: output
      width: 16
  externals:
    uart0:
      header: uart.header.yaml
      parameters:
        FIFO_DEPTH: 16
      connections:
        rx: uart_rx
        tx: uart_tx

cells:
  - id: 1
    contents:
      - sample = 0
      - alarm = 0
    output: [alarm]

rules:
  - sensed > THRESHOLD && uart0.rx_valid == 1 | uart0.rx_data + 1 -> alarm

Additional YAML sugar is also supported:

  • top-level if / then / else blocks
  • recursive nested if blocks anywhere a rule list is allowed
  • fsm: blocks with one or more FSMs per module

Example:

fsm:
  - name: ctrl
    variable: ctrl_state
    initial: IDLE
    states:
      - IDLE:
          rules:
            - if: start > 0
              then: RUN -> ctrl_state
      - RUN:
          rules:
            - if: done > 0
              then: IDLE -> ctrl_state

Single-item sugar is accepted in branch bodies, so these are equivalent:

then:
  - 1 -> y
then: 1 -> y

Qualified references supported by the parser:

  • local variable: x
  • imported GNPS IO: sensor0.level
  • external module signal: uart0.rx_valid
  • Verilog port names are not part of GNPS alias resolution

Defaults

If module is absent, the effective defaults are:

  • module name: source filename stem
  • zero_reset_mode: false
  • real_encoding.kind: fixed_point
  • real_encoding.signed: true
  • real_encoding.width: 32
  • real_encoding.frac_bits: 16
  • clock name: clk
  • reset name: rst
  • reset polarity: active high
  • Verilog ports: none

If constants, aliases, imports, or externals are absent, they default to empty.

Constants may be literal numbers or load-time constant expressions. Expressions are evaluated in declaration order and may reference only previously declared constants:

constants:
  A: 2 * 5
  B: 3 * A + 1

These defaults are also documented in rules.md.

Verilog backend-specific sections:

verilog:
  clock: clk
  reset: rst
  real_encoding:
    kind: fixed_point
    signed: true
    width: 32
    frac_bits: 16
  ports:
    uart_rx:
      direction: input
      width: 1
    uart_tx:
      direction: output
      width: 1
  externals:
    uart0:
      header: uart.header.yaml
      parameters:
        FIFO_DEPTH: 16
      connections:
        rx: uart_rx
        tx: uart_tx

Verilog port entries may also specify kind; it defaults to logic when omitted. The clock and reset fields are scalar names for the generated boundary signals. They are not GNPS aliases, but external module connections may still wire to them through verilog.externals.connections.

Webots backend-specific sections:

webots:
  controller_name: e_puck_pid_controller
  timestep: 64
  bindings:
    left_sensor:
      device: ps0
      read_method: getValue
    right_sensor:
      device: ps7
      read_method: getValue
    left_speed:
      device: left wheel motor
      write_method: setVelocity
    right_speed:
      device: right wheel motor
      write_method: setVelocity
    left_position:
      device: left wheel motor
      write_method: setPosition
    right_position:
      device: right wheel motor
      write_method: setPosition
  init:
    left_position: inf
    right_position: inf

Generated RTL

The verilog backend emits SystemVerilog-style RTL:

  • file extension: .sv
  • wraps each generated module with `default_nettype none and keeps it in effect throughout the generated file
  • module parameters in the module header
  • always_comb for next-state logic
  • always_ff for sequential updates
  • fixed-point values stay as integer literals in the emitted RTL, wrapped in generated module-local localparam aliases such as _VAL_1_0
  • generated fixed-point state, helper signatures, and literals now follow module.real_encoding.signed instead of always being emitted as signed values
  • boundary conversions use generated integer-only helper functions rather than real-based helpers
  • if a GNPS input/output is described in verilog.ports, the generated RTL converts between the module-local fixed-point encoding and the declared Verilog port format at the module boundary
  • if a GNPS module does not declare verilog.ports, the Verilog backend infers the full module boundary from that module's input/output variables and verilog.real_encoding
  • if a GNPS input/output is described in verilog.externals, the generated RTL rewires that variable internally to the external module rather than exposing it at the top-level interface; if the target is a GNPS output that is also a top-level port, the top-level port is driven directly from the external module output
  • plain variable names such as sample or alarm refer to the local GNPS variable, while Verilog port names are emitted only through verilog.ports
  • fixed-point to integer top-port conversion truncates toward zero
  • generated literal aliases are documented with comments showing the original source values and fixed-point format

Supported expression subset:

  • constants
  • local variables
  • qualified references
  • addition and subtraction
  • unary minus
  • constant multiplication and constant division
  • boolean comparisons
  • boolean &&, ||, !

Rejected constructs:

  • generic function calls
  • variable-by-variable multiplication
  • non-constant division
  • arrays

Each GNPS module uses its own real_encoding. Boundary conversions are inserted automatically for imported GNPS IO and external ports. In the Verilog backend, consumed variables are reset to zero explicitly before productions are accumulated.

Examples

See examples/ for:

  • standalone YAML at the repository root, such as example1.yaml, example2.yaml, example3.yaml, example3io.yaml, example3io_b.yaml, and example_add.yaml
  • recursive conditional YAML in examples/fsm/if_recursive.yaml
  • FSM-oriented YAML in examples/fsm/fsm_counter.yaml and examples/fsm/fsm_dual.yaml
  • import-only Python composition in examples/composition/python_composed/
  • imported multicell Python composition in examples/composition/imported_composition/
  • Verilog-oriented YAML in examples/verilog/
  • FPGA-oriented examples under examples/fpga/, including standalone blink.yaml and ledwalk.yaml, plus dedicated folders for blink_uart/, verilog_controller/, fpga_uart_led/, fpga_spi_gpio_bridge/, and axii/
  • Webots controller examples under examples/webots/, including e_puck_pid/ and pioneer3_dx_obstacle_avoidance/

Notes

  • Top-level name and description are treated as metadata and ignored by Verilog generation.
  • Python composition currently supports imports only.
  • externals are not yet supported by the Python backend or runtime simulator.
  • Declaring a variable in output only exposes it at the module boundary; it does not implicitly consume or reset that variable each step. If an output should behave like a per-step pulse/value rather than accumulated state, add an explicit consume/reset rule for it.
  • module.zero_reset_mode: true changes only that module’s local variables: they are cleared to zero at the start of every step before productions are accumulated. Imported modules keep their own mode independently.
  • Detailed behavior and schema rules live in rules.md.

Example:

cells:
  - id: 1
    contents:
      - alarm = 0
    output: [alarm]

rules:
  # Persistent output/state: alarm keeps its previous value unless consumed
  - sensor0.level > 2 | 1 -> alarm
cells:
  - id: 1
    contents:
      - alarm = 0
    output: [alarm]

rules:
  # Per-step output: first produce the value you want
  - sensor0.level > 2 | 1 -> alarm
  # Then consume/reset alarm each step so it does not accumulate
  - alarm * 0 -> alarm

Since version 0.3.0, Codex has been used to help with code-generation and refactoring work in this repository.

Project details


Download files

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

Source Distribution

gnps-0.6.4.tar.gz (94.1 kB view details)

Uploaded Source

Built Distribution

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

gnps-0.6.4-py3-none-any.whl (72.0 kB view details)

Uploaded Python 3

File details

Details for the file gnps-0.6.4.tar.gz.

File metadata

  • Download URL: gnps-0.6.4.tar.gz
  • Upload date:
  • Size: 94.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.25.9 CPython/3.12.11 Linux/6.12.90+deb13-amd64

File hashes

Hashes for gnps-0.6.4.tar.gz
Algorithm Hash digest
SHA256 ce92af6494b1340f3e3df0b3d3b714ae11fd12f6214e0e0dc386e27b87b91c6f
MD5 fa86cdd01e3773eabcab7c750307b1c1
BLAKE2b-256 75c2bebeb5d8047ea38ea35466562bbc81a8bed547c3aaeaa5dd0f337eac12b2

See more details on using hashes here.

File details

Details for the file gnps-0.6.4-py3-none-any.whl.

File metadata

  • Download URL: gnps-0.6.4-py3-none-any.whl
  • Upload date:
  • Size: 72.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.25.9 CPython/3.12.11 Linux/6.12.90+deb13-amd64

File hashes

Hashes for gnps-0.6.4-py3-none-any.whl
Algorithm Hash digest
SHA256 71e8c0fd6f1c6c25989988ae50330c1b67039eb056fe5c5e7270c7266939233c
MD5 072a9547a2c3c181611314008bb7c015
BLAKE2b-256 bb231c79fb81f182fafc88314eff5eea4a34b1b9971cb1dbdc13eec15ac1757c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page