示例#1
0
    def __init__(self, model, dt=0.001, seed=None, builder=Builder()):
        # Call the builder to build the model
        self.model = builder(model, dt)
        self.dt = dt

        # Use model seed as simulator seed if the seed is not provided
        # Note: seed is not used right now, but one day...
        self.seed = self.model.seed if seed is None else seed

        # -- map from Signal.base -> ndarray
        self.signals = SignalDict(__time__=np.asarray(0.0, dtype=np.float64))
        for op in self.model.operators:
            op.init_signals(self.signals, self.dt)

        self.dg = operator_depencency_graph(self.model.operators)
        self._step_order = [node for node in toposort(self.dg)
                            if hasattr(node, 'make_step')]
        self._steps = [node.make_step(self.signals, self.dt)
                       for node in self._step_order]

        self.n_steps = 0

        # Add built states to the probe dictionary
        self._probe_outputs = self.model.params

        # Provide a nicer interface to probe outputs
        self.data = ProbeDict(self._probe_outputs)
示例#2
0
    def __init__(self, network, dt=0.001, seed=None, model=None):
        self.closed = False

        if model is None:
            dt = float(dt)  # make sure it's a float (for division purposes)
            self.model = Model(dt=dt,
                               label="%s, dt=%f" % (network, dt),
                               decoder_cache=get_default_decoder_cache())
        else:
            self.model = model

        if network is not None:
            # Build the network into the model
            self.model.build(network)

        self.model.decoder_cache.shrink()

        # -- map from Signal.base -> ndarray
        self.signals = SignalDict()
        for op in self.model.operators:
            op.init_signals(self.signals)

        # Order the steps (they are made in `Simulator.reset`)
        self.dg = operator_depencency_graph(self.model.operators)
        self._step_order = [op for op in toposort(self.dg)
                            if hasattr(op, 'make_step')]

        # Add built states to the probe dictionary
        self._probe_outputs = self.model.params

        # Provide a nicer interface to probe outputs
        self.data = ProbeDict(self._probe_outputs)

        seed = np.random.randint(npext.maxint) if seed is None else seed
        self.reset(seed=seed)
示例#3
0
    def __init__(
            self, network, dt=0.001, seed=None, model=None, progress_bar=True):
        self.closed = False
        self.progress_bar = progress_bar

        if model is None:
            self._model = Model(dt=float(dt),
                                label="%s, dt=%f" % (network, dt),
                                decoder_cache=get_default_decoder_cache())
        else:
            self._model = model

        if network is not None:
            # Build the network into the model
            self._model.build(network, progress_bar=self.progress_bar)

        # -- map from Signal.base -> ndarray
        self.signals = SignalDict()
        for op in self._model.operators:
            op.init_signals(self.signals)

        # Order the steps (they are made in `Simulator.reset`)
        self.dg = operator_depencency_graph(self._model.operators)
        self._step_order = [op for op in toposort(self.dg)
                            if hasattr(op, 'make_step')]

        # Add built states to the probe dictionary
        self._probe_outputs = self._model.params

        # Provide a nicer interface to probe outputs
        self.data = ProbeDict(self._probe_outputs)

        seed = np.random.randint(npext.maxint) if seed is None else seed
        self.reset(seed=seed)
示例#4
0
    def __init__(self,
                 network,
                 dt=0.001,
                 seed=None,
                 model=None,
                 progress_bar=True,
                 optimize=True):
        self.closed = True  # Start closed in case constructor raises exception
        self.progress_bar = progress_bar
        self.optimize = optimize

        if model is None:
            self.model = Model(
                dt=float(dt),
                label="%s, dt=%f" % (network, dt),
                decoder_cache=get_default_decoder_cache(),
            )
        else:
            self.model = model

        pt = ProgressTracker(progress_bar, Progress("Building", "Build"))
        with pt:
            if network is not None:
                # Build the network into the model
                self.model.build(network,
                                 progress=pt.next_stage("Building", "Build"))

            # Order the steps (they are made in `Simulator.reset`)
            self.dg = operator_dependency_graph(self.model.operators)

            if optimize:
                with pt.next_stage("Building (running optimizer)",
                                   "Optimization"):
                    opmerge_optimize(self.model, self.dg)

        self._step_order = [
            op for op in toposort(self.dg) if hasattr(op, "make_step")
        ]

        # -- map from Signal.base -> ndarray
        self.signals = SignalDict()
        for op in self.model.operators:
            op.init_signals(self.signals)

        # Add built states to the raw simulation data dictionary
        self._sim_data = self.model.params

        # Provide a nicer interface to simulation data
        self.data = SimulationData(self._sim_data)

        if seed is None:
            if network is not None and network.seed is not None:
                seed = network.seed + 1
            else:
                seed = np.random.randint(npext.maxint)

        self.closed = False
        self.reset(seed=seed)
