Example #1
0
def test_composite_module_topology():

    mgr = BDD()

    x = DynamicCover(0, 10)

    m1 = Interface(mgr, {'a': x}, {'b': x, 'i': x})
    m2 = Interface(mgr, {'i': x, 'j': x}, {'k': x})

    m12 = CompositeInterface((m1, m2))
    assert m12.sorted_mods() == ((m1, ), (m2, ))
    assert set(m12.outputs) == {'k', 'b', 'i'}
    assert set(m12.inputs) == {'a', 'j'}
    assert set(m12.latent) == {'i'}

    m3 = Interface(mgr, {'k': x, 'b': x}, {})

    m123 = CompositeInterface([m1, m2, m3])
    assert m123.sorted_mods() == ((m1, ), (m2, ), (m3, ))
    assert set(m123.outputs) == {'b', 'i', 'k'}
    assert set(m123.inputs) == {'a', 'j'}
    assert set(m123.vars) == {'a', 'j', 'b', 'i', 'k'}

    # Renaming
    m123renamed = m123.renamed(b='r', a='q')
    assert set(m123renamed.outputs) == {'r', 'i', 'k'}
    assert set(m123renamed.inputs) == {'q', 'j'}
Example #2
0
def setup():
    """
    Initialize binary circuit manager
    """
    mgr = BDD()
    mgr.configure(reordering=False)
    """
    Declare spaces and types
    """
    # Declare continuous state spaces
    pspace = DynamicCover(-2, 2)
    anglespace = DynamicCover(-np.pi, np.pi, periodic=True)
    # Declare discrete control spaces
    vspace = EmbeddedGrid(2, vmax / 2, vmax)
    angaccspace = EmbeddedGrid(3, -1.5, 1.5)
    """
    Declare interfaces
    """
    dubins_x = Interface(mgr, {
        'x': pspace,
        'theta': anglespace,
        'v': vspace
    }, {'xnext': pspace})
    dubins_y = Interface(mgr, {
        'y': pspace,
        'theta': anglespace,
        'v': vspace
    }, {'ynext': pspace})
    dubins_theta = Interface(mgr, {
        'theta': anglespace,
        'v': vspace,
        'omega': angaccspace
    }, {'thetanext': anglespace})

    return mgr, dubins_x, dubins_y, dubins_theta
Example #3
0
def test_series_comp():

    mgr = BDD()

    inputs = {
        'x': DynamicCover(0, 4),
        'y': DynamicCover(0, 4),
    }
    output = {'z': DynamicCover(0, 4)}

    h = Interface(mgr, inputs, output)
    g = ('j', 'y') >> h >> ('z', 'r')
    precision = {'j': 4, 'x': 3, 'r': 3}
    g = g.io_refined({
        'j': (.75, 2.5),
        'x': (2.5, 3.8),
        'r': (2.1, 3.1)
    },
                     nbits=precision)

    h = ('r', 'x') >> h
    h = h.io_refined({
        'r': (1.3, 3.8),
        'y': (1.0, 2.0),
        'z': (.9, 3.1)
    },
                     nbits={
                         'r': 3,
                         'y': 3,
                         'z': 4
                     })
    assert (g >> h) == g.composed_with(h)
    assert (g >> h) == h.composed_with(g)
    assert (g >> h).nonblock() != mgr.false
    assert (g >> h).count_nb(bits=10) == approx(28)  # 7 * 2 * 2
Example #4
0
    def run(self,
            steps: Optional[int] = None,
            winning: Optional[Interface] = None,
            verbose: bool = False):
        """
        Run a reachability game until reaching a fixed point or a maximum number of steps.

        Parameters
        ----------
        steps: int
            Maximum number of game steps to run
        winning: int
            Currently winning region
        verbose: bool
            If True (not default), then print out intermediate statistics.

        Returns
        -------
        Interface:
            Backward reachable set
        int:
            Number of game steps run
        MemorylessController:
                Controller for the reach game

        """
        if steps:
            assert steps >= 0

        state_control = self.cpre.prestate.copy()
        state_control.update(self.cpre.control)
        C = Interface(self.cpre.mgr, state_control, {})

        z = self.target if winning is None else winning
        zz = Interface(self.cpre.mgr, {}, {})  # Defaults to false interface.

        i = 0
        while (z != zz):
            if steps and i == steps:
                break

            zz = z
            step_start = time.time()
            z = self.cpre(zz, verbose=verbose)  # state-input pairs
            # TODO: Change this to shared refinement?
            C._assum = C.assum | (z.assum & ~self.cpre.elimcontrol(C.assum)
                                  )  # Add new state-input pairs to controller
            if verbose:
                print("Eliminating control")
            z = ihide(z, self.cpre.control)
            z = z + self.target

            i += 1
            if verbose:
                print("Step #: ", i, "Step Time (s): ",
                      time.time() - step_start, "Size: ",
                      self.cpre.mgr.count(z.assum, len(z.assum.support)),
                      "Winning nodes:", len(z.assum))

        return z, i, MemorylessController(self.cpre, C)
