Ejemplo n.º 1
0
def define_ha(unsafe_box):
    '''make the hybrid automaton'''

    ha = HybridAutomaton()

    # dynamics: x' = y, y' = -x, t' == a
    a_mat = [[0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0]]

    one = ha.new_mode('one')
    one.set_dynamics(a_mat)
    one.set_invariant([[0, 0, 1, 0]], [math.pi - 1e-6])  # t <= pi

    two = ha.new_mode('two')
    two.set_dynamics([[0, 0, 0, 0], [0, 0, 0, -1], [0, 0, 0, 1], [0, 0, 0, 0]])
    two.set_invariant([[0, -1, 0, 0]], [3])  # y >= -3

    t = ha.new_transition(one, two)
    t.set_guard_true()

    error = ha.new_mode('error')
    t = ha.new_transition(two, error)

    unsafe_rhs = [
        -unsafe_box[0][0], unsafe_box[0][1], -unsafe_box[1][0],
        unsafe_box[1][1]
    ]
    t.set_guard([[-1, 0, 0, 0], [1, 0, 0, 0], [0, -1, 0, 0], [0, 1, 0, 0]],
                unsafe_rhs)

    return ha
Ejemplo n.º 2
0
def test_guard_strengthening():
    'simple 2-mode, 2-guard, 2d system with 1st guard A->B is x <= 2, 2nd guard A->B is y <= 2, and inv(B) is y <= 2'

    ha = HybridAutomaton()

    mode_a = ha.new_mode('A')
    mode_a.set_dynamics(np.identity(2))

    mode_b = ha.new_mode('B')
    mode_b.set_dynamics(np.identity(2))
    mode_b.set_invariant([[0, 1]], [2])

    trans1 = ha.new_transition(mode_a, mode_b, 'first')
    trans1.set_guard([[1, 0]], [2])

    trans2 = ha.new_transition(mode_a, mode_b, 'second')
    trans2.set_guard([[0, 1]], [2])

    ha.do_guard_strengthening()

    # trans1 should now have 2 conditions
    assert (trans1.guard_csr.toarray() == np.array([[1, 0], [0, 1]], dtype=float)).all()
    assert (trans1.guard_rhs == np.array([2, 2], dtype=float)).all()

    # trans2 should still have 1 condition since invariant was redundant
    assert (trans2.guard_csr.toarray() == np.array([[0, 1]], dtype=float)).all()
Ejemplo n.º 3
0
def test_transition():
    'test a discrete transition'

    ha = HybridAutomaton()

    # mode one: x' = 1, t' = 1, a' = 0 
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 0, 1], [0, 0, 1], [0, 0, 0]])

    # mode two: x' = -1, t' = 1, a' = 0 
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, 0, -1], [0, 0, 1], [0, 0, 0]])

    # invariant: t <= 2.5
    m1.set_invariant([[0, 1, 0]], [2.5])

    # guard: t >= 2.5
    trans1 = ha.new_transition(m1, m2, 'trans1')
    trans1.set_guard([[0, -1, 0]], [-2.5])

    # error t >= 4.5
    error = ha.new_mode('error')
    trans2 = ha.new_transition(m2, error, "to_error")
    trans2.set_guard([[0, -1, 0]], [-4.5])

    # initial set has x0 = [0, 1], t = [0, 0.2], a = 1
    init_lpi = lputil.from_box([(0, 1), (0, 0.2), (1, 1)], m1)
    init_list = [StateSet(init_lpi, m1)]

    # settings, step size = 1.0
    settings = HylaaSettings(1.0, 10.0)
    settings.stdout = HylaaSettings.STDOUT_VERBOSE
    settings.plot.plot_mode = PlotSettings.PLOT_NONE
    settings.plot.store_plot_result = True

    result = Core(ha, settings).run(init_list)
    ce = result.counterexample

    assert len(ce) == 2
    assert ce[0].mode.name == 'm1'
    assert ce[0].outgoing_transition.name == 'trans1'

    assert ce[1].mode.name == 'm2'
    assert ce[1].outgoing_transition.name == 'to_error'

    assert ce[1].start[0] + 1e-9 >= 3.0
    assert ce[1].end[0] - 1e-9 <= 2.0

    polys = [obj[0] for obj in result.plot_data.mode_to_obj_list[0]['m1']]
    assert len(polys) == 4

    polys = [obj[0] for obj in result.plot_data.mode_to_obj_list[0]['m2']]
    assert len(polys) == 3

    assert result.last_cur_state.cur_steps_since_start[0] == 5
Ejemplo n.º 4
0
def define_ha(limit):
    '''make the hybrid automaton and return it'''

    ha = HybridAutomaton()

    mode = ha.new_mode('mode')
    dynamics = loadmat('build.mat')
    a_matrix = dynamics['A']
    b_matrix = csc_matrix(dynamics['B'])

    mode.set_dynamics(csr_matrix(a_matrix))

    # 0.8 <= u1 <= 1.0
    u_mat = [[1.0], [-1.0]]
    u_rhs = [1.0, -0.8]

    mode.set_inputs(b_matrix, u_mat, u_rhs)

    error = ha.new_mode('error')

    y1 = dynamics['C'][0]
    mat = csr_matrix(y1, dtype=float)

    trans1 = ha.new_transition(mode, error)
    rhs = np.array([-limit], dtype=float)  # safe
    trans1.set_guard(mat, rhs)  # y3 >= limit

    return ha
Ejemplo n.º 5
0
def make_automaton():
    'make the hybrid automaton'

    ha = HybridAutomaton()

    # mode one: x' = y + u1, y' = -x + u2, c' = 1, a' = 0
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0]])

    b_mat = [[1, 0], [0, 1], [0, 0], [0, 0]]
    b_constraints = [[1, 0], [-1, 0], [0, 1], [0, -1]]
    b_rhs = [0.5, 0.5, 0.5, 0.5]
    m1.set_inputs(b_mat, b_constraints, b_rhs)

    # mode two: x' = -y, y' = x, a' = 0
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, -1], [1, 0]])

    # m1 invariant: c <= pi/2
    m1.set_invariant([[0, 0, 1, 0]], [math.pi / 2])

    # guard: c >= pi/2
    trans = ha.new_transition(m1, m2)
    trans.set_guard([[0, 0, -1, 0]], [-math.pi / 2])

    # Assign the reset to the transition
    # y *= -1, also the reset is what is used to change the number of system variables (m1 has four vars, m2 has two)

    reset_csr = [[1, 0, 0, 0], [0, -1, 0, 0]]

    # no minkowski sum terms
    trans.set_reset(reset_csr)

    return ha
Ejemplo n.º 6
0
def test_init_outside_invariant():
    'test when initial state is outside of the mode invariant'

    ha = HybridAutomaton()

    mode = ha.new_mode('mode')
    mode.set_dynamics([[0, 0, 1], [0, 0, 1], [0, 0, 0]]) # x' = 1, y' = 1, a' = 0

    # x <= 2.5
    mode.set_invariant([[1, 0, 0]], [2.5])

    # initial set, x = [3, 4]
    init_lpi = lputil.from_box([(3, 4), (0, 1), (1, 1)], mode)
    init_list = [StateSet(init_lpi, mode)]

    # transition to error if x >= 10
    error = ha.new_mode('error')
    trans = ha.new_transition(mode, error)
    trans.set_guard([[-1., 0, 0],], [-10]) 

    # settings
    settings = HylaaSettings(1.0, 5.0)
    settings.stdout = HylaaSettings.STDOUT_VERBOSE

    try:
        Core(ha, settings).run(init_list)
        assert False, "running with initial state outside of invariant did not raise RuntimeError"
    except RuntimeError:
        pass
Ejemplo n.º 7
0
def test_agg_with_reset():
    'test the aggregation of states with a reset'

    # m1 dynamics: x' == 1, y' == 0, x0: [-3, -2], y0: [0, 1], step: 1.0
    # m1 invariant: x + y <= 0
    # m1 -> m2 guard: x + y >= 0 and y <= 0.5, reset = [[0, -1, 0], [1, 0, 0]] (x' = -y, y' = x, remove a)
    # m2 dynamics: x' == 0, y' == 0
    # time bound: 4
    # expected result: last state is line (not box!) from (0, 0) to (-0.5, -0.5) 

    ha = HybridAutomaton()

    # mode one: x' = 1, y' = 0, a' = 0 
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 0, 1], [0, 0, 0], [0, 0, 0]])

    # mode two: x' = 0, y' = 1 
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, 0], [0, 0]])

    # invariant: x + y <= 0
    m1.set_invariant([[1, 1, 0]], [0])

    # guard: x + y == 0 & y <= 0.5
    trans1 = ha.new_transition(m1, m2, 'trans1')
    trans1.set_guard([[-1, -1, 0], [1, 1, 0], [0, 1, 0]], [0, 0, 0.5])
    #trans1.set_reset(np.identity(3)[:2])
    trans1.set_reset(np.array([[0, -1, 0], [1, 0, 0]], dtype=float))

    # initial set has x0 = [-3, -2], y = [0, 1], a = 1
    init_lpi = lputil.from_box([(-3, -2), (0, 1), (1, 1)], m1)
    init_list = [StateSet(init_lpi, m1)]

    # settings, step size = 1.0
    settings = HylaaSettings(1.0, 4.0)
    settings.stdout = HylaaSettings.STDOUT_NONE
    
    settings.plot.plot_mode = PlotSettings.PLOT_NONE

    # use agg_box
    settings.aggstrat.agg_type = Aggregated.AGG_BOX

    core = Core(ha, settings)
    
    result = core.run(init_list)

    lpi = result.last_cur_state.lpi

    # 2 basis matrix rows, 4 init constraints rows, 6 rows from guard conditions (2 from each)
    assert lpi.get_num_rows() == 2 + 4 + 6

    verts = result.last_cur_state.verts(core.plotman)
    assert len(verts) == 3
    assert np.allclose(verts[0], verts[-1])
    
    assert pair_almost_in((0, 0), verts)
    assert pair_almost_in((-0.5, -0.5), verts)
