예제 #1
0
    def test_reset(self):
        # Node and Marble have some arbitrary nonzero initial motion vars.
        node = Node(torch.tensor([1.]), torch.tensor([2.]), torch.tensor([3.]),
                    4, NewtonianGravity(), 1, 1, 1, 1)
        marble = Marble(torch.tensor([1.1]), torch.tensor([2.2]),
                        torch.tensor([3.3]), 4.4, NewtonianGravity(), None)
        model = NenwinModel([node], [marble])
        model.make_timestep(10)
        model.make_timestep(10)
        model.make_timestep(10)

        # Verify that the motion variables have changed
        self.assertFalse(check_close(node.pos, node.init_pos))
        self.assertFalse(check_close(marble.vel, marble.init_vel))
        self.assertFalse(check_close(marble.acc, marble.init_acc))

        model.reset()

        # Now they should be the original values again.
        self.assertTrue(check_close(node.pos, node.init_pos))
        self.assertTrue(check_close(node.vel, node.init_vel))
        self.assertTrue(check_close(node.acc, node.init_acc))
        self.assertTrue(check_close(marble.pos, marble.init_pos))
        self.assertTrue(check_close(marble.vel, marble.init_vel))
        self.assertTrue(check_close(marble.acc, marble.init_acc))
예제 #2
0
    def test_eaten_marbles_disappear(self):

        # Both are generated at the smame pos, so immediately eaten.
        node = MarbleEaterNode(ZERO, ZERO, ZERO, 10, NewtonianGravity(), 1, 1,
                               1, 0, 10)
        marble = Marble(ZERO, ZERO, ZERO, 10, NewtonianGravity(), datum=None)
        model = NenwinModel([node], [marble])
        model.make_timestep(1.0)

        self.assertSetEqual(model.marbles, set([]))
        self.assertNotIn(marble, model._NenwinModel__all_particles)
예제 #3
0
def gen_architecture_c(
    input_placer_type: type
) -> Tuple[NenwinModel, VelInputPlacer, Tuple[Node]]:
    """
    Generate the following architecture:
        * The input region is at (0, 0) and has size (6, 1)
            (So it has vertices {(0, 0), (0, 1), (6, 0), (6, 1)})
        * There are two MarbleEaterNodes, at (1, 4) and (5, 4)
        * There are five normal Nodes, 
            at (1, 2), (2, 3), (3, 2), (4, 3) and (5, 2).

    Returns:
        * Model holding the architecture descibed above.
        * VelInputPlacer with the input region as described above.
        * Tuple of the two MarbleEaterNodes.
    """

    eater_positions = [(1, 4), (5, 4)]
    node_positions = [(1, 2), (2, 3), (3, 2), (4, 3), (5, 2)]

    input_region_pos = np.array((0, 0))
    input_region_size = np.array((6, 1))
    mass = 1
    radius = 0.5

    attraction_function = NewtonianGravity()

    nodes = gen_nodes(attraction_function, mass, node_positions)
    eater_nodes = gen_eater_nodes(attraction_function, mass, radius,
                                  eater_positions)
    model = NenwinModel(nodes + eater_nodes)
    input_placer = input_placer_type(input_region_pos, input_region_size)

    return model, input_placer, eater_nodes
예제 #4
0
def visualization_demo():
    attract_funct = NewtonianGravity()
    marbles = set()
    marble_1 = Marble(np.array([460, 460]),
                      np.array([0, 0]),
                      np.array([0, 0]),
                      mass=20,
                      attraction_function=attract_funct,
                      datum=None,
                      marble_stiffness=1,
                      node_stiffness=0,
                      marble_attraction=0,
                      node_attraction=1)
    marble_2 = Marble(np.array([550, 550]),
                      np.array([10, 10]),
                      np.array([0, 0]),
                      mass=40,
                      attraction_function=attract_funct,
                      datum=None,
                      marble_stiffness=1,
                      node_stiffness=0,
                      marble_attraction=0,
                      node_attraction=1)
    marble_3 = Marble(np.array([450, 500]),
                      np.array([2, -2]),
                      np.array([0, 0]),
                      mass=40,
                      attraction_function=attract_funct,
                      datum=None,
                      marble_stiffness=1,
                      node_stiffness=0,
                      marble_attraction=0,
                      node_attraction=1)
    marbles = set((marble_1, marble_2, marble_3))

    node_1 = Node(np.array([500, 500]),
                  np.array([0, 0]),
                  np.array([0, 0]),
                  mass=200,
                  attraction_function=attract_funct,
                  marble_stiffness=1,
                  node_stiffness=1,
                  marble_attraction=1,
                  node_attraction=1)

    node_2 = Node(np.array([400, 400]),
                  np.array([0, 0]),
                  np.array([0, 0]),
                  mass=200,
                  attraction_function=attract_funct,
                  marble_stiffness=0.7,
                  node_stiffness=1,
                  marble_attraction=1,
                  node_attraction=1)
    nodes = set((node_1, node_2))

    model = NenwinModel(nodes, marbles)
    simulation = Simulation(model, None, None, MockPipe())
    visualization = NenwinVisualization((1500, 1000), simulation, model)
    visualization.run(10, 0.01)