Example #5
0
def test_reachavoid():
    composite = CompositeInterface((pcomp, vcomp))
    dcpre = DecompCPre(composite, (('p', 'pnext'), ('v', 'vnext')), ('a'))

    target = pspace.conc2pred(mgr, 'p', [-3, 3], 6, innerapprox=True)
    target &= vspace.conc2pred(mgr, 'v', [0, 2], 6, innerapprox=True)
    targetint = Interface(mgr, {
        'p': pspace,
        'v': vspace
    }, {},
                          guar=mgr.true,
                          assum=target)

    safe = pspace.conc2pred(mgr, 'p', [-8, 8], 6, innerapprox=True)
    safe &= ~pspace.conc2pred(mgr, 'p', [-.4, .4], 6, innerapprox=True)
    safe &= vspace.conc2pred(mgr, 'v', [-4, 4], 6, innerapprox=True)
    safeint = Interface(mgr, {
        'p': pspace,
        'v': vspace
    }, {},
                        guar=mgr.true,
                        assum=safe)

    game = ReachAvoidGame(dcpre, safeint, targetint)
    basin, _, _ = game.run()


#     scatter2D(mgr, ('p', pspace), ('v', vspace),
#                  basin.pred,
#                  fname = "reachavoid_doubleint.png"
#                  )
Example #6
0
def coarse_abstract(f: Interface,
                    iter_coarseness,
                    save_precision,
                    shift_frac=0.0):
    """
    iter_coarseness:
        How many bits along each input dimension
    save_precision:
        Bits to record in the underlying grid
    shift:
        Shift boxes along each dimension by this fraction. Useful for the offset grid iterator.
    """
    default_boxes = {
        'x': (-.01, .01),
        'y': (.49, .51),
        'vx': (-.01, .01),
        'vy': (-.01, .01),
        'theta': (-.01, .01),
        'omega': (-.01, .01),
        't': -.01,
        's': .25
    }
    iter = f.input_iter(precision=iter_coarseness)
    for iobox in iter:
        # Lift missing arguments to a full dimension with default_boxes.
        for arg in default_boxes:
            if arg not in iobox:
                iobox[arg] = default_boxes[arg]

        # Bloat inputs for numerical precision, just in case.
        for k, v in iobox.items():
            if isinstance(v, tuple):
                iobox[k] = bloatbox(shiftbox(v, shift_frac), .001)

        # Simulate and overapproximate outputs
        stateboxes = {k: v for k, v in iobox.items() if k not in ['s', 't']}
        s = lander_box_dynamics(steps=T,
                                a=(iobox['t'], iobox['s']),
                                **stateboxes,
                                discrete=False)
        out = {i: bloatbox(j, factor=-0.01)
               for i, j in zip(nextstates, s)
               }  # Shrink output box ever so slightly.
        iobox.update(out)

        # Refine
        iobox = {k: v
                 for k, v in iobox.items()
                 if k in f.vars}  # Filter unnecessary input/output slices.
        f = f.io_refined(iobox, nbits=save_precision)

    f.check()
    print("Done coarse abs: ", f.outputs)

    return f
Example #7
0
        def heuristic(iface: Interface) -> Interface:
            """
            Coarsens sink interface along the dimension that shrinks the set the
            least until a certain size met.
            """

            assert iface.is_sink()

            while (len(iface.pred) > maxnodes):
                granularity = {
                    k: len(v)
                    for k, v in iface.pred_bitvars.items()
                    if k in ['x', 'y', 'theta', 'xnext', 'ynext', 'thetanext']
                }
                statebits = len(iface.pred.support)

                # List of (varname, # of coarsened interface nonblock input assignments)
                coarsened_ifaces = [(k, coarsen(iface, bits={
                    k: v - 1
                }).count_nb(statebits)) for k, v in granularity.items()]
                coarsened_ifaces.sort(key=lambda x: x[1], reverse=True)
                best_var = coarsened_ifaces[0][0]
                # print(coarsened_ifaces)
                # print("Coarsening along dimension {}".format(best_var))
                iface = coarsen(iface,
                                bits={best_var: granularity[best_var] - 1})

            return iface
