def test_synthesize(self): mach = synthesize(self.f_un) assert not isinstance(mach, MealyMachine) mach = synthesize(self.f) # There is more than one possible strategy realizing this # specification. Checking only for one here makes this more like # a regression test (fragile). However, it is more meaningful # than simply checking that synthesize() returns something # non-None (i.e., realizability, which is tested elsewhere). assert mach is not None assert len(mach.inputs) == 1 and mach.inputs.has_key("x") assert len(mach.outputs) == 1 and mach.outputs.has_key("y") assert len(mach.states()) == 6 assert set(mach.transitions()) == set([(0, 1), (0, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 0), (3, 3), (4, 0), (4, 3), ("Sinit", 0)]) label_reference = {(0, 1) : (0,0), # value is bitvector of x,y (0, 2) : (1,0), (1, 3) : (0,0), (1, 4) : (1,0), (2, 3) : (0,0), (2, 4) : (1,0), (3, 0) : (1,1), (3, 3) : (0,0), (4, 0) : (1,1), (4, 3) : (0,0), ("Sinit", 0) : (1,1)} for (from_state, to_state, slabel) in mach.transitions(data=True): assert label_reference[(from_state, to_state)] == (slabel["x"], slabel["y"])
def hash_question_mark_test(): specs = GRSpec(env_vars={'w': ['low', 'medium', 'high']}, sys_vars={'a': (0, 2)}, env_init=['w="low"'], env_safety=['(a=1) -> ((w="low") || (w="medium"))'], env_prog=['(w="high")'], sys_init=['a=2'], sys_safety=['a=2'], sys_prog=['a=2']) with nt.assert_raises(ValueError): jtlv.synthesize(specs)
def synthesize( option, specs, env=None, sys=None, ignore_env_init=False, ignore_sys_init=False, bool_states=False, action_vars=None, bool_actions=False ): """Function to call the appropriate synthesis tool on the specification. Beware! This function provides a generic interface to a variety of routines. Being under active development, the types of arguments supported and types of objects returned may change without notice. @param option: Magic string that declares what tool to invoke, what method to use, etc. Currently recognized forms: - C{"gr1c"}: use gr1c for GR(1) synthesis via L{interfaces.gr1c}. - C{"jtlv"}: use JTLV for GR(1) synthesis via L{interfaces.jtlv}. @type specs: L{spec.GRSpec} @param env: A transition system describing the environment: - states controlled by environment - input: sys_actions - output: env_actions - initial states constrain the environment This constrains the transitions available to the environment, given the outputs from the system. Note that an L{OpenFTS} with only sys_actions is equivalent to an L{FTS} for the environment. @type env: L{transys.FTS} or L{transys.OpenFTS} @param sys: A transition system describing the system: - states controlled by the system - input: env_actions - output: sys_actions - initial states constrain the system Note that an OpenFTS with only sys_actions is equivalent to an FTS for the system. @type sys: L{transys.FTS} L{transys.OpenFTS} @param ignore_sys_init: Ignore any initial state information contained in env. @type ignore_sys_init: bool @param ignore_env_init: Ignore any initial state information contained in sys. @type ignore_env_init: bool @param bool_states: if True, then use one bool variable for each state. Otherwise use a single int variable for all states. Currently int state implemented only for gr1c. @type bool_states: bool @param action_vars: for the integer variables modeling environment and system actions in GR(1). Effective only when >2 actions for each player. @type action_vars: 2-tuple of str: (env_action_var_name, sys_action_var_name) Default: ('eact', 'act') (must be valid variable name) @param bool_actions: model actions using bool variables @type bool_actions: bool @return: If spec is realizable, then return a Mealy machine implementing the strategy. Otherwise return None. @rtype: L{transys.MealyMachine} or None """ bool_states, action_vars, bool_actions = _check_solver_options( option, bool_states, action_vars, bool_actions ) specs = spec_plus_sys(specs, env, sys, ignore_env_init, ignore_sys_init, bool_states, action_vars, bool_actions) if option == 'gr1c': ctrl = gr1c.synthesize(specs) elif option == 'jtlv': ctrl = jtlv.synthesize(specs) else: raise Exception('Undefined synthesis option. '+\ 'Current options are "jtlv" and "gr1c"') try: logger.debug('Mealy machine has: n = ' + str(len(ctrl.states) ) +' states.') except: logger.debug('No Mealy machine returned.') # no controller found ? # exploring unrealizability with counterexamples or other means # can be done by calling a dedicated other function, not this if not isinstance(ctrl, transys.MealyMachine): return None return ctrl
def synthesize_many(specs, ts=None, ignore_init=None, bool_actions=None, solver='gr1c'): """Synthesize from logic specs and multiple transition systems. The transition systems are composed synchronously, i.e., they all have to take a transition at each time step. The synchronous composition is obtained by taking the conjunction of the formulas describing each transition system. The states of each transition system can be either: - all integers, or - all strings In either case the transition system state will be represented in logic with a single variable, that ranges over a finite set of integers or strings, respectively. The keys of C{ts} are used to name each state variable. So the logic formula for C{ts['name']} will be C{'name'}. Who controls this state variable is determined from the attribute C{FTS.owner} that can take the values: - C{'env'} - C{'sys'} For example: >>> ts.states.add_from(xrange(4)) >>> ts['door'].owner = 'env' will result in a logic formula with an integer variable C{'door'} controlled by the environment and taking values over C{{0, 1, 2, 3}}. The example: >>> ts.states.add_from(['a', 'b', 'c']) >>> ts['door'].owner = 'sys' will instead result in a string variable C{'door'} controlled by the system and taking values over C{{'a', 'b', 'c'}}. @type specs: L{GRSpec} @type ts: C{dict} of L{FiniteTransitionSystem} @type ignore_init: C{set} of keys from C{ts} @type bool_actions: C{set} of keys from C{ts} @param solver: 'gr1c' or 'slugs' or 'jtlv' @type solver: str """ assert isinstance(ts, dict) for name, t in ts.iteritems(): assert isinstance(t, transys.FiniteTransitionSystem) ignore = name in ignore_init bool_act = name in bool_actions statevar = name if t.owner == 'sys': specs |= sys_to_spec(t, ignore, statevar, bool_actions=bool_act) elif t.owner == 'env': specs |= env_to_spec(t, ignore, statevar, bool_actions=bool_act) if solver == 'gr1c': ctrl = gr1c.synthesize(specs) elif solver == 'slugs': if slugs is None: raise ValueError('Import of slugs interface failed. ' + 'Please verify installation of "slugs".') ctrl = slugs.synthesize(specs) elif solver == 'jtlv': ctrl = jtlv.synthesize(specs) else: raise Exception('Unknown solver: ' + str(solver) + '. ' 'Available solvers: "jtlv", "gr1c", and "slugs"') try: logger.debug('Mealy machine has: n = ' + str(len(ctrl.states)) + ' states.') except: logger.debug('No Mealy machine returned.') # no controller found ? # counterstrategy not constructed by synthesize if not isinstance(ctrl, transys.MealyMachine): return None ctrl.remove_deadends() return ctrl
def synthesize( option, specs, env=None, sys=None, ignore_env_init=False, ignore_sys_init=False, bool_states=False, bool_actions=False, rm_deadends=True ): """Function to call the appropriate synthesis tool on the specification. The states of the transition system can be either: - all integers, or - all strings For more details of how the transition system is represented in logic look at L{synthesize_many}. Beware! ======= This function provides a generic interface to a variety of routines. Being under active development, the types of arguments supported and types of objects returned may change without notice. @param option: Magic string that declares what tool to invoke, what method to use, etc. Currently recognized forms: - C{"gr1c"}: use gr1c for GR(1) synthesis via L{interfaces.gr1c}. - C{"slugs"}: use slugs for GR(1) synthesis via L{interfaces.slugs}. - C{"jtlv"}: use JTLV for GR(1) synthesis via L{interfaces.jtlv}. @type specs: L{spec.GRSpec} @param env: A transition system describing the environment: - states controlled by environment - input: sys_actions - output: env_actions - initial states constrain the environment This constrains the transitions available to the environment, given the outputs from the system. @type env: L{FTS} @param sys: A transition system describing the system: - states controlled by the system - input: env_actions - output: sys_actions - initial states constrain the system @type sys: L{FTS} @param ignore_env_init: Ignore any initial state information contained in env. @type ignore_env_init: bool @param ignore_sys_init: Ignore any initial state information contained in sys. @type ignore_sys_init: bool @param bool_states: deprecated as inefficient if True, then use one bool variable for each state. Otherwise use a single integer variable for all states. @type bool_states: bool @param bool_actions: model actions using bool variables, otherwise use integers. @type bool_actions: bool @param rm_deadends: return a strategy that contains no terminal states. @type rm_deadends: bool @return: If spec is realizable, then return a Mealy machine implementing the strategy. Otherwise return None. @rtype: L{MealyMachine} or None """ specs = _spec_plus_sys( specs, env, sys, ignore_env_init, ignore_sys_init, bool_states, bool_actions) if option == 'gr1c': strategy = gr1c.synthesize(specs) elif option == 'slugs': if slugs is None: raise ValueError('Import of slugs interface failed. ' + 'Please verify installation of "slugs".') strategy = slugs.synthesize(specs) elif option == 'jtlv': strategy = jtlv.synthesize(specs) else: raise Exception('Undefined synthesis option. ' + 'Current options are "jtlv", "gr1c", and "slugs"') ctrl = strategy2mealy(strategy, specs) try: logger.debug('Mealy machine has: n = ' + str(len(ctrl.states)) + ' states.') except: logger.debug('No Mealy machine returned.') # no controller found ? # exploring unrealizability with counterexamples or other means # can be done by calling a dedicated other function, not this if not isinstance(ctrl, transys.MealyMachine): return None if rm_deadends: ctrl.remove_deadends() return ctrl