コード例 #1
0
def unify_obs(observation):
    '''
    TODO: accumulate and apply them all at once
    '''
    action = copy.deepcopy(observation.action)
    action.update_start_time(observation.start_time)
    action.update_end_time(observation.end_time)

    # Constraint check
    action_cons, return_state = constraints_satisfied(action,
                                                      Plan(),
                                                      Proposed(),
                                                      is_observation=True)

    if not action_cons:
        return_state.update_subs({
            var('T1'): observation.start_time,
            var('T2'): observation.end_time,
        })
        process_return_state(observation, return_state)
        return

    KB.log_action_new(action, from_obs=True)
    KB.add_cycle_obs(observation)

    initiates, terminates = process_causalities(action)

    return initiates, terminates
コード例 #2
0
    def iff(self, *args):
        converted = [(arg, True) for arg in args if not isinstance(arg, tuple)]
        converted += [arg for arg in args if isinstance(arg, tuple)]

        KB.set_causality_reqs(self, converted)

        return self
コード例 #3
0
def process_return_state(observation, return_state):
    # TODO: Optional display message for return state
    KB.log_rejected_observation(observation)
    subs = return_state.subs
    for constraint in return_state.goals:
        obj = constraint.goal
        res = reify_obj_args(obj, subs)
コード例 #4
0
    def _obs_before(self):
        KB.clear_cycle_obs(self.current_time)

        self._check_observations()
        self._check_rules()
        self._solve_plans()

        commit_outcomes(self.initiated, self.terminated)
コード例 #5
0
ファイル: core.py プロジェクト: astraldawn/pylps
def false_if(*args):
    converted = []
    for arg in args:
        if isinstance(arg, tuple):
            converted.append(arg)
        else:
            converted.append((arg, True))
    KB.add_constraint(converted)
コード例 #6
0
ファイル: core.py プロジェクト: astraldawn/pylps
def execute(n_solutions=CONFIG_DEFAULT_N_SOLUTIONS,
            single_clause=False,
            solution_preference=SOLN_PREF_FIRST,
            debug=False,
            experimental=True,
            strategy=STRATEGY_GREEDY,
            stepwise=False,
            obs=OBS_BEFORE):
    '''Execute pyLPS program

    Keyword arguments:
    n_solutions -- the number of solutions, use -1 for all solutions
    (default 1)
    single_clause -- only consider the first clause for an event (default true)
    solutions_preference -- the type of solution to favour (defaults to first)

    '''

    if solution_preference is SOLN_PREF_MAX:
        # If we want maximum solutions, override n_solutions if it is default
        if n_solutions == CONFIG_DEFAULT_N_SOLUTIONS:
            n_solutions = -1

    # All solutions if -1
    if n_solutions == -1:
        n_solutions = 10000000

    options_dict = {
        'n_solutions': n_solutions,
        'obs': obs,
        'single_clause': single_clause,
        'solution_preference': solution_preference,

        # Development
        'debug': debug,
        'experimental': experimental,
        'strategy': strategy,
    }

    # Resets
    CONFIG.reactive_id = 0
    KB.reset_kb()

    # Initially
    # for fluent in KB.initial_fluents:
    #     KB.add_fluent(fluent)
    #     KB.log_fluent(fluent, 0, F_INITIATE)

    CONFIG.set_options(options_dict)
    ENGINE.run(stepwise=stepwise)
コード例 #7
0
ファイル: solver_utils.py プロジェクト: astraldawn/pylps
def process_cycle(cycle_events):
    '''
    TODO - Delay all commitment into KB until all are processed
    '''

    for event in cycle_events:

        # Convert args for action
        converted_args = convert_args_to_python(event)

        # Add into observations
        KB.add_cycle_obs(Observation(event, event.start_time, event.end_time))

        # Log action
        KB.log_action_new(event, converted_args=converted_args)

        initiates, terminates = process_causalities(event)
        commit_outcomes(initiates, terminates)
コード例 #8
0
def unify_fluent(cond, cycle_time, counter=0):

    fluent = cond
    temporal_var = cond.time

    # debug_display(fluent, KB.exists_fluent(fluent))

    substitutions = {}
    grounded = is_grounded(fluent)

    # Handle the grounded case
    if grounded:

        # Check if fluent is in KB
        if not KB.exists_fluent(fluent):
            return None

        # Unify with temporal vars, return the substitution
        substitutions.update(unify(
            var(temporal_var.name.split(VAR_SEPARATOR)[0] +
                VAR_SEPARATOR + str(counter)),
            cycle_time))

        yield substitutions

    kb_fluents = KB.get_fluents(fluent)

    for kb_fluent in kb_fluents:
        unify_res = unify_args(fluent.args, kb_fluent.args)

        if unify_res == {}:
            continue

        # debug_display('FLUENT_UNIFY_RES', unify_res)

        unify_res.update(unify(
            var(temporal_var.name.split(VAR_SEPARATOR)[0] +
                VAR_SEPARATOR + str(counter)),
            cycle_time
        ))

        yield unify_res

    return substitutions
