Skip to content

Commit

Permalink
Merge pull request #3 from bThink-BGU/0.0.4
Browse files Browse the repository at this point in the history
b_thread deepcopy bug fix and external event support
  • Loading branch information
tomyaacov authored Feb 5, 2023
2 parents c76a954 + 42657ec commit a65bbba
Show file tree
Hide file tree
Showing 11 changed files with 68 additions and 83 deletions.
3 changes: 2 additions & 1 deletion bppy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
from bppy.execution.listeners.b_program_runner_listener import *
from bppy.execution.listeners.print_b_program_runner_listener import *
from bppy.model.event_selection.event_selection_strategy import *
from bppy.model.event_selection.experimental_smt_event_selection_strategy import *
from bppy.model.event_selection.simple_event_selection_strategy import *
from bppy.model.event_selection.solver_based_event_selection_strategy import *
from bppy.model.event_selection.smt_event_selection_strategy import *
from bppy.model.event_selection.experimental_smt_event_selection_strategy import *
from bppy.model.b_event import *
from bppy.model.bprogram import *
from bppy.model.event_set import *
Expand Down
29 changes: 29 additions & 0 deletions bppy/examples/external_events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from bppy import *

class External(BEvent):
pass


any_external = EventSet(lambda event: isinstance(event, External))

@b_thread
def add_external():
b_program.enqueue_external_event(External("A"))
b_program.enqueue_external_event(External("B"))
b_program.enqueue_external_event(External("C"))
while True:
yield {waitFor: All()}

@b_thread
def act_on_external():
while True:
# triggers external events if exists, else terminates the bprogram
event = yield {block: All(), waitFor: any_external}
yield {request: BEvent(event.name)}


if __name__ == "__main__":
b_program = BProgram(bthreads=[add_external(), act_on_external()],
event_selection_strategy=SimpleEventSelectionStrategy(),
listener=PrintBProgramRunnerListener())
b_program.run()
2 changes: 1 addition & 1 deletion bppy/examples/robots_smt.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from bppy import *
import pygame
# import pygame

H = 250
W = 250
Expand Down
5 changes: 2 additions & 3 deletions bppy/model/b_thread.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from copy import deepcopy
from copy import copy


def b_thread(func):
def wrapper(*args):
while True:
m = None
args_copy = deepcopy(args)
f = func(*args_copy)
f = func(*args)
while True:
try:
e = f.send(m)
Expand Down
6 changes: 5 additions & 1 deletion bppy/model/bprogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def __init__(self, bthreads=None, source_name=None, event_selection_strategy=Non
self.listener = listener
self.variables = None
self.tickets = []
self.external_events_queue = []

def setup(self):
if self.source_name:
Expand Down Expand Up @@ -45,7 +46,7 @@ def add_bthread(self,bt):
self.new_bt.append(bt)

def next_event(self):
return self.event_selection_strategy.select(self.tickets)
return self.event_selection_strategy.select(self.tickets, self.external_events_queue)

def run(self):
if self.listener:
Expand Down Expand Up @@ -74,3 +75,6 @@ def run(self):

if self.listener:
self.listener.ended(b_program=self)

def enqueue_external_event(self, event):
self.external_events_queue.append(event)
2 changes: 1 addition & 1 deletion bppy/model/event_selection/event_selection_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
class EventSelectionStrategy(ABC):

@abstractmethod
def select(self, statements):
def select(self, statements, external_events_queue=[]):
pass

@abstractmethod
Expand Down
Original file line number Diff line number Diff line change
@@ -1,72 +1,7 @@
import sys
import os
from bppy.model.event_selection.event_selection_strategy import EventSelectionStrategy
from bppy.utils.z3helper import *
from bppy.model.event_selection.smt_event_selection_strategy import SMTEventSelectionStrategy


class Request:
def __init__(self, variables=None):
self.variables = variables


class WaitFor:
pass


class Block:
pass


class ExperimentalSMTEventSelectionStrategy(EventSelectionStrategy):

def __init__(self, debug=False):
self.debug = debug

def is_satisfied(self, event, statement):
return is_true(event.eval(statement.get(WaitFor, true)))

def select(self, statements):
sl = Solver()

# Collect the blocking constraints
blocking = Not(Or([l.get(Block, false) for l in statements]))
sl.add(blocking)

# A dictionary that maps each variable to a disjunction of all the requests for the variable
requests = {}

# Make sure that the model assigns a value to each of the variables that appear in any of the statements
for l in statements:
for v in getVariables(l.get(Block, false)):
requests[v] = false

for v in getVariables(l.get(Request, false)):
requests[v] = false

# Fill the requests dictionary
for l in statements:
for key, req in l.items():
if isinstance(key, Request) or key == Request:
if key == Request or key.variables is None:
vars = getVariables(req)
else:
vars = key.variables

for v in vars:
requests[v] = Or(requests.get(v, false), req)

# Add each of the disjunctionin requests to the solver
for r in requests.values():
sl.add(r)

# Use this to debug the assertions
if self.debug:
print(">> Block=", simplify(blocking))
print(">> Requests=")
for key, value in requests.items():
print(">>\t {} -> {}".format(key,simplify(value)))

if sl.check() == sat:
return sl.model()
else:
return None
def ExperimentalSMTEventSelectionStrategy():
from warnings import warn
warn('Class ExperimentalSMTEventSelectionStrategy is deprecated. Returned SMTEventSelectionStrategy instead.',
DeprecationWarning, stacklevel=2)
return SMTEventSelectionStrategy()
7 changes: 5 additions & 2 deletions bppy/model/event_selection/simple_event_selection_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,13 @@ def selectable_events(self, statements):
possible_events = {x for x in possible_events if x not in statement.get('block')}
return possible_events

def select(self, statements):
def select(self, statements, external_events_queue=[]):
selectable_events = self.selectable_events(statements)
if selectable_events:
return random.choice(tuple(selectable_events))
else:
return None
if len(external_events_queue) > 0:
return external_events_queue.pop(0)
else:
return None

7 changes: 5 additions & 2 deletions bppy/model/event_selection/smt_event_selection_strategy.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
from bppy.model.event_selection.event_selection_strategy import EventSelectionStrategy
from bppy.model.event_selection.solver_based_event_selection_strategy import SolverBasedEventSelectionStrategy
from bppy.utils.z3helper import *


class SMTEventSelectionStrategy(EventSelectionStrategy):
class SMTEventSelectionStrategy(SolverBasedEventSelectionStrategy):

def is_satisfied(self, event, statement):
return is_true(event.eval(statement.get('waitFor', true)))

# TODO: implement a way to set additional_statement
def select(self, statements, additional_statement=None):
if isinstance(additional_statement, list) and len(additional_statement) > 0:
raise NotImplementedError("SMTEventSelectionStrategy does not support external events.")
(request, block) = (false, false)

# Collect request and block statements
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from bppy.model.event_selection.event_selection_strategy import EventSelectionStrategy
from abc import abstractmethod

class SolverBasedEventSelectionStrategy(EventSelectionStrategy):
@abstractmethod
def select(self, statements, external_events_queue=[]):
pass

@abstractmethod
def is_satisfied(self, event, statement):
pass
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

setuptools.setup(
name="bppy",
version="0.0.3",
version="0.0.4",
author="Tom Yaacov",
author_email="tomyaacov1210@gmail.com",
description="BPpy: Behavioral Programming In Python",
Expand Down

0 comments on commit a65bbba

Please sign in to comment.