Example #8
0
def test_embeddedgrid_module():

    mgr = BDD()
    inputs = {'x': EmbeddedGrid(4, 0, 3)}
    outputs = {'y': EmbeddedGrid(8, 4, 11)}

    m = Interface(mgr, inputs, outputs)

    mgr.declare("x_0", "x_1", "y_0", "y_1", "y_2")
    x0 = mgr.var("x_0")
    x1 = mgr.var("x_1")
    y0 = mgr.var("y_0")
    y1 = mgr.var("y_1")
    y2 = mgr.var("y_2")
    assert m.io_refined({
        'x': 2,
        'y': 4
    }).pred == (x0 & ~x1) & (~(x0 & ~x1) | (~y0 & ~y1 & ~y2))

    assert len(mgr.vars) > 0
Example #9
0
def make_target(mgr, composite: CompositeInterface):
    """
    Controller Synthesis with a reach objective
    """

    pspace = composite['x']
    anglespace = composite['theta']
    # Declare reach set as [0.8] x [-.8, 0] box in the x-y space.
    target = pspace.conc2pred(mgr, 'x', [1.0, 1.5], 5, innerapprox=False)
    target &= pspace.conc2pred(mgr, 'y', [1.0, 1.5], 5, innerapprox=False)
    targetmod = Interface(mgr, {
        'x': pspace,
        'y': pspace,
        'theta': anglespace
    }, {},
                          guar=mgr.true,
                          assum=target)
    targetmod.check()

    return targetmod
Example #10
0
def test_sinks():

    mgr = BDD()
    x = DynamicCover(0, 10)

    x1 = x.conc2pred(mgr, 'x', [1, 4], 5, innerapprox=True)
    x2 = x.conc2pred(mgr, 'x', [5, 8], 5, innerapprox=True)
    x3 = x.conc2pred(mgr, 'x', [0.0001, 5.001], 5, innerapprox=False)
    x4 = x.conc2pred(mgr, 'x', [4.9999, 9.999], 5, innerapprox=False)

    m1 = Interface(mgr, {'x': x}, {}, assum=x1)
    m2 = Interface(mgr, {'x': x}, {}, assum=x2)
    m3 = Interface(mgr, {'x': x}, {}, assum=x3)
    m4 = Interface(mgr, {'x': x}, {}, assum=x4)

    assert (m1 * m2).assum == mgr.false
    assert (m1 + m2).assum != mgr.false
    assert (m3 + m4).assum == mgr.true

    assert (m3 + m1) == m3
    assert (m3 * m1) == m1

    assert (m4 * m1) <= m4
Example #11
0
def test_module_composition():
    mgr = BDD()

    x = DynamicCover(0, 10)

    m1 = Interface(mgr, {'a': x}, {'b': x, 'c': x})
    m2 = Interface(mgr, {'i': x, 'j': x}, {'k': x})

    m12 = (m1 >> m2.renamed(i='c'))
    assert set(m12.inputs) == set(['a', 'j'])
    assert set(m12.outputs) == set(['c', 'b', 'k'])
    assert m12 == m2.renamed(i='c').composed_with(m1)
    assert m12 == (('c', 'i') >> m2).composed_with(m1)

    # Renaming is left associative
    assert m12 == m1 >> (('c', 'i') >> m2)
    assert m12 != (m1 >> ('c', 'i')) >> m2
    assert m12 == ((m1.renamed(c='i') >> m2)).renamed(i='c')
    assert m12 == ((m1 >> ('c', 'i') >> m2)).renamed(i='c')
    assert m12 == m1.renamed(c='i').composed_with(m2).renamed(i='c')
    assert m12 == m1.renamed(c='i').composed_with(m2) >> ('i', 'c')
Example #12
0
    def __call__(self,
                 Z: Interface,
                 no_inputs=False,
                 verbose=False) -> Interface:
        """
        One step decomposed control predecessor
        Coarsens Z interface whenever its complexity grows too large.
        """
        assert Z.is_sink()

        Z = rename(Z, self.pre_to_post)

        # See if the user has provided a pre-determined order to compose interfaces.
        if self.elimorder is not None:
            to_elim_post = list(self.elimorder)
        else:
            to_elim_post = list(self.poststate)

        if self.condition(Z):
            Z = self.heuristic(Z)

        # Eliminate each interface output
        # FIXME: This code assumes that each module only has a single output.
        # Should instead iterate over modules. Find a better way to specify the
        # module to be outputted. Can't hash them unfortunately.
        # Also doesn't take into account arbitrary DAG topologies and control inputs.
        while (len(to_elim_post) > 0):
            var = to_elim_post.pop()

            # Partition into modules that do/don't depend on var
            dep_mods = tuple(mod for mod in self.sys.children
                             if var in mod.outputs)

            if len(dep_mods) == 0:
                continue

            # Find Z bit precision.
            Z_var_bits = len(
                [b for b in Z.assum.support if bv_var_name(b) == var])
            assert Z_var_bits == len(Z.pred_bitvars[var])

            for mod in dep_mods:
                Z = sinkprepend(coarsen(mod, **{var: Z_var_bits}), Z)

        if no_inputs:
            return ihide(Z, self.control)
        else:
            return Z