Ejemplo n.º 8
0
def test_unaggregation():
    'test an unaggregated discrete transition'

    ha = HybridAutomaton()

    # mode one: x' = 1, t' = 1, a' = 0 
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 0, 1], [0, 0, 1], [0, 0, 0]])

    # mode two: x' = -1, t' = 1, a' = 0 
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, 0, -1], [0, 0, 1], [0, 0, 0]])

    # invariant: t <= 2.5
    m1.set_invariant([[0, 1, 0]], [2.5])

    # guard: t >= 0.5
    trans1 = ha.new_transition(m1, m2, 'trans1')
    trans1.set_guard([[0, -1, 0]], [-0.5])

    # error x >= 4.5
    error = ha.new_mode('error')
    trans2 = ha.new_transition(m2, error, "to_error")
    trans2.set_guard([[-1, 0, 0]], [-4.5])

    # initial set has x0 = [0, 0.2], t = [0, 0.2], a = 1
    init_lpi = lputil.from_box([(0, 0.2), (0, 0.2), (1, 1)], m1)
    init_list = [StateSet(init_lpi, m1)]

    # settings, step size = 1.0
    settings = HylaaSettings(1.0, 10.0)
    settings.stdout = HylaaSettings.STDOUT_DEBUG
    settings.plot.store_plot_result = True
    settings.plot.plot_mode = PlotSettings.PLOT_NONE

    settings.aggstrat = aggstrat.Unaggregated()

    result = Core(ha, settings).run(init_list)

    # expected no exception

    # m2 should be reachable
    polys = [obj[0] for obj in result.plot_data.mode_to_obj_list[0]['m2']]
    assert len(polys) > 15
Ejemplo n.º 9
0
def test_agg_to_more_vars():
    'test the aggregation of states with a reset to a mode with new variables'

    ha = HybridAutomaton()

    # mode one: x' = 1, a' = 0 
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 1], [0, 0]])

    # mode two: x' = 0, a' = 0, y' == 1 
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, 0, 0], [0, 0, 0], [0, 1, 0]])

    # invariant: x <= 3.0
    m1.set_invariant([[1, 0]], [3.0])

    # guard: True
    trans1 = ha.new_transition(m1, m2, 'trans1')
    trans1.set_guard_true()

    reset_mat = [[1, 0], [0, 1], [0, 0]]
    reset_minkowski = [[0], [0], [1]]
    reset_minkowski_constraints = [[1], [-1]]
    reset_minkowski_rhs = [3, -3] # y0 == 3
    
    trans1.set_reset(reset_mat, reset_minkowski, reset_minkowski_constraints, reset_minkowski_rhs)

    # initial set has x0 = [0, 1], a = 1
    init_lpi = lputil.from_box([(0, 1), (1, 1)], m1)
    init_list = [StateSet(init_lpi, m1)]

    # settings, step size = 1.0
    settings = HylaaSettings(1.0, 4.0)
    settings.stdout = HylaaSettings.STDOUT_DEBUG
    settings.plot.plot_mode = PlotSettings.PLOT_NONE
    settings.plot.store_plot_result = True
    settings.plot.xdim_dir = 0
    settings.plot.ydim_dir = {'m1': 1, 'm2': 2}

    result = Core(ha, settings).run(init_list)

    polys = [obj[0] for obj in result.plot_data.mode_to_obj_list[0]['m1']]

    # 4 steps because invariant is allowed to be false for the final step
    assert 4 <= len(polys) <= 5, "expected invariant to become false after 4/5 steps"

    assert_verts_is_box(polys[0], [[0, 1], [1, 1]])
    assert_verts_is_box(polys[1], [[1, 2], [1, 1]])
    assert_verts_is_box(polys[2], [[2, 3], [1, 1]])
    assert_verts_is_box(polys[3], [[3, 4], [1, 1]])

    polys = [obj[0] for obj in result.plot_data.mode_to_obj_list[0]['m2']]

    assert_verts_is_box(polys[0], [[1, 4], [3, 3]])
    assert_verts_is_box(polys[1], [[1, 4], [4, 4]])
Ejemplo n.º 10
0
def make_automaton(unsafe_box):
    'make the hybrid automaton'

    ha = HybridAutomaton('Deaggregation Example')

    # x' = 2
    m1 = ha.new_mode('mode0_right')
    m1.set_dynamics([[0, 0, 2], [0, 0, 0], [0, 0, 0]])
    m1.set_invariant([[1, 0, 0]], [3.5])  # x <= 3.5

    # y' == 2
    m2 = ha.new_mode('mode1_up')
    m2.set_dynamics([[0, 0, 0], [0, 0, 2], [0, 0, 0]])
    m2.set_invariant([0., 1., 0], [3.5])  # y <= 3.5

    # x' == 2
    m3 = ha.new_mode('mode2_right')
    m3.set_dynamics([[0, 0, 2], [0, 0, -0], [0, 0, 0]])
    m3.set_invariant([1., 0, 0], [7])  # x <= 7

    t = ha.new_transition(m1, m2)
    t.set_guard_true()

    t = ha.new_transition(m2, m3)
    t.set_guard_true()

    error = ha.new_mode('error')
    t = ha.new_transition(m3, error)

    unsafe_rhs = [
        -unsafe_box[0][0], unsafe_box[0][1], -unsafe_box[1][0],
        unsafe_box[1][1]
    ]

    # x >= 1.1 x <= 1.9, y >= 2.7, y <= 4.3
    t.set_guard([[-1, 0, 0], [1, 0, 0], [0, -1, 0], [0, 1, 0]], unsafe_rhs)

    t = ha.new_transition(m2, error)
    # x >= 1.1 x <= 1.9, y >= 2.7, y <= 4.3
    t.set_guard([[-1, 0, 0], [1, 0, 0], [0, -1, 0], [0, 1, 0]], unsafe_rhs)

    return ha
Ejemplo n.º 11
0
def test_agg_no_counterexample():
    'test that aggregation to error does not create a counterexample'

    # m1 dynamics: x' == 1, y' == 0, x0, y0: [0, 1], step: 1.0
    # m1 invariant: x <= 3
    # m1 -> m2 guard: True
    # m2 dynamics: x' == 0, y' == 1
    # m2 -> error: y >= 3

    ha = HybridAutomaton()

    # mode one: x' = 1, y' = 0, a' = 0 
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 0, 1], [0, 0, 0], [0, 0, 0]])

    # mode two: x' = 0, y' = 1, a' = 0 
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, 0, 0], [0, 0, 1], [0, 0, 0]])

    # invariant: x <= 3.0
    m1.set_invariant([[1, 0, 0]], [3.0])

    # guard: True
    trans1 = ha.new_transition(m1, m2, 'trans1')
    trans1.set_guard_true()

    error = ha.new_mode('error')
    trans2 = ha.new_transition(m2, error, 'trans2')
    trans2.set_guard([[0, -1, 0]], [-3]) # y >= 3

    # initial set has x0 = [0, 1], t = [0, 1], a = 1
    init_lpi = lputil.from_box([(0, 1), (0, 1), (1, 1)], m1)
    init_list = [StateSet(init_lpi, m1)]

    # settings, step size = 1.0
    settings = HylaaSettings(1.0, 10.0)
    settings.stdout = HylaaSettings.STDOUT_DEBUG
    settings.plot.plot_mode = PlotSettings.PLOT_NONE

    result = Core(ha, settings).run(init_list)

    assert not result.counterexample
Ejemplo n.º 12
0
def test_tt_with_invstr():
    'test time-triggered transitions combined with invariant strengthening'

    ha = HybridAutomaton()

    # mode one: x' = 1, a' = 0 
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 1], [0, 0]])
    m1.set_invariant([[1, 0]], [2.0]) # invariant: x <= 2.0

    # mode two: x' = 1, a' = 0 
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, 1], [0, 0]])
    m2.set_invariant([[1, 1]], [4.0]) # x + a <= 4.0

    # guard: x >= 2.0
    trans1 = ha.new_transition(m1, m2, 'trans1')
    trans1.set_guard([[-1, 0]], [-2.0])

    # error x >= 4.0
    error = ha.new_mode('error')
    trans2 = ha.new_transition(m2, error, "to_error")
    trans2.set_guard([[-1, 0]], [-4.0])

    # initial set has x0 = [0, 1]
    init_lpi = lputil.from_box([(0, 1), (0, 1)], m1)
    init_list = [StateSet(init_lpi, m1)]

    # settings, step size = 0.1
    settings = HylaaSettings(0.1, 5.0)
    settings.stdout = HylaaSettings.STDOUT_VERBOSE
    settings.plot.plot_mode = PlotSettings.PLOT_NONE

    # run setup() only and check the result
    core = Core(ha, settings)
    core.setup(init_list)

    assert trans1.time_triggered
    assert not trans2.time_triggered # not time-triggered because invariant of m2 is True
Ejemplo n.º 13
0
def test_redundant_inv_transition():
    'test removing of redundant invariants with a transition'

    ha = HybridAutomaton()

    mode1 = ha.new_mode('mode1')
 
    # dynamics: x' = 1, y' = 1, a' = 0
    mode1.set_dynamics([[0, 0, 1], [0, 0, 1], [0, 0, 0]])

    # invariant: x <= 2.5
    mode1.set_invariant([[1, 0, 0]], [2.5])

    mode2 = ha.new_mode('mode2')
    mode2.set_dynamics([[0, 0, 0], [0, 0, 0], [0, 0, 0]])

    ha.new_transition(mode1, mode2).set_guard([[-1, 0, 0]], [-2.5]) # x >= 2.5

    # initial set has x0 = [0, 1]
    init_lpi = lputil.from_box([(0, 1), (0, 1), (1, 1)], mode1)
    init_list = [StateSet(init_lpi, mode1)]

    # settings, step size = 0.1
    settings = HylaaSettings(0.1, 5.0)
    settings.stdout = HylaaSettings.STDOUT_DEBUG
    settings.plot.plot_mode = PlotSettings.PLOT_NONE

    core = Core(ha, settings)
    core.setup(init_list)

    for _ in range(20):
        core.do_step()

    assert core.result.last_cur_state.lpi.get_num_rows() == 3 + 2*3 + 1 # 3 for basis matrix, 2*3 for init constraints

    assert len(core.aggdag.waiting_list) > 2

    core.plotman.run_to_completion()
Ejemplo n.º 14
0
def make_automaton():
    'make the hybrid automaton'

    ha = HybridAutomaton()

    mode = ha.new_mode('mode')
    dynamics = loadmat('iss.mat')
    a_matrix = dynamics['A']
    b_matrix = dynamics['B']

    mode.set_dynamics(a_matrix)

    # input bounds
    # 0 <= u1 <= 0.1
    # 0.8 <= u2 <= 1.0
    # 0.9 <= u3 <= 1.0
    bounds_mat = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1],
                  [0, 0, -1]]
    bounds_rhs = [0.1, 0, 1.0, -0.8, 1.0, -0.9]
    mode.set_inputs(b_matrix, bounds_mat, bounds_rhs)

    error = ha.new_mode('error')

    # the third output defines the unsafe condition
    y3 = dynamics['C'][2]

    limit = 0.0005
    #limit = 0.0007

    # Error condition: y3 * x <= -limit OR y3 >= limit
    trans1 = ha.new_transition(mode, error)
    trans1.set_guard(y3, [-limit])

    trans2 = ha.new_transition(mode, error)
    trans2.set_guard(-1 * y3, [-limit])

    return ha