示例#5
0
def noop_planner(operators):
    """Orders operators into a valid execution order, but does not perform
    any merging.

    Parameters
    ----------
    operators : list of :class:`~nengo:nengo.builder.Operator`
        all the ``nengo`` operators in a model (unordered)

    Returns
    -------
    list of tuple of :class:`~nengo:nengo.builder.Operator`
        operators in execution order
    """

    dependency_graph = operator_dependency_graph(operators)
    plan = [(op,) for op in toposort(dependency_graph)]

    logger.debug("NOOP PLAN")
    logger.debug("\n" + "\n".join([str(x) for x in plan]))

    return plan
示例#6
0
def noop_planner(operators):
    """
    Orders operators into a valid execution order, but does not perform
    any merging.

    Parameters
    ----------
    operators : list of `~nengo.builder.Operator`
        All the ``nengo`` operators in a model (unordered)

    Returns
    -------
    plan : list of tuple of `~nengo.builder.Operator`
        Operators in execution order
    """

    dependency_graph = operator_dependency_graph(operators)
    plan = [(op,) for op in toposort(dependency_graph)]

    logger.debug("NOOP PLAN")
    logger.debug("\n%s" * len(plan), *plan)

    return plan
示例#7
0
def transitive_planner(op_list):
    """
    Create merged execution plan through transitive closure construction.

    This is something like a middle ground between `.greedy_planner` and
    `.tree_planner`; it can improve simulation time over the greedy
    planner, but comes with potentially significant build time increases.

    Parameters
    ----------
    op_list : list of `~nengo.builder.Operator`
        All the ``nengo`` operators in a model (unordered)

    Returns
    -------
    plan : list of tuple of `~nengo.builder.Operator`
        Operators combined into mergeable groups and in execution order
    """

    n_ele = len(op_list)
    merge_groups = {}
    dg = operator_dependency_graph(op_list)
    op_codes = {op: np.uint32(i) for i, op in enumerate(op_list)}
    dg = {op_codes[k]: set(op_codes[x] for x in v) for k, v in dg.items()}
    op_codes = {}  # so it will get garbage collected
    dg = BidirectionalDAG(dg)

    # fail fast here if the op graph has cycles
    toposort(dg.forward)

    builder_types = [builder.Builder.builders[type(op)] for op in op_list]

    # sort operators by builder (we'll only be interested in one builder type
    # at a time, because we can't merge operators between builder types anyway)
    ops_by_type = defaultdict(set)
    for i, op in enumerate(op_list):
        ops_by_type[builder_types[i]].add(np.uint32(i))

    # heuristic ordering for builder types (earlier items in the list will
    # have higher priority, meaning that we will choose to merge those ops
    # and potentially break lower-priority groups)
    order = [
        op_builders.SparseDotIncBuilder, op_builders.ElementwiseIncBuilder,
        neuron_builders.SimNeuronsBuilder, process_builders.SimProcessBuilder,
        op_builders.SimPyFuncBuilder, learning_rule_builders.SimOjaBuilder,
        learning_rule_builders.SimVojaBuilder,
        learning_rule_builders.SimBCMBuilder, op_builders.CopyBuilder,
        op_builders.ResetBuilder, tensor_node.SimTensorNodeBuilder]

    for builder_type in order:
        if builder_type not in ops_by_type:
            # no ops of this type in the model
            continue

        ops = ops_by_type[builder_type]

        # compute transitive closure
        trans = [None for _ in range(n_ele)]
        transitive_closure_recurse(dg.forward, ops, trans, builder_type,
                                   builder_types, {})

        # reduce it to the elements we care about (ops of the current
        # builder type)
        trans = {i: v for i, v in enumerate(trans[:len(op_list)]) if i in ops}

        while len(trans) > 0:
            # find all the ops that have no downstream dependents
            available = set(k for k, v in trans.items() if len(v) == 0)

            # sort those ops into mergeable groups
            groups = []
            for op in available:
                for g in groups:
                    if mergeable(op_list[op], (op_list[g[0]],)):
                        g.append(op)
                        break
                else:
                    groups.append([op])

            # merge the groups
            for g in groups:
                dg.merge(g, n_ele)
                merge_groups[n_ele] = g
                n_ele += 1

            # remove those ops from the transitive closure
            for op in available:
                del trans[op]

            # remove those ops from the transitive closure of upstream ops
            # note: we first remove all the duplicate aliased transitive sets,
            # to reduce the number of set operations we need to do
            unique_trans = {id(v): v for v in trans.values()}
            for t in unique_trans.values():
                t -= available

        # trans_reverse = [None for _ in range(n_ele)]
        # transitive_closure_recurse(dg.backward, ops, trans_reverse,
        #                            builder_type, builder_types, cache)
        # trans_reverse = {i: v for i, v in
        #                  enumerate(trans_reverse[:len(op_list)]) if i in ops}
        # group = None
        # for op in toposort(trans, trans_reverse):
        #     if group is None:
        #         group = [op]
        #         continue
        #
        #     if mergeable(op_list[op], (op_list[group[0]],)) and all(
        #             x not in trans[op] for x in group):
        #         group.append(op)
        #     else:
        #         dg.merge(group, n_ele)
        #         merge_groups[n_ele] = group
        #         n_ele += 1
        #         group = [op]
        #
        # dg.merge(group, n_ele)
        # merge_groups[n_ele] = group
        # n_ele += 1

        del ops_by_type[builder_type]

    assert len(ops_by_type) == 0

    # toposort the merged graph to come up with execution plan
    plan = toposort(dg.forward)
    plan = [tuple(op_list[x] for x in merge_groups[group]) for group in plan]

    logger.debug("TRANSITIVE PLAN")
    logger.debug("\n%s" * len(plan), *plan)

    return plan