예제 #5
0
    def test_particle_gradients_moving_node(self):
        """
        Base case: Marble being attracted by a moving Node,
        when using Marble's variables to compute loss,
        also Node.pos should receive gradients 
        when computing backprop on the loss.
        """
        self.node = Node(pos=ZERO,
                         vel=torch.tensor([0.1]),
                         acc=ZERO,
                         mass=1,
                         attraction_function=NewtonianGravity(),
                         marble_stiffness=1,
                         node_stiffness=1,
                         marble_attraction=1,
                         node_attraction=0)
        self.model = NenwinModel([self.node], [self.marble])
        self.model.make_timestep(1.0)
        self.model.make_timestep(1.0)
        self.model.make_timestep(1.0)

        loss = 2 * self.marble.acc
        loss.backward()

        self.assertIsNotNone(self.marble.init_pos.grad)
        self.assertIsNotNone(self.node.init_pos.grad)
        self.assertIsNotNone(self.node.init_vel.grad)
        self.assertIsNotNone(self.node._PhysicalParticle__mass.grad)
예제 #6
0
    def setup_full_emitter(
            self) -> Tuple[Emitter, Marble, float, float, float]:
        """
        Create an instance of a MarbleEmitter with a full prototype Marble
        (not a mock Marble). Also returns the delay, stored_mass
        and initial_time_passed, 
        which have arbitrary nonzero floating-point values.

        Returns:
        * A MarbleEmitter instance
        * A Marble, the prototype associated with the emitter
        * The delay of the emitter
        * The initally stored mass of the emitter
        * The initial time passed of the emitter
        """
        pos = torch.tensor([0], dtype=torch.float)
        vel = torch.tensor([1], dtype=torch.float)
        acc = torch.tensor([2], dtype=torch.float)
        mass = 3.0
        attraction_function = NewtonianGravity()
        marble_stiffness = 0.4
        node_stiffness = 0.5
        marble_attraction = 0.6
        node_attraction = 0.7
        prototype = Marble(pos, vel, acc, mass, attraction_function, None,
                           marble_stiffness, node_stiffness, marble_attraction,
                           node_attraction)
        delay = 8.1
        stored_mass = 9.1
        initial_time_passed = 11.1

        emitter = MarbleEmitter(prototype, delay, stored_mass,
                                initial_time_passed)

        return emitter, prototype, delay, stored_mass, initial_time_passed
예제 #7
0
    def test_repr(self):
        pos = torch.tensor([0], dtype=torch.float)
        vel = torch.tensor([1], dtype=torch.float)
        acc = torch.tensor([2], dtype=torch.float)
        mass = 3.0
        attraction_function = NewtonianGravity()
        marble_stiffness = 0.4
        node_stiffness = 0.5
        marble_attraction = 0.6
        node_attraction = 0.7

        node = Node(pos, vel, acc, mass, attraction_function, marble_stiffness,
                    node_stiffness, marble_attraction, node_attraction)

        # Some numerical errors occurs when converting from float to FloatTensor
        marble_stiffness_float_repr = \
            convert_scalar_param_to_repr(marble_stiffness)
        node_stiffness_float_repr = convert_scalar_param_to_repr(
            node_stiffness)
        marble_attraction_float_repr = \
            convert_scalar_param_to_repr(marble_attraction)
        node_attraction_float_repr = \
            convert_scalar_param_to_repr(node_attraction)
        expected = f"Node({repr(pos)},{repr(vel)},"\
            + f"{repr(acc)},{mass},NewtonianGravity(),"\
            + f"{marble_stiffness_float_repr}," \
            + f"{node_stiffness_float_repr},{marble_attraction_float_repr}," \
            + f"{node_attraction_float_repr})"
        result = repr(node)
        self.assertEqual(expected, result)