Ejemplo n.º 15
0
def make_automaton():
    'make the hybrid automaton'

    ha = HybridAutomaton()

    # mode one: x' = 2, y' = 1, a' = 0 
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 0, 2], [0, 0, 1], [0, 0, 0]])

    # mode two: x' = 1, y' = 1, a' = 0 
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, 0, 1], [0, 0, 1], [0, 0, 0]])

    # invariant: x <= 9.9
    m1.set_invariant([[1, 0, 0]], [9.9])

    # guard: x >= 9.9
    trans = ha.new_transition(m1, m2, 'transition_name')
    trans.set_guard([[-1, 0, 0]], [-9.9])

    # Assign the reset to the transition:
    #
    #    def set_reset(self, reset_csr=None, reset_minkowski_csr=None, reset_minkowski_constraints_csr=None,
    #              reset_minkowski_constraints_rhs=None):
    #    '''resets are of the form x' = Rx + My, Cy <= rhs, where y are fresh variables
    #    the reset_minowski variables can be None if no new variables are needed. If unassigned, the identity
    #    reset is assumed
    #
    #    x' are the new variables
    #    x are the old variables       
    #    reset_csr is R
    #    reset_minkowski_csr is M
    #    reset_minkowski_constraints_csr is C
    #    reset_minkowski_constraints_rhs is rhs
    #    '''

    # we want the reset to set x' := [0, 1], y' := y - 10
    
    reset_csr = [[0, 0, 0], [0, 1, 0], [0, 0, 1]]

    # two new minkowski variables, y0 = [0, 1], y1 = [-10, -10]
    minkowski_csr = [[1, 0], [0, 1], [0, 0]]
    constraints_csr = [[1, 0], [-1, 0], [0, 1], [0, -1]]
    constraints_rhs = [1, 0, -10, 10]

    trans.set_reset(reset_csr, minkowski_csr, constraints_csr, constraints_rhs)

    return ha
Ejemplo n.º 16
0
def test_ha():
    'test for the harmonic oscillator example with line initial set (from ARCH 2018 paper)'

    ha = HybridAutomaton()

    # with time and affine variable
    mode = ha.new_mode('mode')
    mode.set_dynamics([[0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 0]])

    error = ha.new_mode('error')

    trans1 = ha.new_transition(mode, error)
    trans1.set_guard([[1., 0, 0, 0], [-1., 0, 0, 0]], [4.0, -4.0])

    # initial set
    init_lpi = lputil.from_box([(-5, -5), (0, 1), (0, 0), (1, 1)], mode)
    init_list = [StateSet(init_lpi, mode)]

    # settings
    settings = HylaaSettings(math.pi/4, 2*math.pi)
    settings.stdout = HylaaSettings.STDOUT_VERBOSE
    settings.plot.store_plot_result = True
    settings.plot.plot_mode = PlotSettings.PLOT_NONE
    
    core = Core(ha, settings)
    result = core.run(init_list)

    assert result.has_concrete_error

    ce = result.counterexample[0]

    # [-5.0, 0.6568542494923828, 0.0, 1.0] -> [4.0, 3.0710678118654737, 2.356194490192345, 1.0]

    assert ce.mode == mode
    assert np.allclose(ce.start, np.array([-5, 0.65685, 0, 1], dtype=float))
    assert np.allclose(ce.end, np.array([4, 3.07106, 2.35619, 1], dtype=float))

    # check the reachable state (should always have x <= 3.5)
    obj_list = result.plot_data.mode_to_obj_list[0][mode.name]

    for obj in obj_list:
        verts = obj[0]
        
        for vert in verts:
            x, _ = vert

            assert x <= 4.9
Ejemplo n.º 17
0
def test_over_time_range():
    'test plotting over time with aggergation (time range)'

    ha = HybridAutomaton()

    mode_a = ha.new_mode('A')
    mode_b = ha.new_mode('B')
 
    # dynamics: x' = a, a' = 0
    mode_a.set_dynamics([[0, 1], [0, 0]])
    mode_b.set_dynamics([[0, 1], [0, 0]])

    # invariant: x <= 2.5
    mode_a.set_invariant([[1, 0]], [2.5])

    trans1 = ha.new_transition(mode_a, mode_b, 'first')
    trans1.set_guard_true()

    # initial set has x0 = [0, 0]
    init_lpi = lputil.from_box([(0, 0), (1, 1)], mode_a)
    init_list = [StateSet(init_lpi, mode_a)]

    # settings, step size = 1.0
    settings = HylaaSettings(1.0, 4.0)
    settings.stdout = HylaaSettings.STDOUT_DEBUG
    settings.process_urgent_guards = True
    settings.plot.plot_mode = PlotSettings.PLOT_NONE
    settings.plot.store_plot_result = True
    settings.plot.xdim_dir = None
    settings.plot.ydim_dir = 0

    result = Core(ha, settings).run(init_list)

    polys = [obj[0] for obj in result.plot_data.mode_to_obj_list[0][mode_b.name]]
    # expected with aggegregation: [0, 2.5] -> [1, 3.5] -> [2, 4.5] -> [3, 5.5] -> [4, 6.5]

    # 4 steps because invariant is allowed to be false for the final step
    assert len(polys) == 5, "expected invariant to become false after 5 steps"

    for i in range(5):
        assert_verts_is_box(polys[i], [[i, i + 3.0], [i, i + 3.0]])
Ejemplo n.º 18
0
def test_agg_ha():
    'test aggregation with the harmonic oscillator dynamics'

    ha = HybridAutomaton('Deaggregation Example')

    m1 = ha.new_mode('green')
    m1.set_dynamics([[0, 1], [-1, 0]])

    m2 = ha.new_mode('cyan')
    m2.set_dynamics([[0, 0, 0], [0, 0, -2], [0, 0, 0]])

    t1 = ha.new_transition(m1, m2)
    t1.set_guard_true()
    reset_mat = [[1, 0], [0, 1], [0, 0]]
    t1.set_reset(reset_mat, [[0], [0], [1]], [[1], [-1]], [1, -1]) # create 3rd variable with a0 = 1

    mode = ha.modes['green']
    init_lpi = lputil.from_box([(-5, -4), (-0.5, 0.5)], mode)
    
    init_list = [StateSet(init_lpi, mode)]

    step = math.pi/4
    settings = HylaaSettings(step, 2*step)
    settings.process_urgent_guards = True
    settings.plot.plot_mode = PlotSettings.PLOT_NONE
    settings.stdout = HylaaSettings.STDOUT_DEBUG

    core = Core(ha, settings)
    core.setup(init_list)

    core.do_step() # pop
    #xs, ys = zip(*core.cur_state.verts(core.plotman))
    #plt.plot(xs, ys, 'k-')
    
    core.do_step() # 0
    #xs, ys = zip(*core.cur_state.verts(core.plotman))
    #plt.plot(xs, ys, 'k-')

    core.do_step() # 1
    #xs, ys = zip(*core.cur_state.verts(core.plotman))
    #plt.plot(xs, ys, 'k-')
    
    core.do_step() # 2
    assert len(core.aggdag.waiting_list) > 1

    #for state in core.waiting_list:
    #    xs, ys = zip(*state.verts(core.plotman))
    #    plt.plot(xs, ys, 'k-')
    
    core.do_step() # pop
    assert not core.aggdag.waiting_list

    lpi = core.aggdag.get_cur_state().lpi

    # 3 constraints from basis matrix
    # 2 aggregation directions from premode arnoldi, +1 from null space
    # + 2 more aggregation directions from box (3rd is omited since it's exactly the same as null space direction)

    #print(lpi)
    #xs, ys = zip(*core.cur_state.verts(core.plotman))
    #plt.plot(xs, ys, 'r--')
    #plt.show()

    assert lpi.get_num_rows() == 3 + 2 * (5)
    assert lputil.is_point_in_lpi((-5, 2, 1), lpi)