示例#8
0
def test_toposort():
    edges = graphs.graph({'a': {'b', 'c'}, 'b': ('c', )})
    assert graphs.toposort(edges) == ['a', 'b', 'c']
示例#9
0
    def __init__(self, network, dt=0.001, seed=None, model=None):
        """Initialize the simulator with a network and (optionally) a model.

        Most of the time, you will pass in a network and sometimes a dt::

            sim1 = nengo.Simulator(my_network)  # Uses default 0.001s dt
            sim2 = nengo.Simulator(my_network, dt=0.01)  # Uses 0.01s dt

        For more advanced use cases, you can initialize the model yourself,
        and also pass in a network that will be built into the same model
        that you pass in::

            sim = nengo.Simulator(my_network, model=my_model)

        If you want full control over the build process, then you can build
        your network into the model manually. If you do this, then you must
        explicitly pass in ``None`` for the network::

            sim = nengo.Simulator(None, model=my_model)

        Parameters
        ----------
        network : nengo.Network instance or None
            A network object to the built and then simulated.
            If a fully built ``model`` is passed in, then you can skip
            building the network by passing in network=None.
        dt : float
            The length of a simulator timestep, in seconds.
        seed : int
            A seed for all stochastic operators used in this simulator.
            Note that there are not stochastic operators implemented
            currently, so this parameters does nothing.
        model : nengo.builder.Model instance or None
            A model object that contains build artifacts to be simulated.
            Usually the simulator will build this model for you; however,
            if you want to build the network manually, or to inject some
            build artifacts in the Model before building the network,
            then you can pass in a ``nengo.builder.Model`` instance.
        """
        self.dt = dt
        if model is None:
            self.model = Model(dt=self.dt, label="%s, dt=%f" % (network.label, dt), seed=network.seed)
        else:
            self.model = model

        if network is not None:
            # Build the network into the model
            Builder.build(network, model=self.model)

        # Use model seed as simulator seed if the seed is not provided
        # Note: seed is not used right now, but one day...
        self.seed = self.model.seed if seed is None else seed

        # -- map from Signal.base -> ndarray
        self.signals = SignalDict(__time__=np.asarray(0.0, dtype=np.float64))
        for op in self.model.operators:
            op.init_signals(self.signals, self.dt)

        self.dg = operator_depencency_graph(self.model.operators)
        self._step_order = [node for node in toposort(self.dg) if hasattr(node, "make_step")]
        self._steps = [node.make_step(self.signals, self.dt) for node in self._step_order]

        self.n_steps = 0

        # Add built states to the probe dictionary
        self._probe_outputs = self.model.params

        # Provide a nicer interface to probe outputs
        self.data = ProbeDict(self._probe_outputs)