コード例 #9
0
def generate_outcome_fluents(fluent):
    ret = []
    if is_grounded(fluent):
        return [fluent]

    for kb_fluent in KB.get_fluents(fluent):
        unify_subs = unify_args(fluent.args, kb_fluent.args)
        kb_fluent.args = reify_args(kb_fluent.args, unify_subs)
        fluent_args = reify_args(fluent.args, unify_subs)

        if kb_fluent.args == fluent_args:
            ret.append(kb_fluent)

    return ret
コード例 #10
0
def process_causalities(action, deconflict=True):
    causalities = KB.exists_causality(action)

    initiates = OrderedSet()
    terminates = OrderedSet()

    if not causalities:
        return OrderedSet(), OrderedSet()

    for causality in causalities:
        action_subs = unify_args(causality.action.args, action.args)
        '''
        TODO: This check should be shifted into generating fluents
        Because the fluent might not be grounded yet
        '''

        constraint_subs = _check_reqs(causality.reqs, action_subs)

        if not constraint_subs:
            continue

        # Handle the case where there is no constraint
        if isinstance(constraint_subs, bool):
            constraint_subs = [action_subs]

        for c_sub in constraint_subs:
            for causality_outcome in causality.outcomes:
                outcome = causality_outcome.outcome
                fluent = copy.deepcopy(causality_outcome.fluent)

                fluent.args = reify_args(fluent.args, c_sub)

                # TODO: Constraint check on solution
                check_outcome_constraint(fluent)

                fluents = generate_outcome_fluents(fluent)

                if outcome is A_INITIATE:
                    for f in fluents:
                        initiates.add((f, action.end_time))
                elif outcome is A_TERMINATE:
                    for f in fluents:
                        terminates.add((f, action.end_time))
                else:
                    raise UnknownOutcomeError(outcome)

    if deconflict:
        terminates = terminates - initiates

    return initiates, terminates
コード例 #11
0
def commit_outcomes(initiates, terminates):

    for (fluent, time) in initiates:
        if KB.add_fluent(fluent):
            KB.log_fluent(fluent, time, F_INITIATE)

    for (fluent, time) in terminates:
        if KB.remove_fluent(fluent):
            KB.log_fluent(fluent, time, F_TERMINATE)
コード例 #12
0
ファイル: solver_utils.py プロジェクト: astraldawn/pylps
def add_to_cycle_proposed(cycle_proposed, state):
    actions = reify_actions(state, reify=True)
    cycle_proposed.add_actions(actions)

    for action in actions:
        causalities = KB.exists_causality(action)

        if not causalities:
            continue

        for causality in causalities:
            action_subs = unify_args(causality.action.args, action.args)

            for causality_outcome in causality.outcomes:
                reify_outcome = copy.deepcopy(causality_outcome)
                reify_outcome.fluent.args = reify_args_constraint_causality(
                    reify_outcome.fluent.args, action_subs)

                cycle_proposed.add_fluent(reify_outcome)
コード例 #13
0
def unify_fact(fact, reactive=False):
    substitutions = []
    kb_facts = KB.get_facts(fact, reactive)
    grounded = is_grounded(fact)

    if grounded:
        for kb_fact in kb_facts:
            if fact.args == kb_fact.args:
                yield True

        yield False

    for kb_fact in kb_facts:
        unify_res = unify_args(fact.args, kb_fact.args)

        if unify_res == {}:
            continue

        yield unify_res

    return substitutions
コード例 #14
0
ファイル: core.py プロジェクト: astraldawn/pylps
def show_kb_log(show_events=False):
    return KB.show_log(show_events=show_events)