Ejemplo n.º 19
0
def define_ha():
    '''make the hybrid automaton and return it'''

    ha = HybridAutomaton('Drivetrain')

    # dynamics variable order: [x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, t, affine]

    negAngle = ha.new_mode('negAngle')
    a_matrix = [ \
        [0, 0, 0, 0, 0, 0, 0.0833333333333333, 0, -1, 0, 0, 0, 0], \
        [13828.8888888889, -26.6666666666667, 60, 60, 0, 0, -5, -60, 0, 0, 0, 0, 716.666666666667], \
        [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5], \
        [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], \
        [0, 0, 0, 0, -714.285714285714, -0.04, 0, 0, 0, 714.285714285714, 0, 0, 0], \
        [-2777.77777777778, 3.33333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -83.3333333333333], \
        [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], \
        [100, 0, 0, 0, 0, 0, 0, -1000, -0.01, 1000, 0, 0, 3], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \
        [0, 0, 0, 0, 1000, 0, 0, 1000, 0, -2000, -0.01, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \
        ]
    negAngle.set_dynamics(a_matrix)
    # x1 <= -0.03
    negAngle.set_invariant([
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    ], [
        -0.03,
    ])

    deadzone = ha.new_mode('deadzone')
    a_matrix = [ \
        [0, 0, 0, 0, 0, 0, 0.0833333333333333, 0, -1, 0, 0, 0, 0], \
        [-60, -26.6666666666667, 60, 60, 0, 0, -5, -60, 0, 0, 0, 0, 300], \
        [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5], \
        [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], \
        [0, 0, 0, 0, -714.285714285714, -0.04, 0, 0, 0, 714.285714285714, 0, 0, 0], \
        [0, 3.33333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, -1000, -0.01, 1000, 0, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \
        [0, 0, 0, 0, 1000, 0, 0, 1000, 0, -2000, -0.01, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \
        ]
    deadzone.set_dynamics(a_matrix)
    # -0.03 <= x1 & x1 <= 0.03
    deadzone.set_invariant([
        [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    ], [
        0.03,
        0.03,
    ])

    posAngle = ha.new_mode('posAngle')
    a_matrix = [ \
        [0, 0, 0, 0, 0, 0, 0.0833333333333333, 0, -1, 0, 0, 0, 0], \
        [13828.8888888889, -26.6666666666667, 60, 60, 0, 0, -5, -60, 0, 0, 0, 0, -116.666666666667], \
        [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5], \
        [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], \
        [0, 0, 0, 0, -714.285714285714, -0.04, 0, 0, 0, 714.285714285714, 0, 0, 0], \
        [-2777.77777777778, 3.33333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83.3333333333333], \
        [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], \
        [100, 0, 0, 0, 0, 0, 0, -1000, -0.01, 1000, 0, 0, -3], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \
        [0, 0, 0, 0, 1000, 0, 0, 1000, 0, -2000, -0.01, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \
        ]
    posAngle.set_dynamics(a_matrix)
    # 0.03 <= x1
    posAngle.set_invariant([
        [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    ], [
        -0.03,
    ])

    negAngleInit = ha.new_mode('negAngleInit')
    a_matrix = [ \
        [0, 0, 0, 0, 0, 0, 0.0833333333333333, 0, -1, 0, 0, 0, 0], \
        [13828.8888888889, -26.6666666666667, 60, 60, 0, 0, -5, -60, 0, 0, 0, 0, 116.666666666667], \
        [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -5], \
        [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], \
        [0, 0, 0, 0, -714.285714285714, -0.04, 0, 0, 0, 714.285714285714, 0, 0, 0], \
        [-2777.77777777778, 3.33333333333333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -83.3333333333333], \
        [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], \
        [100, 0, 0, 0, 0, 0, 0, -1000, -0.01, 1000, 0, 0, 3], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], \
        [0, 0, 0, 0, 1000, 0, 0, 1000, 0, -2000, -0.01, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], \
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], \
        ]
    negAngleInit.set_dynamics(a_matrix)
    # t <= 0.2
    negAngleInit.set_invariant([
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
    ], [
        0.2,
    ])

    error = ha.new_mode('error')

    trans = ha.new_transition(negAngleInit, negAngle)
    # t >= 0.2
    trans.set_guard([
        [-0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -1, -0],
    ], [
        -0.2,
    ])

    trans = ha.new_transition(negAngle, deadzone)
    # x1 >= -0.03
    trans.set_guard([
        [-1, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0],
    ], [
        0.03,
    ])

    trans = ha.new_transition(deadzone, posAngle)
    # x1 >= 0.03
    trans.set_guard([
        [-1, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0],
    ], [
        -0.03,
    ])

    trans = ha.new_transition(deadzone, error)
    # x1 <= -0.03
    trans.set_guard([
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    ], [
        -0.03,
    ])

    trans = ha.new_transition(posAngle, error)
    # x1 <= 0.03
    trans.set_guard([
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    ], [
        0.03,
    ])

    return ha
Ejemplo n.º 20
0
def make_automaton(theta_deg, maxi=20):
    'make the hybrid automaton'

    ha = HybridAutomaton('Gearbox')

    # variables
    variables = ["px", "py", "vx", "vy", "I"]
    derivatives = ["vx", "vy", "Fs/ms", "-Rs*Tf/Jg2", "0"]

    constant_dict = {
        "zeta": 0.9,
        "ms": 3.4,
        "mg2": 18.1,
        "Jg2": 0.7,
        "Rs": 0.08,
        "theta": theta_deg * math.pi / 180,  #0.628318530717959,
        "deltap": -0.003,
        "Fs": 70,
        "Tf": 1
    }

    ############## Modes ##############
    move_free = ha.new_mode('move_free')
    #
    a_mat = symbolic.make_dynamics_mat(variables,
                                       derivatives,
                                       constant_dict,
                                       has_affine_variable=True)
    move_free.set_dynamics(a_mat)

    invariant = f"px<=deltap & py<=-px*0.726542528005361 & py>=px*0.726542528005361 & I <= {maxi}"
    mat, rhs = symbolic.make_condition(variables,
                                       invariant.split('&'),
                                       constant_dict,
                                       has_affine_variable=True)
    move_free.set_invariant(mat, rhs)

    meshed = ha.new_mode('meshed')
    a_mat = np.zeros((6, 6))
    meshed.set_dynamics(a_mat)

    # error mode
    error = ha.new_mode('error')

    ############## Cyclic Transitions ##############
    # t1
    t1 = ha.new_transition(move_free, move_free, "t1")
    t1_guard = "py>=-px*0.726542528005361 & vx*0.587785252292473+vy*0.809016994374947>=0 & px <= deltap"
    mat, rhs = symbolic.make_condition(variables,
                                       t1_guard.split('&'),
                                       constant_dict,
                                       has_affine_variable=True)
    t1.set_guard(mat, rhs)

    # projection of a point onto a plane
    # if <x, y> is the point and <nx, ny> is the normal to the plane with mag 1
    # proj = <x, y> - (<x, y> dot <nx, ny>) * <nx, ny>
    nx = math.cos(math.pi / 2 - constant_dict['theta'])
    ny = math.sin(math.pi / 2 - constant_dict['theta'])

    i_reset = "I+(vx*0.587785252292473+vy*0.809016994374947)*(zeta+1)*ms*mg2/(ms*(0.809016994374947*0.809016994374947)+mg2*(0.587785252292473*0.587785252292473))"
    resets = [
        f"px - (px*{nx} + py*{ny}) * {nx}", f"py - (px*{nx} + py*{ny}) * {ny}",
        "(vx*(ms*0.809016994374947*0.809016994374947-mg2*zeta*0.587785252292473*0.587785252292473)+vy*(-(zeta+1)*mg2*0.587785252292473*0.809016994374947))/(ms*(0.809016994374947*0.809016994374947)+mg2*(0.587785252292473*0.587785252292473))",
        "(vx*(-(zeta+1)*ms*0.587785252292473*0.809016994374947)+vy*(mg2*0.587785252292473*0.587785252292473-ms*zeta*0.809016994374947*0.809016994374947))/(ms*(0.809016994374947*0.809016994374947)+mg2*(0.587785252292473*0.587785252292473))",
        i_reset
    ]
    reset_mat = symbolic.make_reset_mat(variables,
                                        resets,
                                        constant_dict,
                                        has_affine_variable=True)
    t1.set_reset(reset_mat)

    # T1 to error mode
    t1_to_error = ha.new_transition(move_free, error, "t1_to_error")
    guard = f"{t1_guard} & {i_reset}>={maxi}"
    mat, rhs = symbolic.make_condition(variables,
                                       guard.split('&'),
                                       constant_dict,
                                       has_affine_variable=True)
    t1_to_error.set_guard(mat, rhs)
    t1_to_error.set_reset(reset_mat)

    # t2
    t2 = ha.new_transition(move_free, move_free, "t2")
    t2_guard = "py<=px*0.726542528005361 & vx*0.587785252292473-vy*0.809016994374947>=0 & px <= deltap"
    mat, rhs = symbolic.make_condition(variables,
                                       t2_guard.split('&'),
                                       constant_dict,
                                       has_affine_variable=True)
    t2.set_guard(mat, rhs)

    ny = -ny

    i_reset = "I+(vx*0.587785252292473-vy*0.809016994374947)*(zeta+1)*ms*mg2/(ms*(0.809016994374947*0.809016994374947)+mg2*(0.587785252292473*0.587785252292473))"
    resets = [
        f"px - (px*{nx} + py*{ny}) * {nx}", f"py - (px*{nx} + py*{ny}) * {ny}",
        "(vx*(ms*0.809016994374947*0.809016994374947-mg2*zeta*0.587785252292473*0.587785252292473)+vy*((zeta+1)*mg2*0.587785252292473*0.809016994374947))/(ms*(0.809016994374947*0.809016994374947)+mg2*(0.587785252292473*0.587785252292473))",
        "(vx*((zeta+1)*ms*0.587785252292473*0.809016994374947)+vy*(mg2*0.587785252292473*0.587785252292473-ms*zeta*0.809016994374947*0.809016994374947))/(ms*(0.809016994374947*0.809016994374947)+mg2*(0.587785252292473*0.587785252292473))",
        i_reset
    ]
    reset_mat = symbolic.make_reset_mat(variables,
                                        resets,
                                        constant_dict,
                                        has_affine_variable=True)
    t2.set_reset(reset_mat)

    # T2 to error mode
    t2_to_error = ha.new_transition(move_free, error, "t2_to_error")
    guard = f"{t2_guard} & {i_reset}>={maxi}"
    mat, rhs = symbolic.make_condition(variables,
                                       guard.split('&'),
                                       constant_dict,
                                       has_affine_variable=True)
    t2_to_error.set_guard(mat, rhs)
    t2_to_error.set_reset(reset_mat)

    #### transitions to meshed

    guards = [
        "px >= deltap & vx >= 0 & vy >= 0", "px >= deltap & vx >= 0 & vy <= 0",
        "px >= deltap & vx <= 0 & vy >= 0", "px >= deltap & vx <= 0 & vy <= 0"
    ]

    i_resets = [
        "I+ms*vx+ms*vy", "I+ms*vx-ms*vy", "I-ms*vx+ms*vy", "I-ms*vx-ms*vy"
    ]

    for i, (guard, i_reset) in enumerate(zip(guards, i_resets)):
        t3 = ha.new_transition(move_free, meshed, f"meshed_{i}")

        t3_guard = guard + f" & I <= {maxi}"
        mat, rhs = symbolic.make_condition(variables,
                                           t3_guard.split('&'),
                                           constant_dict,
                                           has_affine_variable=True)
        t3.set_guard(mat, rhs)

        resets = [f"px", f"py", "0", "0", i_reset]
        reset_mat = symbolic.make_reset_mat(variables,
                                            resets,
                                            constant_dict,
                                            has_affine_variable=True)
        t3.set_reset(reset_mat)

        # T3 to error mode
        t3_to_error = ha.new_transition(move_free, error, f"t3_to_error_{i}")
        t3_err_guard = guard + f" & I >= {maxi}"
        mat, rhs = symbolic.make_condition(variables,
                                           t3_err_guard.split('&'),
                                           constant_dict,
                                           has_affine_variable=True)
        t3_to_error.set_guard(mat, rhs)

    return ha
Ejemplo n.º 21
0
def test_plain():
    'test plain aggregation of states across discrete transitions'

    # m1 dynamics: x' == 1, y' == 0, x0, y0: [0, 1], step: 1.0
    # m1 invariant: x <= 3
    # m1 -> m2 guard: True
    # m2 dynamics: x' == 0, y' == 1
    # time bound: 4
    # excepted final states to be: x: [0, 4], y: [4,5]
    # x is [1, 4] because no transitions are allowed at step 0 (simulation-equiv semantics) and a transition is
    #        allowed one step after the invariant becomes false
    # y is [4,5] because after aggregation, the time elapsed for the aggregated set will be 0.0, the minimum

    ha = HybridAutomaton()

    # mode one: x' = 1, y' = 0, a' = 0 
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 0, 1], [0, 0, 0], [0, 0, 0]])

    # mode two: x' = 0, y' = 1, a' = 0 
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, 0, 0], [0, 0, 1], [0, 0, 0]])

    # invariant: x <= 3.0
    m1.set_invariant([[1, 0, 0]], [3.0])

    # guard: True
    trans1 = ha.new_transition(m1, m2, 'trans1')
    trans1.set_guard(csr_matrix((0, 0)), [])

    # initial set has x0 = [0, 1], t = [0, 1], a = 1
    init_lpi = lputil.from_box([(0, 1), (0, 1), (1, 1)], m1)
    init_list = [StateSet(init_lpi, m1)]

    # settings, step size = 1.0
    settings = HylaaSettings(1.0, 4.0)
    settings.stdout = HylaaSettings.STDOUT_DEBUG
    settings.plot.plot_mode = PlotSettings.PLOT_NONE
    settings.plot.store_plot_result = True

    core = Core(ha, settings)
    result = core.run(init_list)

    # check history
    state = result.last_cur_state

    assert state.mode == m2
    assert len(state.aggdag_op_list) > 1
    
    op0 = state.aggdag_op_list[0]
    op1 = state.aggdag_op_list[1]
    assert isinstance(op0, OpTransition)

    assert len(core.aggdag.roots) == 1
   
    assert op0.child_node.stateset.mode is m2
    assert op0.transition == trans1
    assert op0.parent_node == core.aggdag.roots[0]
    assert isinstance(op0.poststate, StateSet)
    assert op0.step == 1
    assert isinstance(op0.child_node, AggDagNode)
    assert op0.child_node == op1.child_node
    assert op0.child_node not in core.aggdag.roots

    assert len(op0.parent_node.stateset.aggdag_op_list) == 1
    assert op0.parent_node.stateset.aggdag_op_list[0] is None
     
    # check polygons in m2
    polys2 = [obj[0] for obj in result.plot_data.mode_to_obj_list[0]['m2']]

    assert 4 <= len(polys2) <= 5

    assert_verts_is_box(polys2[0], [[1, 4], [0, 1]])
    assert_verts_is_box(polys2[1], [[1, 4], [1, 2]])
    assert_verts_is_box(polys2[2], [[1, 4], [2, 3]])
    assert_verts_is_box(polys2[3], [[1, 4], [3, 4]])