예제 #8
0
def gen_architecture_b(
    input_placer_type: type
) -> Tuple[NenwinModel, VelInputPlacer, Tuple[Node]]:
    """
    Same as architecture A, but with four additional Nodes
    (normal Nodes, no MarbleEaterNodes) at:
        * (2.5, 2.5), (-2.5, 2.5), (2.5, -2.5), (-2.5, -2.5)

    So the normal Nodes surround the input-region, 
    and the MarbleEaterNodes are to the left and right of this.

    Returns:
        * Model holding the architecture descibed above.
        * VelInputPlacer with the input region as described above.
        * Tuple of the two MarbleEaterNodes.
    """

    eater_positions = [(-10, 0), (10, 0)]
    node_positions = [(0, -5), (-5, 0), (5, 0), (0, 5), (2.5, 2.5),
                      (-2.5, 2.5), (2.5, -2.5), (-2.5, -2.5)]

    input_region_pos = np.array((-2.5, -1))
    input_region_size = np.array((5, 2))
    mass = 1
    radius = 0.5

    attraction_function = NewtonianGravity()

    nodes = gen_nodes(attraction_function, mass, node_positions)
    eater_nodes = gen_eater_nodes(attraction_function, mass, radius,
                                  eater_positions)
    model = NenwinModel(nodes + eater_nodes)
    input_placer = input_placer_type(input_region_pos, input_region_size)

    return model, input_placer, eater_nodes
예제 #9
0
def gen_node_at(pos: torch.Tensor, mass: float = 10) -> MarbleEaterNode:
    output = MarbleEaterNode(pos, vel=ZERO, acc=ZERO,
                             mass=mass,
                             attraction_function=NewtonianGravity(),
                             marble_attraction=1,
                             marble_stiffness=1,
                             node_attraction=0,
                             node_stiffness=0,
                             radius=1)

    return output
예제 #10
0
    def test_repr(self):
        pos = torch.tensor([0], dtype=torch.float)
        vel = torch.tensor([1], dtype=torch.float)
        acc = torch.tensor([2], dtype=torch.float)
        mass = 3.0
        attraction_funct = NewtonianGravity()

        expected = f"PhysicalParticle({repr(pos)},{repr(vel)},"\
            + f"{repr(acc)},{mass},NewtonianGravity(),{repr(DEVICE)})"
        result = repr(PhysicalParticle(pos, vel, acc, mass, attraction_funct))
        self.assertEqual(expected, result)
예제 #11
0
def gen_marble_at(pos: torch.Tensor,
                  vel: torch.Tensor = ZERO,
                  mass: float = 10,
                  datum: Any = None) -> Marble:
    output = Marble(pos=pos, vel=vel, acc=ZERO,
                    mass=mass,
                    attraction_function=NewtonianGravity(),
                    marble_attraction=0,
                    marble_stiffness=1,
                    node_attraction=0,
                    node_stiffness=0,
                    datum=datum)

    return output
예제 #12
0
    def setUp(self):
        self.node = Node(pos=ZERO,
                         vel=ZERO,
                         acc=ZERO,
                         mass=1,
                         attraction_function=NewtonianGravity(),
                         marble_stiffness=1,
                         node_stiffness=1,
                         marble_attraction=1,
                         node_attraction=0)
        self.marble = Marble(pos=np.array([5]),
                             vel=ZERO,
                             acc=ZERO,
                             mass=1,
                             attraction_function=ATTRACT_FUNCT,
                             datum=None)

        self.model = NenwinModel([self.node], [self.marble])
예제 #13
0
    def test_repr(self):
        pos = torch.tensor([0], dtype=torch.float)
        vel = torch.tensor([1], dtype=torch.float)
        acc = torch.tensor([2], dtype=torch.float)
        mass = 3.0
        attraction_function = NewtonianGravity()
        marble_stiffness = 0.4
        node_stiffness = 0.5
        marble_attraction = 0.6
        node_attraction = 0.7
        radius = 8.0
        # Some numerical errors occurs when converting from float to FloatTensor
        marble_stiffness_float_repr = \
            convert_scalar_param_to_repr(marble_stiffness)
        node_stiffness_float_repr = convert_scalar_param_to_repr(
            node_stiffness)
        marble_attraction_float_repr = \
            convert_scalar_param_to_repr(marble_attraction)
        node_attraction_float_repr = \
            convert_scalar_param_to_repr(node_attraction)

        emitter = MockEmitter(MockPrototype(), 0)

        expected = f"MarbleEmitterNode({repr(pos)},{repr(vel)},"\
            + f"{repr(acc)},{mass},NewtonianGravity(),"\
            + f"{marble_stiffness_float_repr}," \
            + f"{node_stiffness_float_repr},{marble_attraction_float_repr}," \
            + f"{node_attraction_float_repr},"\
            + f"{radius}," \
            + f"{repr(emitter)})"

        eater = MarbleEmitterNode(pos, vel, acc, mass, attraction_function,
                                  marble_stiffness, node_stiffness,
                                  marble_attraction, node_attraction, radius,
                                  emitter)

        result = repr(eater)
        self.assertEqual(expected, result)