Example #13
0
    def __call__(self,
                 Z: Interface,
                 no_inputs: bool = False,
                 verbose=False) -> Interface:
        """One step control predecessor"""
        assert Z.is_sink()

        if len(Z.outputs) > 0:
            raise ValueError("Only accept sink modules as inputs.")

        # Rename inputs from pre variables to post.
        Z = rename(Z, self.pre_to_post)

        # Compute robust state-input pairs
        xu = sinkprepend(self.sys, Z)

        # Return state-input pairs or only states
        if no_inputs:
            return ihide(xu, self.control)
        else:
            return xu
Example #14
0
def test_reach_control():
    composite = CompositeInterface((pcomp, vcomp))
    dcpre = DecompCPre(composite, (('p', 'pnext'), ('v', 'vnext')), ('a'))

    target = pspace.conc2pred(mgr, 'p', [-2, 2], 6, innerapprox=True)
    targetint = Interface(mgr, {
        'p': pspace,
        'v': vspace
    }, {},
                          guar=mgr.true,
                          assum=target)

    # Solve game and plot 2D invariant region
    game = ReachGame(dcpre, targetint)
    dbasin, _, _ = game.run()

    system = pcomp * vcomp
    cpre = ControlPre(system, (('p', 'pnext'), ('v', 'vnext')), ('a'))
    game = ReachGame(cpre, targetint)
    basin, _, _ = game.run()

    assert dbasin == basin
Example #15
0
def test_safe_control():
    composite = CompositeInterface((pcomp, vcomp))
    dcpre = DecompCPre(composite, (('p', 'pnext'), ('v', 'vnext')), ('a'))

    safe = pspace.conc2pred(mgr, 'p', [-8, 8], 6, innerapprox=True)
    safesink = Interface(mgr, {
        'p': pspace,
        'v': vspace
    }, {},
                         guar=mgr.true,
                         assum=safe)

    # Solve game and plot 2D invariant region
    game = SafetyGame(dcpre, safesink)
    dinv, _, controller = game.run()

    system = pcomp * vcomp
    cpre = ControlPre(system, (('p', 'pnext'), ('v', 'vnext')), ('a'))
    game = SafetyGame(cpre, safesink)
    inv, _, _ = game.run(verbose=True)

    assert dinv == inv

    #     assert dinv.count_nb(p_precision + v_precision) == approx(5988)

    # Simulate for initial states
    state_box = fn.first(controller.winning_states())
    assert state_box is not None
    state = {k: .5 * (v[0] + v[1]) for k, v in state_box.items()}
    for step in range(30):
        u = fn.first(controller.allows(state))
        assert u is not None
        picked_u = {
            'a': u['a'][0]
        }  # Pick lower bound of first allowed control voxel

        state.update(picked_u)
        nextstate = dynamics(**state)
        state = {'p': nextstate[0], 'v': nextstate[1]}
Example #16
0
def test_refinement_and_coarsening():

    mgr = BDD()

    def conc(x):
        return -3 * x

    x = DynamicCover(-10, 10)
    y = DynamicCover(20, 20)

    linmod = Interface(mgr, {'x': x}, {'y': y})

    width = 15

    for _ in range(50):
        # Generate random input windows
        f_width = {'x': np.random.rand() * width}
        f_left = {'x': -10 + np.random.rand() * (20 - f_width['x'])}
        f_right = {k: f_width[k] + f_left[k] for k in f_width}
        iobox = {k: (f_left[k], f_right[k]) for k in f_width}

        # Generate output overapproximation
        ur = conc(**f_left)
        ll = conc(**f_right)
        iobox['y'] = (ll, ur)

        # Refine and check abstract relation
        newmod = linmod.io_refined(iobox, nbits={'x': 8, 'y': 8})
        assert linmod <= newmod
        linmod = newmod

        # Check abstract relation relative to coarsened module
        assert linmod.coarsened(x=5, y=5) <= linmod
        assert linmod.coarsened(x=5) <= linmod
        assert linmod.coarsened(y=5) <= linmod
        # Coarsen should do nothing because it keeps many bits
        assert linmod.coarsened({'x': 10}, y=10) == linmod