Ejemplo n.º 22
0
def fail_deagg_counterexample():
    'test that aggregation with a counterexample'
    # init: x0, y0 \in [0, 1], step = 1.0
    #
    # m1 dynamics: x' == 1, y' == 0,
    # m1 invariant: x <= 3
    # m1 -> m2 guard: True
    # m2 dynamics: x' == 0, y' == 1
    # m2 -> error: y >= 3

    ha = HybridAutomaton()

    # mode one: x' = 1, y' = 0, a' = 0
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 0, 1], [0, 0, 0], [0, 0, 0]])

    # mode two: x' = 0, y' = 1, a' = 0
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, 0, 0], [0, 0, 1], [0, 0, 0]])

    # invariant: x <= 3.0
    m1.set_invariant([[1, 0, 0]], [3.0])

    # guard: True
    trans1 = ha.new_transition(m1, m2, 'trans1')
    trans1.set_guard_true()

    error = ha.new_mode('error')
    trans2 = ha.new_transition(m2, error, 'trans2')
    trans2.set_guard([[0, -1, 0]], [-3])  # y >= 3

    # initial set has x0 = [0, 1], t = [0, 1], a = 1
    init_lpi = lputil.from_box([(0, 1), (0, 1), (1, 1)], m1)
    init_list = [StateSet(init_lpi, m1)]

    # settings, step size = 1.0
    settings = HylaaSettings(1.0, 10.0)
    settings.stdout = HylaaSettings.STDOUT_VERBOSE
    settings.plot.plot_mode = PlotSettings.PLOT_NONE
    settings.aggregation.deaggregation = True

    core = Core(ha, settings)

    core.setup(init_list)

    core.do_step()  # pop

    assert core.aggdag.cur_node is not None

    for _ in range(5):  # 4 + 1 step to leave invariant
        core.do_step()  # continuous post in m1

    core.do_step()  # pop

    # at this point, the state should be aggregated, but we should maintain one concrete state that's feasible
    cur_node = core.aggdag.cur_node
    assert cur_node.aggregated_state == core.aggdag.get_cur_state()

    assert cur_node.concrete_state is not None

    assert len(core.aggdag.roots) == 1
    root = core.aggdag.roots[0]

    assert root.op_list
    assert isinstance(
        root.op_list[0],
        OpTransition) and root.op_list[0].step == 1  # transition from x=[1, 2]
    assert isinstance(
        root.op_list[1],
        OpTransition) and root.op_list[1].step == 2  # transition from x=[2, 3]
    assert isinstance(
        root.op_list[2],
        OpTransition) and root.op_list[2].step == 3  # transition from x=[3, 4]
    assert isinstance(
        root.op_list[3],
        OpTransition) and root.op_list[3].step == 4  # transition from x=[4, 5]

    for s in range(4):
        assert root.op_list[s].transition == trans1 and root.op_list[
            s].poststate.is_concrete

    assert isinstance(root.op_list[4], OpInvIntersect)
    op4 = root.op_list[4]
    assert op4.step == 5 and op4.node == root and op4.i_index == 0 and not op4.is_stronger

    assert isinstance(
        root.op_list[5],
        OpTransition) and root.op_list[5].step == 5  # transition from x=[4, 4]

    assert isinstance(root.op_list[6], OpInvIntersect)
    op6 = root.op_list[6]
    assert op6.step == 6 and op6.node == root and op6.i_index == 0 and op6.is_stronger

    assert len(root.op_list) == 7

    core.run_to_completion()

    assert root.op_list[0].child_node == cur_node
    assert root.op_list[3].child_node == cur_node
Ejemplo n.º 23
0
def test_tt_09():
    'test time-triggered transition at 0.9 bug'

    # this test is from an issue reported by Mojtaba Zarei
    tt_time = 0.9
    
    ha = HybridAutomaton()

    # the test seems to be sensitive to the a_matrix... my guess is the LP is barely feasible at the tt_time
    a_matrix = np.array(
        [[6.037291088, -4.007840286, 2.870370645, 43.12729646, 10.06751155, 23.26084098, -0.001965587832, 0, 0],
         [3.896645707, -0.03417905392, -9.564966476, 15.25894014, -21.57196438, 16.60548055, 0.03473846441, 0, 0],
         [22.72995871, 14.12055097, -0.9315267908, 136.9851951, -71.66383111, 109.7143863, 0.1169799769, 0, 0],
         [-38.16694597, 3.349061908, -9.10171149, -185.1866526, 9.210877185, -165.8086527, -0.06858712649, 0, 0],
         [46.78596597, 27.7996521, 17.18120319, 285.4632424, -135.289626, 235.9427441, 0.228154713, 0, 0],
         [-8.31135303, 3.243945466, -4.523811735, -39.26067436, -9.385678542, -36.63193931, -0.0008874747046, 0, 0],
         [0, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 0, 0, 0, 1],
         [0, 0, 0, 0, 0, 0, 0, 0, 0]], dtype=float)

    mode1 = ha.new_mode('mode')
    mode1.set_dynamics(a_matrix)

    # time-triggered invariant: t <= tt_time
    mat = np.array([[0, 0, 0, 0, 0, 0, 0, 1, 0]], dtype=float)
    rhs = [tt_time]

    mode1.set_invariant(mat, rhs)
    
    mode2 = ha.new_mode('mode2')
    mode2.set_dynamics(a_matrix)

    # transition, guard: x >= -2 & y > 4 & t >= tt_time

    # transition, guard: t >= 0.9
    mat = np.array([[0, 0, 0, 0, 0, 0, 0, -1, 0]], dtype=float)
    rhs = [-tt_time]
    
    t = ha.new_transition(mode1, mode2)
    t.set_guard(mat, rhs)

    # initial set
    init_box = np.array([[-0.1584, -0.1000],
                         [-0.0124, 0.0698],
                         [-0.3128, 0.0434],
                         [-0.0208, 0.0998],
                         [-0.4895, 0.1964],
                         [-0.0027, 0.0262],
                         [42.40, 42.5],
                         [0, 0], # t(0) = 0
                         [1, 1]]) # affine(0) = 1
    
    init_lpi = lputil.from_box(init_box, mode1)
    init_list = [StateSet(init_lpi, mode1)]

    # settings
    settings = HylaaSettings(0.05, 1.0)
    settings.stdout = HylaaSettings.STDOUT_DEBUG
    settings.plot.store_plot_result = True
    settings.plot.plot_mode = PlotSettings.PLOT_NONE #INTERACTIVE

    #settings.plot.xdim_dir = 7 #None
    #settings.plot.ydim_dir = 0
    
    core = Core(ha, settings)
    result = core.run(init_list)

    mode2_list = result.plot_data.mode_to_obj_list[0]['mode2']
    assert len(mode2_list) == 3, f"mode2_list len was {len(mode2_list)}, expected 3 (0.9, 0.95, 1.0)"