示例#10
0
    def __init__(self, network, dt=0.001, seed=None, model=None):
        """Initialize the simulator with a network and (optionally) a model.

        Most of the time, you will pass in a network and sometimes a dt::

            sim1 = nengo.Simulator(my_network)  # Uses default 0.001s dt
            sim2 = nengo.Simulator(my_network, dt=0.01)  # Uses 0.01s dt

        For more advanced use cases, you can initialize the model yourself,
        and also pass in a network that will be built into the same model
        that you pass in::

            sim = nengo.Simulator(my_network, model=my_model)

        If you want full control over the build process, then you can build
        your network into the model manually. If you do this, then you must
        explicitly pass in ``None`` for the network::

            sim = nengo.Simulator(None, model=my_model)

        Parameters
        ----------
        network : nengo.Network instance or None
            A network object to the built and then simulated.
            If a fully built ``model`` is passed in, then you can skip
            building the network by passing in network=None.
        dt : float
            The length of a simulator timestep, in seconds.
        seed : int
            A seed for all stochastic operators used in this simulator.
            Note that there are not stochastic operators implemented
            currently, so this parameters does nothing.
        model : nengo.builder.Model instance or None
            A model object that contains build artifacts to be simulated.
            Usually the simulator will build this model for you; however,
            if you want to build the network manually, or to inject some
            build artifacts in the Model before building the network,
            then you can pass in a ``nengo.builder.Model`` instance.
        """
        self.dt = dt
        if model is None:
            self.model = Model(dt=self.dt,
                               label="%s, dt=%f" % (network.label, dt),
                               seed=network.seed)
        else:
            self.model = model

        if network is not None:
            # Build the network into the model
            Builder.build(network, model=self.model)

        # Use model seed as simulator seed if the seed is not provided
        # Note: seed is not used right now, but one day...
        self.seed = self.model.seed if seed is None else seed

        # -- map from Signal.base -> ndarray
        self.signals = SignalDict(__time__=np.asarray(0.0, dtype=np.float64))
        for op in self.model.operators:
            op.init_signals(self.signals, self.dt)

        self.dg = operator_depencency_graph(self.model.operators)
        self._step_order = [node for node in toposort(self.dg)
                            if hasattr(node, 'make_step')]
        self._steps = [node.make_step(self.signals, self.dt)
                       for node in self._step_order]

        self.n_steps = 0

        # Add built states to the probe dictionary
        self._probe_outputs = self.model.params

        # Provide a nicer interface to probe outputs
        self.data = ProbeDict(self._probe_outputs)