Example #17
0
def test_mixed_module():

    from redax.module import Interface
    from redax.spaces import DynamicCover, FixedCover

    mgr = BDD()
    inputs = {
        'x': DynamicCover(0, 16),
        'y': FixedCover(-10, 10, 10),
        'theta': DynamicCover(-np.pi, np.pi, periodic=True),
        'v': FixedCover(0, 5, 5),
        'omega': FixedCover(-2, 2, 4)
    }
    outputs = {
        'xnext': DynamicCover(0, 4),
        'ynext': FixedCover(-10, 10, 10),
        'thetanext': DynamicCover(-np.pi, np.pi, periodic=True)
    }

    dubins = Interface(mgr, inputs, outputs)

    # Underspecified input-output
    with raises(AssertionError):
        dubins.io_refined(
            {
                'v': (3.6, 3.7),
                'theta': (6, -6),
                'y': (2, 3),
                'ynext': (2.1, 3.1)
            },
            nbits={'theta': 3})

    # Test that fixed covers yield correct space cardinality
    assert mgr.count(dubins.inspace(),
                     4 + 4 + 4 + 3 + 2) == 16 * 10 * 16 * 5 * 4
    assert mgr.count(dubins.outspace(), 2 + 4 + 4) == 4 * 10 * 16
Example #18
0
ts = .2
k = .1
g = 9.8


def dynamics(p, v, a):
    vsign = 1 if v > 0 else -1
    return p + v * ts, v + a * ts - vsign * k * (v**2) * ts - g * ts


pspace = DynamicCover(-10, 10)
vspace = DynamicCover(-16, 16)
aspace = DynamicCover(0, 20)

# Smaller component modules
pcomp = Interface(mgr, {'p': pspace, 'v': vspace}, {'pnext': pspace})
vcomp = Interface(mgr, {'v': vspace, 'a': aspace}, {'vnext': vspace})

# Declare grid precision
p_precision = 7
v_precision = 7
precision = {
    'p': p_precision,
    'v': v_precision,
    'a': 7,
    'pnext': p_precision,
    'vnext': v_precision
}
bittotal = sum(precision.values())
outorder = {0: 'pnext', 1: 'vnext'}
possible_transitions = (pcomp * vcomp).count_io_space(bittotal)
Example #19
0
    def run(self,
            steps: Optional[int] = None,
            winning: Optional[Interface] = None,
            verbose: bool = False):
        """
        Run a reach-avoid game until reaching a fixed point or a maximum number of steps.

        Solves for the temporal logic formula "safe UNTIL target"

        Parameters
        ----------
        steps: int
            Maximum number of game steps to run

        Returns
        -------
        Interface:
            Safe backward reachable set
        int:
            Number of game steps run
        MemorylessController:
            Controller for the reach-avoid game

        """

        if steps:
            assert steps >= 0

        state_control_vars = self.cpre.prestate.copy()
        state_control_vars.update(self.cpre.control)
        C = Interface(self.cpre.mgr, state_control_vars, {})

        z = self.target if winning is None else winning
        zz = Interface(self.cpre.mgr, {}, {})  # Defaults to false interface.

        i = 0
        while (z != zz):
            if steps and i == steps:
                print("Reached step limit")
                break

            zz = z
            step_start = time.time()
            z = self.cpre(zz, verbose=verbose)  # state-input pairs
            # z = (self.cpre(zz, verbose=verbose) * self.safe) + self.target  # state-input pairs
            # C = C | (z.assum & ~self.cpre.elimcontrol(C))  # Add new state-input pairs to controller
            C._assum = C.assum | (z.assum & ~self.cpre.elimcontrol(C.assum)
                                  )  # Add new state-input pairs to controller
            C._assum &= self.safe.assum

            if verbose:
                print("Eliminating control")
            z = ihide(z, self.cpre.control)

            z = (z * self.safe) + self.target

            i += 1
            if verbose:
                print("Step #: ", i, "Step Time (s): ",
                      time.time() - step_start, "Size: ",
                      self.cpre.mgr.count(z.assum, len(z.assum.support)),
                      "Winning nodes:", len(z.assum))

        return z, i, MemorylessController(self.cpre, C)