예제 #14
0
    def test_reset_removed_added_marbles(self):
        """
        NenwinModel.reset() should remove all Marbles
        added with NenwinModel.add_marbles()
        """
        original_marble = Marble(ZERO,
                                 ZERO,
                                 ZERO,
                                 10,
                                 NewtonianGravity(),
                                 datum=None)
        added_marble = original_marble.copy()

        assert added_marble is not original_marble

        model = NenwinModel([], [original_marble])
        model.add_marbles([added_marble])

        model.reset()

        self.assertIn(original_marble, model.marbles)
        self.assertIn(original_marble, model._NenwinModel__all_particles)
        self.assertNotIn(added_marble, model.marbles)
        self.assertNotIn(added_marble, model._NenwinModel__all_particles)
예제 #15
0
def gen_architecture_a(
    input_placer_type: type
) -> Tuple[NenwinModel, VelInputPlacer, Tuple[Node]]:
    """
    Generate the following architecture:
        * The input region is at (-2.5, -1) and has size (5, 2)
            (So it has vertices {(-2.5, -1), (-2.5, 1), (2.5, -1), (2.5, 1)})
        * There are two MarbleEaterNodes, at (-10, 0) and (10, 0)
        * There are four normal Nodes, at (0, -5), (-5, 0), (5, 0) and (0, 5).

    So the normal Nodes surround the input-region, 
    and the MarbleEaterNodes are to the left and right of this.

    Returns:
        * Model holding the architecture descibed above.
        * VelInputPlacer with the input region as described above.
        * Tuple of the two MarbleEaterNodes.
    """

    eater_positions = [(-10, 0), (10, 0)]
    node_positions = [(0, -5), (-5, 0), (5, 0), (0, 5)]
    input_region_pos = np.array((-2.5, -1))
    input_region_size = np.array((5, 2))
    mass = 1
    radius = 0.5

    attraction_function = NewtonianGravity()

    nodes = gen_nodes(attraction_function, mass, node_positions)
    eater_nodes = gen_eater_nodes(attraction_function, mass, radius,
                                  eater_positions)
    model = NenwinModel(nodes + eater_nodes)

    input_placer = input_placer_type(input_region_pos, input_region_size)

    return model, input_placer, eater_nodes
예제 #16
0
파일: canon.py 프로젝트: Nifrec/nenwin
Author: Lulof Pirée
October 2020

An experiment to see if an architecture can be made that accelerates a
ḿarble in a straight line.
"""
import numpy as np
from typing import List

from nenwin.marble_eater_node import MarbleEaterNode
from nenwin.node import Node, Marble
from nenwin.attraction_functions.attraction_functions import NewtonianGravity
from nenwin.architectures.run_and_visualize import run
from nenwin.auxliary import generate_stiffness_dict
ZERO = np.array([0, 0])
ATTRACTION_FUNCTION = NewtonianGravity()
NODE_STIFFNESSES = generate_stiffness_dict(marble_stiffness=1,
                                           node_stiffness=1,
                                           marble_attraction=1,
                                           node_attraction=0)
MARBLE_STIFFNESS = generate_stiffness_dict(marble_stiffness=0,
                                           node_stiffness=0,
                                           marble_attraction=0,
                                           node_attraction=0)


def cannon_experiment():
    """
    Simulate a NAND gate using a Nenwin architecture.
    Also visualizes the simulation and prints the result.
    """
예제 #17
0
 def setUp(self):
     self.newtonian = NewtonianGravity()
예제 #18
0
 def test_repr(self):
     self.assertEqual("NewtonianGravity()", repr(NewtonianGravity()))
예제 #19
0
 def setUp(self):
     self.attract_funct = NewtonianGravity()