示例#11
0
    def __init__(self,
                 network,
                 dt=0.001,
                 seed=None,
                 model=None,
                 dtype=rc.get('precision', 'dtype')):
        """Initialize the simulator with a network and (optionally) a model.

        Most of the time, you will pass in a network and sometimes a dt::

            sim1 = nengo.Simulator(my_network)  # Uses default 0.001s dt
            sim2 = nengo.Simulator(my_network, dt=0.01)  # Uses 0.01s dt

        For more advanced use cases, you can initialize the model yourself,
        and also pass in a network that will be built into the same model
        that you pass in::

            sim = nengo.Simulator(my_network, model=my_model)

        If you want full control over the build process, then you can build
        your network into the model manually. If you do this, then you must
        explicitly pass in ``None`` for the network::

            sim = nengo.Simulator(None, model=my_model)

        Parameters
        ----------
        network : nengo.Network instance or None
            A network object to the built and then simulated.
            If a fully built ``model`` is passed in, then you can skip
            building the network by passing in network=None.
        dt : float
            The length of a simulator timestep, in seconds.
        seed : int
            A seed for all stochastic operators used in this simulator.
            Note that there are not stochastic operators implemented
            currently, so this parameters does nothing.
        model : nengo.builder.Model instance or None
            A model object that contains build artifacts to be simulated.
            Usually the simulator will build this model for you; however,
            if you want to build the network manually, or to inject some
            build artifacts in the Model before building the network,
            then you can pass in a ``nengo.builder.Model`` instance.
        """
        dt = float(dt)  # make sure it's a float (for division purposes)
        if model is None:
            self.model = Model(dt=dt,
                               label="%s, dt=%f" % (network, dt),
                               decoder_cache=get_default_decoder_cache(),
                               dtype=dtype)
        else:
            self.model = model

        #print(network)
        if network is not None:
            # Build the network into the model
            self.model.build(network)

        self.model.decoder_cache.shrink()

        self.seed = np.random.randint(npext.maxint) if seed is None else seed
        self.rng = np.random.RandomState(self.seed)

        # -- map from Signal.base -> ndarray
        self.signals = SignalDict(
            __time__=np.asarray(npext.castDecimal(0), dtype=self.dtype))
        #print(self.model)
        #print(self.model.operators)
        for op in self.model.operators:
            op.init_signals(self.signals)
        self.dg = operator_depencency_graph(self.model.operators)
        self._step_order = [
            node for node in toposort(self.dg) if hasattr(node, 'make_step')
        ]
        self._steps = [
            node.make_step(self.signals, dt, self.rng)
            for node in self._step_order
        ]

        # Add built states to the probe dictionary
        self._probe_outputs = self.model.params

        # Provide a nicer interface to probe outputs
        self.data = ProbeDict(self._probe_outputs)

        self.reset()
示例#12
0
    def __init__(self, network, dt=0.001, seed=None):
        self.model = Model(
            dt=float(dt),
            label="Nengo RS model",
            decoder_cache=get_default_decoder_cache(),
        )
        self.model.build(network)

        signal_to_engine_id = {}
        for signal_dict in self.model.sig.values():
            for signal in signal_dict.values():
                self.add_sig(signal_to_engine_id, signal)
        x = SignalU64("step", 0)
        signal_to_engine_id[self.model.step] = x
        signal_to_engine_id[self.model.time] = SignalF64("time", 0.0)
        self._sig_to_ngine_id = signal_to_engine_id

        dg = BidirectionalDAG(operator_dependency_graph(self.model.operators))
        toposorted_dg = toposort(dg.forward)
        node_indices = {node: idx for idx, node in enumerate(toposorted_dg)}

        ops = []
        for op in toposorted_dg:
            dependencies = [node_indices[node] for node in dg.backward[op]]
            if isinstance(op, core_op.Reset):
                ops.append(
                    Reset(
                        np.asarray(op.value, dtype=np.float64),
                        self.get_sig(signal_to_engine_id, op.dst),
                        dependencies,
                    ))
            elif isinstance(op, core_op.TimeUpdate):
                ops.append(
                    TimeUpdate(
                        dt,
                        self.get_sig(signal_to_engine_id, self.model.step),
                        self.get_sig(signal_to_engine_id, self.model.time),
                        dependencies,
                    ))
            elif isinstance(op, core_op.ElementwiseInc):
                ops.append(
                    ElementwiseInc(
                        self.get_sig(signal_to_engine_id, op.Y),
                        self.get_sig(signal_to_engine_id, op.A),
                        self.get_sig(signal_to_engine_id, op.X),
                        dependencies,
                    ))
            elif isinstance(op, core_op.Copy):
                assert op.src_slice is None and op.dst_slice is None
                ops.append(
                    Copy(
                        op.inc,
                        self.get_sig(signal_to_engine_id, op.src),
                        self.get_sig(signal_to_engine_id, op.dst),
                        dependencies,
                    ))
            elif isinstance(op, core_op.DotInc):
                ops.append(
                    DotInc(
                        self.get_sig(signal_to_engine_id, op.Y),
                        self.get_sig(signal_to_engine_id, op.A),
                        self.get_sig(signal_to_engine_id, op.X),
                        dependencies,
                    ))
            elif isinstance(op, neurons.SimNeurons):
                signals = SignalDict()
                op.init_signals(signals)
                ops.append(
                    SimNeurons(
                        self.dt,
                        op.neurons.step_math,
                        [signals[s]
                         for s in op.states] if hasattr(op, "states") else [],
                        self.get_sig(signal_to_engine_id, op.J),
                        self.get_sig(signal_to_engine_id, op.output),
                        dependencies,
                    ))
            elif isinstance(op, processes.SimProcess):
                signals = SignalDict()
                op.init_signals(signals)
                shape_in = (0, ) if op.input is None else op.input.shape
                shape_out = op.output.shape
                rng = None
                state = {k: signals[s] for k, s in op.state.items()}
                step_fn = op.process.make_step(shape_in, shape_out, self.dt,
                                               rng, state)
                ops.append(
                    SimProcess(
                        op.mode == "inc",
                        lambda *args, step_fn=step_fn: np.asarray(
                            step_fn(*args), dtype=float),
                        self.get_sig(signal_to_engine_id, op.t),
                        self.get_sig(signal_to_engine_id, op.output),
                        None if op.input is None else self.get_sig(
                            signal_to_engine_id, op.input),
                        dependencies,
                    ))
            elif isinstance(op, core_op.SimPyFunc):
                ops.append(
                    SimPyFunc(
                        lambda *args, op=op: np.asarray(op.fn(*args),
                                                        dtype=float),
                        self.get_sig(signal_to_engine_id, op.output),
                        None if op.t is None else self.get_sig(
                            signal_to_engine_id, op.t),
                        None if op.x is None else self.get_sig(
                            signal_to_engine_id, op.x),
                        dependencies,
                    ))
            else:
                raise Exception(f"missing: {op}")

        self.probe_mapping = {}
        for probe in self.model.probes:
            self.probe_mapping[probe] = Probe(
                signal_to_engine_id[self.model.sig[probe]["in"]])

        self._engine = Engine(list(signal_to_engine_id.values()), ops,
                              list(self.probe_mapping.values()))
        self.data = SimData(self)
        print("initialized")

        self._engine.reset()