コード例 #15
0
    def _check_rules(self):

        # Check rules
        for rule in KB.rules:

            # Handle triggering from constant
            if rule.constant_trigger:
                continue

            conds = []
            true_trigger = False
            only_facts = True

            for cond in rule.conds:
                cond_object = copy.deepcopy(cond)

                # TODO: What if its hidden inside an EXPR?

                # Flag setting for fact triggers
                if cond_object.BaseClass != FACT:
                    only_facts = False

                cond_object.from_reactive = True

                rename_args(0, cond_object)
                conds.append(cond_object)

            # Special case for rules beginning with True
            if len(conds) == 1 and conds[0].BaseClass is CONSTANT and \
                    conds[0].const is True:
                true_trigger = True
                rule._constant_trigger = True
                state_list = [Plan([], {}, result=G_SOLVED)]

            # fact only
            if only_facts:
                rule._constant_trigger = True

            if not true_trigger:

                state_list = list(SOLVER.backtrack_solve(
                    start=Plan(conds, {}),  # REMOVED_DEEPCOPY
                    reactive=True,
                    only_facts=only_facts,
                    current_time=self.current_time
                ))

                # debug_display('STATE_LIST', self.current_time, state_list)

            if not state_list:
                continue

            for state in state_list:
                subs = state.subs
                result = state.result
                # TODO: Not exactly, there may just be facts with constant
                if subs == {} and not (true_trigger or result is G_DEFER):
                    continue

                new_goals = reify_goals(rule.goals, subs)

                if result is G_SOLVED:
                    KB.add_plan(new_goals, subs)

                if result is G_DEFER:
                    defer = list(state.goals)[state.goal_pos:]
                    new_goals = defer + new_goals
                    KB.add_plan(new_goals, subs)
コード例 #16
0
ファイル: core.py プロジェクト: astraldawn/pylps
def show_kb_rules():
    return KB.show_reactive_rules()
コード例 #17
0
ファイル: solver_utils.py プロジェクト: astraldawn/pylps
def process_solutions(solutions, cycle_time):
    maximum_solved = max([sol.solved for sol in solutions])
    new_kb_goals = []

    # Ensure that actions executed per cycle are unique
    processed = set()
    solved_goals = set()

    cycle_events = OrderedSet()

    for solution in solutions:

        for state in solution.states:

            if state.result is G_SOLVED:
                solved_goals.add(state.reactive_id)
                processed.add(state.reactive_id)
                cycle_events |= state.actions

            elif state.result is G_DEFER:
                if state.reactive_id in solved_goals:
                    continue

                processed.add(state.reactive_id)

                # Kept because of the reactive_id possibly being solved
                cycle_events |= state.actions

                new_state = state  # REMOVED DEEPCOPY

                # Clear actions / fluents and set to unprocessed
                new_state.clear_actions()
                new_state.clear_fluents()
                new_state.set_result(G_NPROCESSED)

                # Allow another temporal sub
                new_state.set_temporal_used(False)
                new_state.compress()
                new_kb_goals.append(new_state)

            elif state.result is G_DISCARD:
                processed.add(state.reactive_id)
                continue
            elif state.result is G_NPROCESSED:
                continue

        if maximum_solved > 0 and solution.solved == maximum_solved:
            break

    process_cycle(cycle_events)

    unsolved_existing_goals = OrderedSet()

    for start_state in KB.plans:
        if start_state.reactive_id in processed or \
                start_state.reactive_id in solved_goals:
            continue

        unsolved_existing_goals.add(start_state)

    for state in new_kb_goals:

        if state.reactive_id in solved_goals:
            continue

        unsolved_existing_goals.add(state)

    KB.set_plans(unsolved_existing_goals)
コード例 #18
0
ファイル: core.py プロジェクト: astraldawn/pylps
def observe(obs):
    # TODO: Make observations iterable?
    obs = Observation(obs, obs.start_time, obs.end_time)
    KB.add_observation(obs)
コード例 #19
0
ファイル: core.py プロジェクト: astraldawn/pylps
def kb_display_log(show_events=False, print_log=False):
    KB.show_log(show_events=show_events, print_log=False)
    return KB.display_log
コード例 #20
0
ファイル: core.py プロジェクト: astraldawn/pylps
def event(*args):
    new_clause = GoalClause(args)
    KB.add_clause(new_clause)
    return new_clause
コード例 #21
0
ファイル: core.py プロジェクト: astraldawn/pylps
def reactive_rule(*args):
    new_rule = ReactiveRule(args)
    KB.add_rule(new_rule)
    return new_rule
コード例 #22
0
ファイル: core.py プロジェクト: astraldawn/pylps
def goal(*args):
    new_clause = GoalClause(args)
    KB.add_clause(new_clause)
    return new_clause
コード例 #23
0
 def terminates(self, fluent):
     self.fluent = fluent
     KB.add_causality_outcome(self, A_TERMINATE)
     return self
コード例 #24
0
ファイル: core.py プロジェクト: astraldawn/pylps
def show_kb_fluents():
    return KB.show_fluents()