class F1Hylaa:
    def __init__(self):

        # ------------------ Semi-Static Configuration ----------------------
        self.settings = None  #hylaa settings object
        self.dt = None  #dt from MPC metdata
        self.ttime = None

        self.input_uncertainty = []
        self.state_uncertainty = []

        self.model = None  #dynamics abstraction object

        #TODO automatic or otherwise validated variability
        # ------------------ Per-run Configuration ----------------------
        self.ha = None
        self.predictions = None  #predictions from MPC 3d array : [ dt[ state[x,y,psi], inputs[d,v] ] ]
        self.modeList = []
        self.initialState = None

    def set_model_params(self,
                         state_uncertainty,
                         input_uncertainty,
                         dynamics_module="kinematics_model"):
        model_gen = importlib.import_module(dynamics_module)
        self.modeList = []
        self.state_uncertainty = state_uncertainty
        self.input_uncertainty = input_uncertainty
        self.model = model_gen.getModel()
        self.model.setInputUncertainty(input_uncertainty)

        return 1

    def run_hylaa(self, predictions):
        self.ha = None
        self.predictions = None
        self.modeList = []
        self.initialState = None

        self.ha = HybridAutomaton()
        self.predictions = predictions
        self.graphPredictions()
        self.make_automaton()

        initialBox = self.make_init(self.predictions[0][0])
        core = Core(self.ha, self.settings)
        profile.runctx(
            'resultprof = self.run_hylaa_profile(initialBox, core)',
            globals(),
            locals(),
            filename=
            "/home/nvidia/f1racing/f110_ws/src/ppcm/reachability/scripts/profiler/prof/out_tmp.prof"
        )
        result = locals()['resultprof']
        #result = core.run(initialBox)
        reachsets = [
            result.plot_data.get_verts_list(mode)[0] for mode in self.modeList
        ]

        return reachsets

    def run_hylaa_profile(self, initialBox, core):
        return core.run(initialBox)

    def make_settings(self,
                      dt,
                      total,
                      displayType,
                      verbosity,
                      fileName="hylaa_reach.png"):
        #rospy.loginfo("SETTINGS CREATED WITH dt={}, total={}".format(dt, total))
        self.dt = dt
        self.ttime = total

        'make the reachability settings object'

        # see hylaa.settings for a list of reachability settings
        settings = HylaaSettings(dt, total)
        settings.optimize_tt_transitions = True
        settings.plot.filename = fileName

        #wwe want to store the reach set cuz that is the whole point of this
        settings.plot.store_plot_result = True

        settings.plot.plot_mode = PlotSettings.PLOT_IMAGE
        settings.stdout = HylaaSettings.STDOUT_VERBOSE

        if displayType == "NONE":
            settings.plot.plot_mode = PlotSettings.PLOT_NONE
        elif displayType == "IMAGE":
            settings.plot.plot_mode = PlotSettings.PLOT_IMAGE
        elif displayType == "VIDEO":
            settings.plot.plot_mode = PlotSettings.PLOT_VIDEO
        else:
            #rospy.logwarn("Invalid hylaa plot type specified, default=NONE used")
            settings.plot.plot_mode = PlotSettings.PLOT_NONE
        #rospy.loginfo("Using HYLAA setting: plot_mode = {}".format(displayType))

        if verbosity == "NONE":
            settings.stdout = HylaaSettings.STDOUT_NONE
        elif verbosity == "VERBOSE":
            settings.stdout = HylaaSettings.STDOUT_VERBOSE
        else:
            #rospy.logwarn("WARNING: Invalid hylaa output verbosity specified, default=VERBOSE used")
            settings.stdout = HylaaSettings.STDOUT_VERBOSE
        #rospy.loginfo("Using HYLAA setting: stdout = {}".format(verbosity))

        if displayType != "NONE":
            settings.plot.xdim_dir = [0, 6]
            settings.plot.ydim_dir = [1, 2]
            settings.plot.label = [LabelSettings(), LabelSettings()]

            xyplot = settings.plot.label[0]
            ytplot = settings.plot.label[1]
            #xy plot
            xyplot.big(size=26)
            xyplot.title = "Linearized Kinematics"
            xyplot.x_label = "X Position"
            xyplot.y_label = "Y Position"

            #yaw time plot
            ytplot.big(size=26)
            ytplot.title = "Yaw Vs Time"
            ytplot.x_label = "Time"
            ytplot.y_label = "Yaw"

            #plot the predicted trajectory (MPC output)
            nl_Circles = None

        self.settings = settings
        return 1

    def graphPredictions(self):
        if True:  #self.graph_predictions:
            nl_Centers = [(state[0], state[1])
                          for state, _ in self.predictions]
            nl_Patches = [Ellipse(center, .2, .2) for center in nl_Centers]
            nl_Circles = collections.PatchCollection(nl_Patches,
                                                     facecolors='red',
                                                     edgecolors='black',
                                                     zorder=1000)

            nl_yaw_centers = [(self.dt * pidx, self.predictions[pidx][0][2])
                              for pidx in range(len(self.predictions))]
            nl_yaw_patches = [
                Ellipse(center, self.dt / 8, 3.14 / 32)
                for center in nl_yaw_centers
            ]
            nl_yaw_circles = collections.PatchCollection(nl_yaw_patches,
                                                         facecolors='red',
                                                         edgecolors='black',
                                                         zorder=-1)

            self.settings.plot.extra_collections = [[nl_Circles],
                                                    [nl_yaw_circles]]

    def make_init(self, initialState):
        'make the initial states'
        # initial set has every variable as [-0.1, 0.1]
        mode = self.ha.modes['m0']

        dims = mode.a_csr.shape[0]
        without_time_dim = dims - 2
        pure_state_dim = without_time_dim // 2
        init_box = [(0, 0)] * (pure_state_dim)
        lin_box = [(1, 1)] * (pure_state_dim)
        time_init = [(0.0, 0.0), (1.0, 1.0)]

        #initial state = state uncertainty + linear var uncertainty + time uncertainty(0)
        #we assume the uncertainty is symettrical for x, y, yaw
        for s in range(len(init_box)):
            init_box[s] = (initialState[s] - self.state_uncertainty[s],
                           initialState[s] + self.state_uncertainty[s])
        init_box += lin_box + time_init
        #print(init_box)
        init_lpi = lputil.from_box(init_box, mode)

        init_list = [StateSet(init_lpi, mode)]

        return init_list

    #generated modes IN PLACE on given ha, filling with given inputs
    def make_automaton(self):

        modeIncrement = 0
        lastMode = None
        for state, inputs in self.predictions[:int(self.ttime / self.dt)]:

            #get the dynamics linearized around this state/input set
            dynamics = self.model.linearized_dynamics(state[:3], inputs,
                                                      self.dt)

            modeName = 'm{}'.format(modeIncrement)
            mode = self.ha.new_mode(modeName)
            self.modeList.append(modeName)

            a_matrix = dynamics['A']
            b_matrix = dynamics['B']
            mode.set_dynamics(a_matrix)

            bounds_mat = dynamics["bounds_mat"]
            bounds_rhs = dynamics["bounds_rhs"]
            mode.set_inputs(b_matrix,
                            bounds_mat,
                            bounds_rhs,
                            allow_constants=True)

            offsetTime = 1e-4
            criticalTime = self.dt * modeIncrement  #using time offset frome rendevous example

            invariant_mat = dynamics["invariant_mat"]

            #TODO add configurable ciritical time variance
            invariant_rhs = [criticalTime + offsetTime]
            mode.set_invariant(invariant_mat, invariant_rhs)

            if lastMode:
                t = self.ha.new_transition(lastMode, mode)
                guard_mat = dynamics["guard_mat"]
                guard_rhs = [-criticalTime + offsetTime
                             ]  #time from last state is bound
                t.set_guard(guard_mat, guard_rhs)

            lastMode = mode
            modeIncrement += 1
Ejemplo n.º 25
0
def test_tt_split():
    'tests time-triggered dynamics where the state is split (based on state) after some amount of time elapses'

    ha = HybridAutomaton()

    # dynamics variable order: [x0, x1, x2, x3, u, t, affine]
    pole = ha.new_mode('pole')
    a_matrix = [ \
        [0, 1, 0, 0, 0, 0, 0], \
        [0, 0, 0.7164, 0, 0.9755, 0, 0], \
        [0, 0, 0, 1, 0, 0, 0], \
        [0, 0, 0.76, 0, 0.46, 0, 0], \
        [0, 0, 0, 0, 0, 0, 0], \
        [0, 0, 0, 0, 0, 0, 1], \
        [0, 0, 0, 0, 0, 0, 0], \
        ]
    pole.set_dynamics(a_matrix)
    # 0.0 <= t & t <= 0.1
    pole.set_invariant([[0, 0, 0, 0, 0, -1, 0], [0, 0, 0, 0, 0, 1, 0], ], [0, 0.1, ])

    trans = ha.new_transition(pole, pole, 'b2')
    # x3 <= 1.0229164510965 & x2 <= 2.0244571492076 & x3 > -10.0172335505486 & x2 <= 1.0329331979156 & t >= 0.1
    trans.set_guard([[0, 0, 0, 1, 0, 0, 0],
                     [0, 0, 1, 0, 0, 0, 0],
                     [-0, -0, -0, -1, -0, -0, -0],
                     [0, 0, 1, 0, 0, 0, 0], 
                     [-0, -0, -0, -0, -0, -1, -0],
                    ], [1.0229164510965, 2.0244571492076, 10.0172335505486, 1.0329331979156, -0.1, ])

    # Reset:
    # t := 0.0
    # u := 0.2
    reset_mat = [ \
        [1, 0, 0, 0, 0, 0, 0, ], \
        [0, 1, 0, 0, 0, 0, 0, ], \
        [0, 0, 1, 0, 0, 0, 0, ], \
        [0, 0, 0, 1, 0, 0, 0, ], \
        [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], \
        [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ], \
        [0, 0, 0, 0, 0, 0, 1, ], \
        ]
    reset_minkowski = [ \
        [0, ], \
        [0, ], \
        [0, ], \
        [0, ], \
        [1, ], \
        [0, ], \
        [0, ], \
        ]
    minkowski_constraints = [ \
        [1, ], \
        [-1, ], \
        ]
    minkowski_rhs = [0.2, -0.2]
    trans.set_reset(reset_mat, reset_minkowski, minkowski_constraints, minkowski_rhs)

    # manually run ha.detect_tt_transitions() and check the result
    def print_none(str):
        'suppress printing'
        pass
    
    settings = HylaaSettings(0.05, 0.15)
    settings.plot.plot_mode = PlotSettings.PLOT_IMAGE
    settings.plot.xdim_dir = 0
    settings.plot.ydim_dir = 3
    settings.stdout = HylaaSettings.STDOUT_DEBUG

    init_list = []
    mode = ha.modes['pole']
    mat = [[1, 0, 0, 0, 0, 0, 0], \
        [-1, -0, -0, -0, -0, -0, -0], \
        [0, 1, 0, 0, 0, 0, 0], \
        [-0, -1, -0, -0, -0, -0, -0], \
        [0, 0, 1, 0, 0, 0, 0], \
        [-0, -0, -1, -0, -0, -0, -0], \
        [0, 0, 0, -1, 0, 0, 0], \
        [0, 0, 0, 1, 0, 0, 0], \
        [0, 0, 0, 0, 1, 0, 0], \
        [-0, -0, -0, -0, -1, -0, -0], \
        [0, 0, 0, 0, 0, 1, 0], \
        [-0, -0, -0, -0, -0, -1, -0], \
        [0, 0, 0, 0, 0, 0, 1], \
        [-0, -0, -0, -0, -0, -0, -1], ]
        
    rhs = [0, -0, 0, -0, 0, -0, 1.3, -1.3, 0, -0, 0, -0, 1, -1, ]
    init_list.append(StateSet(lputil.from_constraints(mat, rhs, mode), mode))

    core = Core(ha, settings)
    result = core.run(init_list)    # expect no exception during running

    assert result.last_cur_state.cur_steps_since_start[0] == 3
    assert result.last_cur_state.cur_steps_since_start[1] == 3