示例#13
0
def test_toposort():
    edges = graphs.graph({"a": {"b", "c"}, "b": {"c"}, "c": set()})
    assert graphs.toposort(edges) == ["a", "b", "c"]
示例#14
0
def test_toposort():
    edges = graphs.graph({'a': {'b', 'c'}, 'b': {'c'}, 'c': set()})
    assert graphs.toposort(edges) == ['a', 'b', 'c']
示例#15
0
def test_toposort():
    edges = graphs.graph({'a': set(['b', 'c']), 'b': ('c',)})
    assert graphs.toposort(edges) == ['a', 'b', 'c']
示例#16
0
文件: model.py 项目: jresch/nengo_mpi
    def finalize_build(self):
        """ Finalize the build step.

        Called once the MpiBuilder has finished running. Finalizes
        operators and probes, converting them to strings. Then writes
        all relevant information (signals, ops and probes for each component)
        to an HDF5 file. Then, if self.mpi_sim is not None (so we want to
        create a runnable MPI simulator), calls self.mpi_sim.load_file, which
        tells the C++ code to load the HDF5 file we have just written and
        create a working simulator.

        """
        all_ops = list(chain(*[self.component_ops[component] for component in range(self.n_components)]))

        dg = operator_depencency_graph(all_ops)
        global_ordering = [op for op in toposort(dg) if hasattr(op, "make_step")]
        self.global_ordering = {op: i for i, op in enumerate(global_ordering)}

        self._finalize_ops()
        self._finalize_probes()

        with h5.File(self.save_file_name, "w") as save_file:
            save_file.attrs["dt"] = self.dt
            save_file.attrs["n_components"] = self.n_components

            for component in range(self.n_components):
                component_group = save_file.create_group(str(component))

                # signals
                signals = self.signals[component]
                signal_dset = component_group.create_dataset(
                    "signals", (self.total_signal_size[component],), dtype="float64", compression=self.h5_compression
                )

                offset = 0
                for key, sig in signals:
                    A = sig.base._value

                    if A.ndim == 0:
                        A = np.reshape(A, (1, 1))

                    if A.dtype != np.float64:
                        A = A.astype(np.float64)

                    signal_dset[offset : offset + A.size] = A.flatten()
                    offset += A.size

                # signal keys
                component_group.create_dataset(
                    "signal_keys",
                    data=[long(key) for key, sig in signals],
                    dtype="int64",
                    compression=self.h5_compression,
                )

                # signal shapes
                def pad(x):
                    return (1, 1) if len(x) == 0 else ((x[0], 1) if len(x) == 1 else x)

                component_group.create_dataset(
                    "signal_shapes",
                    data=np.array([pad(sig.shape) for key, sig in signals]),
                    dtype="u2",
                    compression=self.h5_compression,
                )

                # signal_labels
                signal_labels = [str(p[1]) for p in signals]
                store_string_list(component_group, "signal_labels", signal_labels, compression=self.h5_compression)

                # operators
                op_strings = self.op_strings[component]
                store_string_list(component_group, "operators", op_strings, compression=self.h5_compression)

                # probes
                probe_strings = self.probe_strings[component]
                store_string_list(component_group, "probes", probe_strings, compression=self.h5_compression)

            probe_strings = self.probe_strings[component]
            store_string_list(save_file, "probe_info", self.all_probe_strings, compression=self.h5_compression)

        if self.mpi_sim is not None:
            self.mpi_sim.load_network(self.save_file_name)
            os.remove(self.save_file_name)

            for args in self.pyfunc_args:
                f = {
                    "N": self.mpi_sim.create_PyFunc,
                    "I": self.mpi_sim.create_PyFuncI,
                    "O": self.mpi_sim.create_PyFuncO,
                    "IO": self.mpi_sim.create_PyFuncIO,
                }[args[0]]
                f(*args[1:])

            self.mpi_sim.finalize_build()