コード例 #25
0
ファイル: constraints.py プロジェクト: astraldawn/pylps
def constraints_satisfied(o_goal, state, cycle_proposed: Proposed,
                          is_observation=False):

    constraints = KB.get_constraints(o_goal)
    causalities = KB.exists_causality(o_goal)

    if not constraints:
        return (True, True) if is_observation else True

    # Handle goal
    goal = reify_obj_args(o_goal, state.subs)
    # print(goal)

    all_proposed = copy.deepcopy(cycle_proposed)

    # The new action
    all_proposed._actions.add(goal)

    all_proposed._actions = OrderedSet(
        [reify_action(c_action, state.subs)
         for c_action in all_proposed._actions]
    )

    for obs in KB.cycle_obs:
        end_time = o_goal.end_time
        if not isinstance(end_time, int):
            end_time = reify(var(end_time.name), state.subs)

        # print(obs.action.end_time, end_time)
        if obs.end_time == end_time:
            all_proposed._actions.add(obs.action)

    if causalities:
        for causality in causalities:
            action_subs = unify_args(causality.action.args, goal.args)

            for causality_outcome in causality.outcomes:
                reify_outcome = copy.deepcopy(causality_outcome)
                reify_outcome.fluent.args = reify_args_constraint_causality(
                    reify_outcome.fluent.args, action_subs)

                if reify_outcome in all_proposed.fluents:
                    continue

                all_proposed.add_fluent(reify_outcome)  # REMOVED_DEEPCOPY

                # TODO: Check this addition for duplicates
                co_cons = KB.get_constraints(causality_outcome.fluent)
                if co_cons:
                    constraints.extend(co_cons)

    for constraint in constraints:

        try:
            res = next(check_constraint(constraint, all_proposed))

            if is_observation:
                return (False, res)

            return False
        except StopIteration:
            continue

    if is_observation:
        return (True, True)

    return True
コード例 #26
0
 def _handle_initial(self):
     for fluent in KB.initial_fluents:
         KB.add_fluent(fluent)
         KB.log_fluent(fluent, 0, F_INITIATE)
コード例 #27
0
 def __pos__(self):
     KB.add_fact(self, force=True)
コード例 #28
0
 def initiates(self, fluent):
     self.fluent = fluent
     KB.add_causality_outcome(self, A_INITIATE)
     return self
コード例 #29
0
ファイル: constraints.py プロジェクト: astraldawn/pylps
def expand_fluent(constraint, cur_state, states, all_proposed):
    cons_fluent, outcome = constraint.goal, constraint.outcome
    cur_subs = cur_state.subs
    fluents = copy.deepcopy(KB.get_fluents(cons_fluent))

    grounded = True

    for arg in cons_fluent.args:
        try:
            if not cur_subs.get(var(arg.name)):
                grounded = False
        except AttributeError:
            continue

    # debug_display('CONS_FLUENT', cons_fluent, outcome, cur_subs)
    # debug_display('CUR_SUBS', cur_subs)
    # debug_display('FROM KB', fluents)
    # debug_display('ALL_PROP', all_proposed)

    for causality_outcome in all_proposed.fluents:
        if causality_outcome.outcome == A_INITIATE:
            if causality_outcome.fluent in fluents:
                continue

            # TODO: Hotfix, force grounded
            if is_grounded(causality_outcome.fluent):
                # debug_display('CFLUENT', causality_outcome.fluent)
                fluents.append(causality_outcome.fluent)

        # TODO: Why does this work?
        # elif causality_outcome.outcome == A_TERMINATE:
        #     if outcome:
        #         pass
        #     if causality_outcome.fluent not in fluents:
        #         continue
        #     fluents.remove(causality_outcome.fluent)

    # debug_display('FROM KB AFTER ADD', fluents)
    # debug_display()

    # No fluents found
    if not fluents:
        # Expect something
        if outcome:
            return

        new_state = cur_state  # REMOVED_DEEPCOPY
        states.append(new_state)
        return

    matched = False
    for fluent in fluents:
        if grounded:
            res = reify_args(cons_fluent.args, cur_subs)
            if res == fluent.args:
                matched = True
                if outcome:
                    new_state = copy.deepcopy(cur_state)
                    states.append(new_state)
                    continue

            continue

        new_state = copy.deepcopy(cur_state)
        cons_fluent_res = reify_args(cons_fluent.args, cur_subs)
        res = unify_args(cons_fluent_res, fluent.args)

        if res == {}:
            continue

        new_state.update_subs(res)
        states.append(new_state)

    if not outcome and not matched:
        new_state = cur_state  # REMOVED_DEEPCOPY
        states.append(new_state)
コード例 #30
0
ファイル: core.py プロジェクト: astraldawn/pylps
def show_kb_facts():
    return KB.show_facts()