dds/generic.rkt
Sergiu Ivanov 39575f39c2 generic: Add dds-build-state-graph and dds-build-n-step-state-graph.
Also provide a common fallback implementation.
2020-02-23 18:51:57 +01:00

83 lines
3.5 KiB
Racket

#lang racket
;;; dds/generic
;;; Provides the definition of several generic interfaces for discrete
;;; dynamical systems.
(require racket/generic graph)
(provide
;; Generics
gen:dds
;; Functions
(contract-out [dds-step-one (-> dds? any/c (set/c any/c))]
[dds-step-one-annotated (-> dds? any/c (set/c (cons/c any/c any/c)))]
[dds-step (-> dds? (set/c any/c #:kind 'dont-care) (set/c any/c))]
[dds-build-state-graph (-> dds? (set/c any/c #:kind 'dont-care) graph?)]
[dds-build-n-step-state-graph (-> dds? (set/c any/c #:kind 'dont-care) number? graph?)])
;; Predicates
(contract-out [dds? (-> any/c boolean?)]))
;;; Given a dds and a set of starting states, produce the set of
;;; states reachable in one step. This is a fallback for dds-step.
(define (fallback-dds-step dds ss)
(apply set-union (for/list ([s ss]) (dds-step-one dds s))))
;;; Given a dds, a set of starting states, and a range whose length
;;; determines the number of steps to run, produces the state graph
;;; reachable from the starting steps in this many steps. This is a
;;; fallback for dds-build-state-graph and dds-build-n-step-state
;;; graph.
(define (fallback-dds-build-state-graph dds states step-range)
(for/fold ([edges empty]
[current-states states]
[visited-states states]
#:result (directed-graph edges))
([i step-range]
#:break (set-empty? current-states))
(for/fold ([new-edges empty]
[new-states (set)]
#:result (values
(append edges new-edges)
(set-subtract new-states visited-states)
(set-union current-states visited-states)))
([s current-states])
(let ([ss-next (dds-step-one dds s)])
(values
(append new-edges (for/list ([s-next ss-next]) (list s s-next)))
(set-union ss-next new-states))))))
;;; A discrete dynamical system.
(define-generics dds
;; Given a dds and a state, produce the next states of the dds.
;; This method has no fallback.
(dds-step-one dds state)
;; Given a dds and a state, produce the next states paired with some
;; annotation. Typical usage would include including the
;; information about the update mode. This method has no fallback.
(dds-step-one-annotated dds state)
;; Given a dds and a set of starting states, produce the set of
;; states reachable in one step. This method falls back to running
;; dds-step-one for all states.
(dds-step dds states)
;; Given a dds and a set of starting states, produces the state
;; graph reachable from the starting states. This method falls back
;; to exploring the state graph with dds-step-one.
(dds-build-state-graph dds states)
;; Given a dds, a set of starting states, and a number of steps to
;; run, produces the state graph reachable from the starting states
;; in this many steps. This method falls back to exploring the
;; state graph with dds-step-one.
(dds-build-n-step-state-graph dds states nsteps)
#:defined-predicate dds-implements?
#:fallbacks
[(define dds-step fallback-dds-step)
(define (dds-build-state-graph dds states)
;; Run fallback-dds-build-state-graph with an infinite range,
;; which will make it stop only when it has explored all the
;; state graph.
(fallback-dds-build-state-graph dds states (in-naturals)))
(define (dds-build-n-step-state-graph dds states nsteps)
(fallback-dds-build-state-graph dds states (in-range nsteps)))])