Ejemplo n.º 26
0
def test_inputs_reset():
    'test a system with both inputs and a reset'

    # 2-d system with one input
    # x' = x, y' = u, u \in [1, 1]
    # x0 = 1, y0 = 0
    # inv1: y <= 2.5
    
    # guard: y >= 2.5
    # reset: x := 1, y += 2 [should go from (e^3, 3.0) -> (1, 5.0)]

    # mode2:
    # x' = 2x, y' = Bu, u \in [1, 2], B = 2
    # (1, 5.0) -> (e^2, [7, 9]) -> (e^4, [9, 13])

    # mode2 -> error y >= 13

    ha = HybridAutomaton()
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[1, 0], [0, 0]])
    m1.set_inputs([[0], [1]], [[1], [-1]], [1, -1], allow_constants=True)
    m1.set_invariant([[0, 1]], [2.5])

    m2 = ha.new_mode('m2')
    m2.set_dynamics([[2, 0], [0, 0]])
    m2.set_inputs([[0], [2]], [[1], [-1]], [2, -1])

    error = ha.new_mode('error')

    t1 = ha.new_transition(m1, m2)
    t1.set_guard([[0, -1]], [-2.5]) # y >= 2.5
    reset_mat = [[0, 0], [0, 1]]
    min_mat = np.identity(2)
    min_cons = [[1, 0], [-1, 0], [0, 1], [0, -1]]
    min_rhs = [1, -1, 2, -2]
    t1.set_reset(reset_mat, min_mat, min_cons, min_rhs)

    t2 = ha.new_transition(m2, error)
    t2.set_guard([0, -1], [-13]) # y >= 13

    init_box = [[1, 1], [0, 0]]
    lpi = lputil.from_box(init_box, m1)

    settings = HylaaSettings(1.0, 10.0)
    settings.stdout = HylaaSettings.STDOUT_VERBOSE
    settings.plot.store_plot_result = True
    settings.plot.plot_mode = PlotSettings.PLOT_NONE

    core = Core(ha, settings)
    init_list = [StateSet(lpi, m1)]
    core.setup(init_list)

    core.do_step() # pop
    core.do_step() # continuous_post() to time 1

    lpi = core.result.last_cur_state.lpi

    assert lpi.get_names() == ['m0_i0', 'm0_i1', 'm0_c0', 'm0_c1', 'm0_ti0', 'm0_ti1', 'm0_I0']

    assert_verts_is_box(lpplot.get_verts(lpi), [[math.exp(1), math.exp(1)], [1, 1]])

    core.do_step() # continuous_post() to time 2
    assert_verts_is_box(lpplot.get_verts(core.result.last_cur_state.lpi), [[math.exp(2), math.exp(2)], [2, 2]])

    core.do_step() # continuous_post() to time 3
    assert_verts_is_box(lpplot.get_verts(core.result.last_cur_state.lpi), [[math.exp(3), math.exp(3)], [3, 3]])

    core.do_step() # trim to invariant
    assert core.aggdag.get_cur_state() is None
    assert len(core.aggdag.waiting_list) == 1

    core.run_to_completion()

    result = core.result

    # reset: x := 1, y += 2 [should go from (e^3, 3.0) -> (1, 5.0)]
    # (1, 5.0) -> (e^2, [7, 9]) -> (e^4, [9, 13])
    polys2 = [obj[0] for obj in result.plot_data.mode_to_obj_list[0]['m2']]
    assert_verts_is_box(polys2[0], [[1, 1], [5, 5]])
    assert_verts_is_box(polys2[1], [[math.exp(2), math.exp(2)], [7, 9]])
    assert_verts_is_box(polys2[2], [[math.exp(4), math.exp(4)], [9, 13]])
    assert len(polys2) == 3

    # check counterexamples
    assert len(result.counterexample) == 2
    
    c1 = result.counterexample[0]
    assert c1.mode == m1
    assert c1.outgoing_transition == t1
    assert np.allclose(c1.start, [1, 0])
    assert np.allclose(c1.end, [math.exp(3), 3])
    assert len(c1.reset_minkowski_vars) == 2
    assert abs(c1.reset_minkowski_vars[0] - 1) < 1e-9
    assert abs(c1.reset_minkowski_vars[1] - 2) < 1e-9

    assert len(c1.inputs) == 3
    for i in c1.inputs:
        assert len(i) == 1
        assert abs(i[0] - 1) < 1e-9

    c2 = result.counterexample[1]
    assert c2.mode == m2
    assert c2.outgoing_transition == t2
    assert np.allclose(c2.start, [1, 5])
    assert np.allclose(c2.end, [math.exp(4), 13])
    assert not c2.reset_minkowski_vars
    assert len(c2.inputs) == 2

    for i in c2.inputs:
        assert len(i) == 1
        assert abs(i[0] - 2) < 1e-9
Ejemplo n.º 27
0
def make_automaton(abortmin, abortmax):
    'make the hybrid automaton'

    safe = True
    ha = HybridAutomaton('Spacecraft Rendezvous with Abort')
    rad = 5.0

    passive_min_time = abortmin
    passive_max_time = abortmax

    ############## Modes ##############
    p2 = ha.new_mode('Far')
    a_mat = [\
        [0.0, 0.0, 1.0, 0.0, 0.0, 0], \
        [0.0, 0.0, 0.0, 1.0, 0.0, 0], \
        [-0.057599765881773, 0.000200959896519766, -2.89995083970656, 0.00877200894463775, 0.0, 0], \
        [-0.000174031357370456, -0.0665123984901026, -0.00875351105536225, -2.90300269286856, 0.0, 0.0], \
        [0.0, 0.0, 0.0, 0.0, 0.0, 1.0], \
        [0, 0, 0, 0, 0, 0]]
    inv_mat = [[0.0, 0.0, 0.0, 0.0, 1.0, 0], [1.0, 0.0, 0.0, 0.0, 0.0, 0]]
    inv_rhs = [125.0, -100.0]
    p2.set_dynamics(a_mat)
    p2.set_invariant(inv_mat, inv_rhs)

    p3 = ha.new_mode('Approaching')
    a_mat = [\
        [0.0, 0.0, 1.0, 0.0, 0.0, 0], \
        [0.0, 0.0, 0.0, 1.0, 0.0, 0], \
        [-0.575999943070835, 0.000262486079431672, -19.2299795908647, 0.00876275931760007, 0.0, 0], \
        [-0.000262486080737868, -0.575999940191886, -0.00876276068239993, -19.2299765959399, 0.0, 0], \
        [0.0, 0.0, 0.0, 0.0, 0.0, 1.],\
        [0, 0, 0, 0, 0, 0]]
    inv_mat = [\
        [-1.0, 0., 0., 0., 0., 0], \
        [1.0, 0., 0., 0., 0., 0], \
        [0., -1.0, 0., 0., 0., 0], \
        [0., 1.0, 0., 0., 0., 0], \
        [-1.0, -1.0, 0.0, 0.0, 0.0, 0], \
        [1.0, 1.0, 0.0, 0.0, 0.0, 0], \
        [-1.0, 1.0, 0., 0., 0., 0], \
        [1.0, -1.0, 0., 0., 0., 0], \
        [0., 0., 0., 0., 1., 0]]
    inv_rhs = [
        100, 100, 100, 100, 141.1, 141.1, 141.1, 141.1, passive_max_time
    ]
    p3.set_dynamics(a_mat)
    p3.set_invariant(inv_mat, inv_rhs)

    passive = ha.new_mode('Abort')
    a_mat = [\
         [0, 0, 1, 0, 0, 0], \
         [0, 0, 0, 1, 0, 0], \
         [0.0000575894721132000, 0, 0, 0.00876276, 0, 0], \
         [0, 0, -0.00876276, 0, 0, 0], \
         [0, 0, 0, 0, 0, 1.], \
         [0, 0, 0, 0, 0, 0]]
    passive.set_dynamics(a_mat)

    error = ha.new_mode('Error')

    ############## Normal Transitions ##############
    t1 = ha.new_transition(p2, p3)
    guard_mat = [\
        [-1.0, 0., 0., 0., 0., 0], \
        [1.0, 0., 0., 0., 0., 0], \
        [0., -1.0, 0., 0., 0., 0], \
        [0., 1.0, 0., 0., 0., 0], \
        [-1.0, -1.0, 0.0, 0.0, 0.0, 0], \
        [1.0, 1.0, 0.0, 0.0, 0.0, 0], \
        [-1.0, 1.0, 0., 0., 0., 0], \
        [1.0, -1.0, 0., 0., 0., 0]]
    guard_rhs = [100, 100, 100, 100, 141.1, 141.1, 141.1, 141.1]
    t1.set_guard(guard_mat, guard_rhs)

    ha.new_transition(p2, passive).set_guard([[0.0, 0.0, 0.0, 0.0, -1.0, 0]],
                                             [-passive_min_time])

    ha.new_transition(p3, passive).set_guard([[0.0, 0.0, 0.0, 0.0, -1.0, 0]],
                                             [-passive_min_time])

    ############## Error Transitions ##############
    # In the aborting mode, the vehicle must avoid the target, which is modeled as a box B with
    # 0.2m edge length and the center placed as the origin

    # unsafe rad: 1.0
    #rad = 1.0

    t = ha.new_transition(passive, error)
    guard_mat = [ \
        [1, 0, 0., 0., 0., 0], \
        [-1, 0, 0., 0., 0., 0], \
        [0, 1., 0., 0., 0., 0], \
        [0, -1., 0., 0., 0., 0]]
    guard_rhs = [rad, rad, rad, rad]
    t.set_guard(guard_mat, guard_rhs)

    #In the rendezvous attempt the spacecraft must remain within the lineof-sight
    #cone L = {[x, y]^T | (x >= -100m) AND (y >= x*tan(30)) AND (-y >= x*tan(30))}
    #ha.new_transition(p3, error).set_guard([[1, 0, 0., 0., 0., 0]], [-100])
    #ha.new_transition(p3, error).set_guard([[-0.57735, 1, 0, 0., 0., 0]], [0])
    #ha.new_transition(p3, error).set_guard([[-0.57735, -1, 0., 0., 0., 0]], [0])

    # sqrt(vx^2 + vy^2) should stay below 0.055 m/SECOND (time in model is in MINUTES)
    # to make the model unsafe, try changing this to 0.05
    meters_per_sec_limit = 0.055 if safe else 0.05
    meters_per_min_limit = meters_per_sec_limit * 60
    h = meters_per_min_limit * math.cos(math.pi / 8.0)
    w = meters_per_min_limit * math.sin(math.pi / 8.0)

    #ha.new_transition(p3, error).set_guard([[0, 0, 1., 0., 0., 0]], [-h])
    #ha.new_transition(p3, error).set_guard([[0, 0, -1., 0., 0., 0]], [-h])
    #ha.new_transition(p3, error).set_guard([[0, 0, 0., 1., 0., 0]], [-h])
    #ha.new_transition(p3, error).set_guard([[0, 0, 0., -1., 0., 0]], [-h])

    #ha.new_transition(p3, error).set_guard([[0, 0, 1., 1., 0., 0]], [-(w + h)])
    #ha.new_transition(p3, error).set_guard([[0, 0, -1., 1., 0., 0]], [-(w + h)])
    #ha.new_transition(p3, error).set_guard([[0, 0, -1., -1., 0., 0]], [-(w + h)])
    #ha.new_transition(p3, error).set_guard([[0, 0, 1., -1., 0., 0]], [-(w + h)])

    return ha