Example #20
0
    # Reach Game
    if True:
        f = CompositeInterface(tuple(subsys[i] for i in states))
        controller = None
        target = f['x'].conc2pred(mgr, 'x', (-.1, .1), 7, innerapprox=True)
        target &= f['y'].conc2pred(mgr, 'y', (.05, .15), 7, innerapprox=False)
        target &= f['theta'].conc2pred(mgr,
                                       'theta', (-.15, .15),
                                       5,
                                       innerapprox=True)
        target &= f['vy'].conc2pred(mgr, 'vy', (-.2, .3), 6, innerapprox=True)
        print("Target Size:", mgr.count(target, statebits))
        target = Interface(mgr,
                           {k: v
                            for k, v in f.inputs.items() if k in states}, {},
                           guar=mgr.true,
                           assum=target)

        w = target
        c = mgr.false

        iterreach_start = time.time()
        for gameiter in range(5):

            print("\nStep:", gameiter)

            # Monitoring the set of states in the lunar lander reach basin
            elimvars = [
                v for v in w.pred.support if _name(v) not in ['x', 'y']
            ]
Example #21
0
g = 9.8

init_time = time.time()


def dynamics(p, v, a):
    vsign = 1 if v > 0 else -1
    return p + v * ts, v + a * ts - vsign * k * (v**2) * ts - g * ts


pspace = DynamicCover(-10, 10)
vspace = DynamicCover(-16, 16)
aspace = DynamicCover(0, 20)

# Smaller component modules
pcomp = Interface(mgr, {'p': pspace, 'v': vspace}, {'pnext': pspace})
vcomp = Interface(mgr, {'v': vspace, 'a': aspace}, {'vnext': vspace})

bounds = {'p': [-10, 10], 'v': [-16, 16]}

# Monolithic system
system = pcomp * vcomp

# Composite system
composite = CompositeInterface((pcomp, vcomp))