示例#17
0
文件: simulator.py 项目: epaxon/nengo
    def __init__(self, network, dt=0.001, seed=None, model=None):
        """Initialize the simulator with a network and (optionally) a model.

        Most of the time, you will pass in a network and sometimes a dt::

            sim1 = nengo.Simulator(my_network)  # Uses default 0.001s dt
            sim2 = nengo.Simulator(my_network, dt=0.01)  # Uses 0.01s dt

        For more advanced use cases, you can initialize the model yourself,
        and also pass in a network that will be built into the same model
        that you pass in::

            sim = nengo.Simulator(my_network, model=my_model)

        If you want full control over the build process, then you can build
        your network into the model manually. If you do this, then you must
        explicitly pass in ``None`` for the network::

            sim = nengo.Simulator(None, model=my_model)

        Parameters
        ----------
        network : nengo.Network instance or None
            A network object to the built and then simulated.
            If a fully built ``model`` is passed in, then you can skip
            building the network by passing in network=None.
        dt : float, optional
            The length of a simulator timestep, in seconds.
        seed : int, optional
            A seed for all stochastic operators used in this simulator.
        model : nengo.builder.Model instance or None, optional
            A model object that contains build artifacts to be simulated.
            Usually the simulator will build this model for you; however,
            if you want to build the network manually, or to inject some
            build artifacts in the Model before building the network,
            then you can pass in a ``nengo.builder.Model`` instance.
        """
        if model is None:
            dt = float(dt)  # make sure it's a float (for division purposes)
            self.model = Model(dt=dt,
                               label="%s, dt=%f" % (network, dt),
                               decoder_cache=get_default_decoder_cache())
        else:
            self.model = model

        if network is not None:
            # Build the network into the model
            self.model.build(network)

        self.model.decoder_cache.shrink()

        # -- map from Signal.base -> ndarray
        self.signals = SignalDict(__time__=np.asarray(0.0, dtype=np.float64))
        for op in self.model.operators:
            op.init_signals(self.signals)

        # Order the steps (they are made in `Simulator.reset`)
        self.dg = operator_depencency_graph(self.model.operators)
        self._step_order = [op for op in toposort(self.dg)
                            if hasattr(op, 'make_step')]

        # Add built states to the probe dictionary
        self._probe_outputs = self.model.params

        # Provide a nicer interface to probe outputs
        self.data = ProbeDict(self._probe_outputs)

        seed = np.random.randint(npext.maxint) if seed is None else seed
        self.reset(seed=seed)