Ejemplo n.º 28
0
def define_ha():
    '''make the hybrid automaton and return it'''

    ha = HybridAutomaton()

    # dynamics variable order: [x1, x2, t, affine]

    loc2 = ha.new_mode('loc2')
    a_matrix = [ \
        [0, 1, 0, 0], \
        [18300, -20, 0, -9562.5], \
        [0, 0, 0, 1], \
        [0, 0, 0, 0], \
        ]
    loc2.set_dynamics(a_matrix)
    # -x1 > -0.51 & -x1 <= -0.5
    loc2.set_invariant([[1, -0, -0, -0], [-1, 0, 0, 0], ], [0.51, -0.5, ])

    loc3 = ha.new_mode('loc3')
    a_matrix = [ \
        [0, 1, 0, 0], \
        [-825, -20, 0, 0], \
        [0, 0, 0, 1], \
        [0, 0, 0, 0], \
        ]
    loc3.set_dynamics(a_matrix)
    # -x1 > -0.5 & -x1 <= -0.09
    loc3.set_invariant([[1, -0, -0, -0], [-1, 0, 0, 0], ], [0.5, -0.09, ])

    loc4 = ha.new_mode('loc4')
    a_matrix = [ \
        [0, 1, 0, 0], \
        [30675, -695, 0, -2835], \
        [0, 0, 0, 1], \
        [0, 0, 0, 0], \
        ]
    loc4.set_dynamics(a_matrix)
    # -x1 > -0.09 & -x1 <= -0.08
    loc4.set_invariant([[1, -0, -0, -0], [-1, 0, 0, 0], ], [0.09, -0.08, ])

    loc1 = ha.new_mode('loc1')
    a_matrix = [ \
        [0, 1, 0, 0], \
        [-450, -20, 0, 0], \
        [0, 0, 0, 1], \
        [0, 0, 0, 0], \
        ]
    loc1.set_dynamics(a_matrix)
    # -x1 <= -0.51
    loc1.set_invariant([[-1, 0, 0, 0], ], [-0.51, ])

    loc5 = ha.new_mode('loc5')
    a_matrix = [ \
        [0, 1, 0, 0], \
        [-4762.5, -95, 0, 0], \
        [0, 0, 0, 1], \
        [0, 0, 0, 0], \
        ]
    loc5.set_dynamics(a_matrix)
    # -x1 > -0.08 & -x1 < 0.08
    loc5.set_invariant([[1, -0, -0, -0], [-1, 0, 0, 0], ], [0.08, 0.08, ])

    loc6 = ha.new_mode('loc6')
    a_matrix = [ \
        [0, 1, 0, 0], \
        [30675, -695, 0, 2835], \
        [0, 0, 0, 1], \
        [0, 0, 0, 0], \
        ]
    loc6.set_dynamics(a_matrix)
    # -x1 >= 0.08 & -x1 < 0.09
    loc6.set_invariant([[1, -0, -0, -0], [-1, 0, 0, 0], ], [-0.08, 0.09, ])

    loc7 = ha.new_mode('loc7')
    a_matrix = [ \
        [0, 1, 0, 0], \
        [-825, -20, 0, 0], \
        [0, 0, 0, 1], \
        [0, 0, 0, 0], \
        ]
    loc7.set_dynamics(a_matrix)
    # -x1 >= 0.09 & -x1 < 0.5
    loc7.set_invariant([[1, -0, -0, -0], [-1, 0, 0, 0], ], [-0.09, 0.5, ])

    loc8 = ha.new_mode('loc8')
    a_matrix = [ \
        [0, 1, 0, 0], \
        [18300, -20, 0, 9562.5], \
        [0, 0, 0, 1], \
        [0, 0, 0, 0], \
        ]
    loc8.set_dynamics(a_matrix)
    # -x1 >= 0.5 & -x1 < 0.51
    loc8.set_invariant([[1, -0, -0, -0], [-1, 0, 0, 0], ], [-0.5, 0.51, ])

    loc9 = ha.new_mode('loc9')
    a_matrix = [ \
        [0, 1, 0, 0], \
        [-450, -20, 0, 0], \
        [0, 0, 0, 1], \
        [0, 0, 0, 0], \
        ]
    loc9.set_dynamics(a_matrix)
    # -x1 >= 0.51
    loc9.set_invariant([[1, -0, -0, -0], ], [-0.51, ])

    trans = ha.new_transition(loc2, loc1)
    # -x1 <= -0.51
    trans.set_guard([[-1, 0, 0, 0], ], [-0.51, ])

    trans = ha.new_transition(loc2, loc3)
    # -x1 > -0.5
    trans.set_guard([[1, -0, -0, -0], ], [0.5, ])

    trans = ha.new_transition(loc3, loc4)
    # -x1 > -0.09
    trans.set_guard([[1, -0, -0, -0], ], [0.09, ])

    trans = ha.new_transition(loc3, loc2)
    # -x1 <= -0.5
    trans.set_guard([[-1, 0, 0, 0], ], [-0.5, ])

    trans = ha.new_transition(loc4, loc5)
    # -x1 > -0.08
    trans.set_guard([[1, -0, -0, -0], ], [0.08, ])

    trans = ha.new_transition(loc4, loc3)
    # -x1 <= -0.09
    trans.set_guard([[-1, 0, 0, 0], ], [-0.09, ])

    trans = ha.new_transition(loc1, loc2)
    # -x1 > -0.51
    trans.set_guard([[1, -0, -0, -0], ], [0.51, ])

    trans = ha.new_transition(loc5, loc6)
    # -x1 >= 0.0801
    trans.set_guard([[1, -0, -0, -0], ], [-0.0801, ])

    trans = ha.new_transition(loc5, loc4)
    # -x1 <= -0.0801
    trans.set_guard([[-1, 0, 0, 0], ], [-0.0801, ])

    trans = ha.new_transition(loc6, loc7)
    # -x1 >= 0.09
    trans.set_guard([[1, -0, -0, -0], ], [-0.09, ])

    trans = ha.new_transition(loc6, loc5)
    # -x1 < 0.08
    trans.set_guard([[-1, 0, 0, 0], ], [0.08, ])

    trans = ha.new_transition(loc7, loc8)
    # -x1 >= 0.5
    trans.set_guard([[1, -0, -0, -0], ], [-0.5, ])

    trans = ha.new_transition(loc7, loc6)
    # -x1 < 0.09
    trans.set_guard([[-1, 0, 0, 0], ], [0.09, ])

    trans = ha.new_transition(loc8, loc9)
    # -x1 >= 0.51
    trans.set_guard([[1, -0, -0, -0], ], [-0.51, ])

    trans = ha.new_transition(loc8, loc7)
    # -x1 < 0.5
    trans.set_guard([[-1, 0, 0, 0], ], [0.5, ])

    trans = ha.new_transition(loc9, loc8)
    # -x1 < 0.51
    trans.set_guard([[-1, 0, 0, 0], ], [0.51, ])

    return ha
Ejemplo n.º 29
0
def test_time_triggered():
    'test to make sure exact time-triggered guards only have a single sucessor state'

    ha = HybridAutomaton()

    # mode one: x' = 1, a' = 0 
    m1 = ha.new_mode('m1')
    m1.set_dynamics([[0, 1], [0, 0]])

    # mode two: x' = 1, a' = 0 
    m2 = ha.new_mode('m2')
    m2.set_dynamics([[0, 1], [0, 0]])

    # invariant: x <= 2.0
    m1.set_invariant([[1, 0]], [2.0])

    # guard: x >= 2.0
    trans1 = ha.new_transition(m1, m2, 'trans1')
    trans1.set_guard([[-1, 0]], [-2.0])

    # error x >= 4.0
    error = ha.new_mode('error')
    trans2 = ha.new_transition(m2, error, "to_error")
    trans2.set_guard([[-1, 0]], [-4.0])


    # manually run ha.detect_tt_transitions() and check the result
    ha.detect_tt_transitions()

    assert trans1.time_triggered
    assert not trans2.time_triggered # not time-triggered because invariant of m2 is True

    # initial set has x = 0, a = 1
    init_lpi = lputil.from_box([(0, 0), (1, 1)], m1)
    init_list = [StateSet(init_lpi, m1)]

    # settings, step size = 1.0
    settings = HylaaSettings(1.0, 10.0)
    settings.stdout = HylaaSettings.STDOUT_VERBOSE
    settings.plot.plot_mode = PlotSettings.PLOT_NONE
    settings.plot.store_plot_result = True

    result = Core(ha, settings).run(init_list)
    ce = result.counterexample

    assert len(ce) == 2
    assert ce[0].mode.name == 'm1'
    assert ce[0].outgoing_transition.name == 'trans1'

    assert ce[1].mode.name == 'm2'
    assert ce[1].outgoing_transition.name == 'to_error'

    assert abs(ce[0].start[0] - 0.0) < 1e-5
    assert abs(ce[0].end[0] - 2.0) < 1e-5

    assert abs(ce[1].start[0] - 2.0) < 1e-5
    assert abs(ce[1].end[0] - 4.0) < 1e-5

    polys = [obj[0] for obj in result.plot_data.mode_to_obj_list[0]['m1']]
    assert len(polys) == 3 # time 0, 1, 2

    polys = [obj[0] for obj in result.plot_data.mode_to_obj_list[0]['m2']]
    assert len(polys) == 3 # times 2, 3, 4