# Declare grid precision
p_precision = 7
v_precision = 7
precision = {
    'p': p_precision,
Example #22
0
def setup(init=False):

    mgr = BDD()
    mgr.configure(
        reordering=False
    )  # Reordering causes too much time overhead for minimal gain.
    subsys = {}
    subsys['x'] = Interface(mgr, {
        'x': xspace,
        'vx': vxspace,
        'theta': thetaspace,
        't': thrust
    }, {'xnext': xspace})
    subsys['y'] = Interface(mgr, {
        'y': yspace,
        'vy': vyspace,
        'theta': thetaspace,
        't': thrust
    }, {'ynext': yspace})
    subsys['vx'] = Interface(
        mgr, {
            'vx': vxspace,
            'theta': thetaspace,
            'omega': omegaspace,
            't': thrust,
            's': side
        }, {'vxnext': vxspace})
    subsys['vy'] = Interface(
        mgr, {
            'vy': vyspace,
            'theta': thetaspace,
            'omega': omegaspace,
            't': thrust,
            's': side
        }, {'vynext': vyspace})
    subsys['theta'] = Interface(mgr, {
        'theta': thetaspace,
        'omega': omegaspace,
        's': side
    }, {'thetanext': thetaspace})
    subsys['omega'] = Interface(mgr, {
        'omega': omegaspace,
        's': side
    }, {'omeganext': omegaspace})

    # Coarse, but exhaustive abstraction of submodules.
    if init:
        iter_coarseness = {
            'x': {
                'x': 7,
                'vx': 5,
                'theta': 2
            },
            'y': {
                'y': 7,
                'vy': 5,
                'theta': 2
            },
            'vx': {
                'vx': 5,
                'theta': 4,
                'omega': 3
            },
            'vy': {
                'vy': 5,
                'theta': 4,
                'omega': 3
            },
            'theta': {
                'theta': 5,
                'omega': 4
            },
            'omega': {
                'omega': 4
            }
        }
        # iter_coarseness = {k: {k_: v_ + 1 for k_, v_ in v.items()} for k, v in iter_coarseness.items()}
        # iter_coarseness = sysview
        initabs_start = time.time()
        for i in states:
            print("Refining", i, "module")
            print("Iter Coarseness:", iter_coarseness[i])
            print("Recording Coarseness:",
                  {k: v
                   for k, v in sysview[i].items() if k in subsys[i].vars})
            subsys[i] = coarse_abstract(subsys[i], iter_coarseness[i],
                                        sysview[i])
            print(len(mgr), "manager nodes after first pass")
            subsys[i].check()
            print("Subsys", i, "ND ratio:", nd_ratio(subsys[i]))

            subsys[i] = coarse_abstract(subsys[i],
                                        iter_coarseness[i],
                                        sysview[i],
                                        shift_frac=0.5)
            print(len(mgr), "manager nodes after second pass")
            subsys[i].check()
            print("Subsys", i, "ND ratio:", nd_ratio(subsys[i]), "\n")

            mgr.reorder(
                order_heuristic(mgr, [
                    'x', 'y', 'vx', 'vy', 'theta', 'omega', 't', 's', 'xnext',
                    'ynext', 'vxnext', 'vynext', 'thetanext', 'omeganext'
                ]))

        print("Coarse Initial Abstraction Time (s): ",
              time.time() - initabs_start)

    return mgr, subsys
Example #23
0
def test_dynamic_module():
    mgr = BDD()

    inputs = {
        'x': DynamicCover(0, 16),
        'y': DynamicCover(0, 4),
    }
    output = {'z': DynamicCover(0, 4)}

    h = Interface(mgr, inputs, output)

    # Rename inputs
    assert set(h.inputs) == {'x', 'y'}
    assert set(h.outputs) == {'z'}
    g = ('j', 'x') >> h >> ('z', 'r')
    assert set(g.inputs) == {'j', 'y'}
    assert set(g.outputs) == {'r'}
    assert g == h.renamed(x='j', z='r')

    precision = {'j': 4, 'y': 3, 'r': 3}
    bittotal = sum(precision.values())

    assert g.count_io_space(bittotal) == approx(1024)
    assert g.count_io(bittotal) == approx(0)
    g = g.io_refined({
        'j': (2.9, 10.1),
        'y': (2.4, 3.8),
        'r': (2.1, 3.1)
    },
                     nbits=precision)
    assert g.count_io(bittotal) == approx(42)  # = 7 * 2 * 3

    # Adding approximately the same transitions twice does nothing due to quantization
    oldpred = g.pred
    g = g.io_refined({
        'j': (3., 10.),
        'y': (2.5, 3.8),
        'r': (2.1, 3.1)
    },
                     nbits=precision)
    assert g.pred == oldpred

    assert (g).pred.support == {
        'j_0', 'j_1', 'j_2', 'j_3', 'y_0', 'y_1', 'y_2', 'r_0', 'r_1', 'r_2'
    }
    assert (g >> ('r', 'z')).pred.support == {
        'j_0', 'j_1', 'j_2', 'j_3', 'y_0', 'y_1', 'y_2', 'z_0', 'z_1', 'z_2'
    }

    assert g.nonblock() == g.input_to_abs({
        'j': (3., 10.),
        'y': (2.5, 3.8)
    },
                                          nbits=precision)  # No inputs block
    assert g.nonblock() == (g.ohidden(g.outputs).pred)

    # Identity test for input and output renaming
    assert ((g >> ('r', 'z')) >> ('z', 'r')) == g
    assert (('j', 'w') >> (('w', 'j') >> g)) == g

    # Parallel composition
    assert set((g * h).outputs) == {'z', 'r'}
    assert set((g * h).inputs) == {'x', 'y', 'j'}

    # Series composition with disjoint I/O yields parallel composition
    assert (g >> h) == (g * h)
    assert (g >> h) == g.composed_with(h)
    assert (g >> h) == h.composed_with(g)
    assert (g * h) == h.composed_with(g)

    # Out of bounds errors
    with raises(OutOfDomainError):
        g = g.io_refined({
            'j': (3., 10.),
            'y': (2.5, 3.8),
            'r': (2.1, 4.6)
        },
                         silent=False,
                         nbits=precision)
Example #24
0
    def run(self,
            steps: Optional[int] = None,
            winning: Optional[Interface] = None,
            verbose=False,
            winningonly=False):
        """
        Run a safety game until reaching a fixed point or a maximum number of steps.

        Parameters
        ----------
        steps: int
            Maximum number of game steps to run
        winning: Interface or None
            Currently winning region
        verbose: bool, False
            If True (not default), then print out intermediate statistics.
        winningonly: bool, False
            If true, output safety controller that only stores the invariant region.

        Returns
        -------
        Interface:
            Safe invariant region
        int:
            Actualy number of game steps run.
        MemorylessController:
            Controller that maps state dictionary to safe input dictionary

        """
        if steps is not None:
            assert steps >= 0

        z = self.safe if winning is None else winning
        zz = Interface(self.cpre.mgr, {}, {})  # Defaults to false interface.

        # C = self.cpre.mgr.false
        state_control = self.cpre.prestate.copy()
        state_control.update(self.cpre.control)
        # C = Interface(self.cpre.mgr, state_control, {})

        i = 0
        while (z != zz):
            if steps and i == steps:
                break
            step_start = time.time()
            zz = z

            z = self.cpre(zz, verbose=verbose)

            C = z
            if verbose:
                print("Eliminating control")

            z = ihide(z, self.cpre.control)
            z = z * self.safe

            i = i + 1

            if verbose:
                print(
                    "Step #: ", i,
                    "Step Time (s): {0:.3f}".format(time.time() - step_start),
                    "Winning Size:",
                    self.cpre.mgr.count(z.assum, len(z.assum.support)),
                    "Winning nodes:", len(z.assum))

        return z, i, MemorylessController(self.cpre, C)
Example #25
0
Declare modules
"""

mgr = aigerwrapper()

# Declare continuous state spaces
pspace = DynamicCover(-2, 2)
anglespace = DynamicCover(-np.pi, np.pi, periodic=True)
# Declare discrete control spaces
vspace = EmbeddedGrid(2, vmax / 2, vmax)
angaccspace = EmbeddedGrid(3, -1.5, 1.5)

# Declare modules
dubins_x = Interface(mgr, {
    'x': pspace,
    'theta': anglespace,
    'v': vspace
}, {'xnext': pspace})
dubins_y = Interface(mgr, {
    'y': pspace,
    'theta': anglespace,
    'v': vspace
}, {'ynext': pspace})
dubins_theta = Interface(mgr, {
    'theta': anglespace,
    'v': vspace,
    'omega': angaccspace
}, {'thetanext': anglespace})

bits = 7
precision = {
Example #26
0
def test_sin_sqrt_comp():
    def containszero(left, right):
        """Determine if 0 is contained in a periodic interval [left,right]. Possible that right < left."""
        # Map to interval [-pi,pi]
        left = ((left + np.pi) % (np.pi * 2)) - np.pi
        left = left - 2 * np.pi if left > np.pi else left
        right = ((right + np.pi) % (np.pi * 2)) - np.pi
        right = right - 2 * np.pi if right > np.pi else right

        if right < left:
            if left <= 0:
                return True
        else:
            if left <= 0 and right >= 0:
                return True

        return False

    def maxmincos(left, right):
        """Compute the maximum and minimum values of cos in an interval."""
        if containszero(left, right) is True:
            maxval = 1
        else:
            maxval = max([np.cos(left), np.cos(right)])

        if containszero(left + np.pi, right + np.pi) is True:
            minval = -1
        else:
            minval = min([np.cos(left), np.cos(right)])

        return (minval, maxval)

    def maxminsin(left, right):
        """Compute the maximum and minimum values of sin in an interval."""
        return maxmincos(left - np.pi / 2, right - np.pi / 2)

    mgr = BDD()

    sinout = DynamicCover(-1.2, 1.2)
    sinin = DynamicCover(-2 * np.pi, 2 * np.pi, periodic=True)

    # Sin module
    sinmod = Interface(mgr, {'sin': sinin}, {'sout': sinout})

    # Sqrt module
    sqrtout = DynamicCover(0, 1.2)
    sqrtmod = Interface(mgr, {'sout': sinout}, {'sqrt': sqrtout})

    comp = CompositeInterface([sinmod, sqrtmod])

    def random_input_gen(module: Interface, scale: float) -> dict:
        iobox = dict()
        for invar, space in module.inputs.items():
            if isinstance(space, ContinuousCover):
                width = scale * space.width()
                if space.periodic:
                    left = space.lb + np.random.rand() * space.width()
                else:
                    left = space.lb + np.random.rand() * (space.width() -
                                                          width)
                right = left + width
                iobox.update({invar: (left, right)})
        return iobox

    precision = {'sin': 9, 'sout': 9, 'sqrt': 9}

    # Learn sin module
    from redax.visualizer import scatter2D
    for i in range(200):
        iobox = random_input_gen(sinmod, scale=.01)
        out = maxminsin(iobox['sin'][0], iobox['sin'][1])
        iobox.update({'sout': (out[0], out[1])})

        # No errors should be raised
        sinmod = sinmod.io_refined(iobox, silent=False, nbits=precision)
        comp = comp.io_refined(iobox, nbits=precision)
        assert sinmod == comp.children[0]

    # Learn sqrt module
    for i in range(200):
        iobox = random_input_gen(sqrtmod, scale=.1)
        if iobox['sout'][0] < 0 or iobox['sout'][1] < 0:
            continue
        out = (math.sqrt(iobox['sout'][0]), math.sqrt(iobox['sout'][1]))
        iobox.update({'sqrt': out})
        sqrtmod = sqrtmod.io_refined(iobox, silent=True, nbits=precision)
        comp = comp.io_refined(iobox, nbits=precision)
        assert sqrtmod == comp.children[1]

    # sinroot = (sinmod >> sqrtmod).ohidden(['sout'])
    sinroot = (comp.children[0] >> comp.children[1]).ohidden(['sout'])
    assert set(sinroot.vars) == {'sin', 'sqrt'}
    assert sinroot.pred != mgr.false
    sinroot.check()