示例#18
0
    def finalize_build(self):
        """ Finalize the build step.

        Called once the MpiBuilder has finished running. Finalizes
        operators and probes, converting them to strings. Then writes
        all relevant information (signals, ops and probes for each component)
        to an HDF5 file. Then, if self.native_sim is not None (so we want to
        create a runnable MPI simulator), calls self.native_sim.load_file which
        tells the C++ code to load the HDF5 file we have just written and
        create a working simulator.

        """
        all_ops = list(chain(
            *[self.component_ops[component]
              for component in range(self.n_components)]))
        dg = operator_depencency_graph(all_ops)
        global_ordering = [
            op for op in toposort(dg) if hasattr(op, 'make_step')]
        self.global_ordering = {op: i for i, op in enumerate(global_ordering)}
        self.global_ordering[self.time_update] = -1

        # Needs to be done after calling operator_depencency_graph.
        # operator_depencency_graph will detect an error caused
        # by multiple sets of the time signal
        for component in range(self.n_components):
            self.assign_ops(component, [self.time_update])

        self._finalize_ops()
        self._finalize_probes()

        with h5.File(self.save_file, 'w') as save_file:
            save_file.attrs['dt'] = self.dt
            save_file.attrs['n_components'] = self.n_components

            for component in range(self.n_components):
                component_group = save_file.create_group(str(component))

                # base signals
                base_signals = self.base_signals[component]
                signal_dset = component_group.create_dataset(
                    'signals', (self.total_base_signal_size[component],),
                    dtype='float64', compression=self.h5_compression)

                offset = 0
                for base in base_signals.values():
                    shape = base.shape
                    stride = base.elemstrides

                    if base.ndim == 2:
                        # assert that the signal is contiguous
                        assert ((stride[1] == 1 and shape[1] == stride[0]) or
                                (stride[0] == 1 and shape[0] == stride[1]))

                        if base.elemstrides[1] == 1:
                            values = base.initial_value.flatten()
                        elif base.elemstrides[0] == 1:
                            values = base.initial_value.T.flatten()
                        else:
                            raise ValueError(
                                "Received a signal with strides that "
                                "nengo_mpi cannot handle. Signal "
                                "was %s, stride is %s." % (
                                    base, base.elemstrides))

                        signal_dset[offset:offset+base.size] = values
                    else:
                        # assert that the signal is contiguous
                        assert base.ndim == 0 or stride[0] == 1
                        signal_dset[
                            offset:offset+base.size] = base.initial_value

                    offset += base.size

                # base signal keys
                base_signal_keys = np.array([
                    long(key) for key in base_signals.keys()])

                component_group.create_dataset(
                    'signal_keys', data=base_signal_keys,
                    dtype='int64', compression=self.h5_compression)

                # base signal shapes
                base_signal_shapes = np.array([
                    pad(sig.shape) for sig in base_signals.values()])

                component_group.create_dataset(
                    'signal_shapes', data=base_signal_shapes,
                    dtype='int64', compression=self.h5_compression)

                # base signal strides
                base_signal_strides = np.array([
                    pad(sig.elemstrides) for sig in base_signals.values()])

                component_group.create_dataset(
                    'signal_strides', data=base_signal_strides,
                    dtype='int64', compression=self.h5_compression)

                # base signal labels
                if self.debug:
                    signal_labels = [sig.name for sig in base_signals.values()]
                else:
                    signal_labels = ['' for sig in base_signals.values()]

                store_string_list(
                    component_group, 'signal_labels', signal_labels,
                    compression=self.h5_compression)

                # operators
                op_strings = self.op_strings[component]
                store_string_list(
                    component_group, 'operators', op_strings,
                    compression=self.h5_compression)

                # probes
                probe_strings = self.probe_strings[component]
                store_string_list(
                    component_group, 'probes', probe_strings,
                    compression=self.h5_compression)

            store_string_list(
                save_file, 'probe_info', self.all_probe_strings,
                compression=self.h5_compression)

        if self.native_sim is not None:
            self.native_sim.load_network(self.save_file)
            os.remove(self.save_file)

            for op in self.pyfunc_ops:
                self.native_sim.create_PyFunc(op, self.global_ordering[op])

            self.native_sim.finalize_build()