From 42d1d8f36baf06abfb977fd3b40e740c43e38b04 Mon Sep 17 00:00:00 2001 From: shiffman Date: Mon, 12 Feb 2024 17:32:55 +0000 Subject: [PATCH] Notion - Update docs --- content/02_forces.html | 2 +- content/03_oscillation.html | 2 +- content/04_particles.html | 8 ++++---- content/06_libraries.html | 4 ++-- content/10_nn.html | 6 +++--- content/11_nn_ga.html | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/content/02_forces.html b/content/02_forces.html index e9a6263d..3b03b90f 100644 --- a/content/02_forces.html +++ b/content/02_forces.html @@ -393,11 +393,11 @@

Parsing Formulas

If you can follow these steps with the example forces I’ll provide here, then hopefully when you find yourself googling atomic nuclei weak nuclear force at 3 AM, you’ll have the skills to take what you find and adapt it for p5.js.

Friction

Let’s begin with friction and follow the preceding steps. Whenever two surfaces come into contact, they experience friction. Friction is a dissipative force, meaning it causes the kinetic energy of an object to be converted into another form, giving the impression of loss, or dissipation.

-

Let’s say you’re driving a car. When you press your foot on the brake pedal, the car’s brakes use friction to slow the motion of the tires. Kinetic energy (motion) is converted into thermal energy (heat). A complete model of friction would include separate cases for static friction (a body at rest against a surface) and kinetic friction (a body in motion against a surface), but for simplicity here, I’m going to work through only the kinetic case. Figure 2.3 shows the formula for friction.

Figure 2.3: Friction is a force that points in the opposite direction of the sled’s velocity when the sled is sliding in contact with the hill.
Figure 2.3: Friction is a force that points in the opposite direction of the sled’s velocity when the sled is sliding in contact with the hill.
+

Let’s say you’re driving a car. When you press your foot on the brake pedal, the car’s brakes use friction to slow the motion of the tires. Kinetic energy (motion) is converted into thermal energy (heat). A complete model of friction would include separate cases for static friction (a body at rest against a surface) and kinetic friction (a body in motion against a surface), but for simplicity here, I’m going to work through only the kinetic case. Figure 2.3 shows the formula for friction.

Since friction is a vector, let me separate this formula into two parts that determine the direction of friction as well as its magnitude. Figure 2.3 indicates that friction points in the opposite direction of velocity. In fact, that’s the part of the formula that says -1 \times \hat{v}, or –1 times the velocity unit vector. In p5.js, this would mean taking an object’s velocity vector and multiplying it by -1:

let friction = this.velocity.copy();
 friction.normalize();
diff --git a/content/03_oscillation.html b/content/03_oscillation.html
index 68b510a8..d6182e14 100644
--- a/content/03_oscillation.html
+++ b/content/03_oscillation.html
@@ -25,13 +25,13 @@ 

Angles

Figure 3.1: Angles measured in degrees
Figure 3.1: Angles measured in degrees
-

You’re most likely to be familiar with the concept of an angle as measured in degrees (see Figure 3.1). A full rotation goes from 0 to 360 degrees, and 90 degrees (a right angle) is one-fourth of 360, shown in Figure 3.1 as two perpendicular lines.

Figure 3.2: A square rotated by 45 degrees
Figure 3.2: A square rotated by 45 degrees
+

You’re most likely to be familiar with the concept of an angle as measured in degrees (see Figure 3.1). A full rotation goes from 0 to 360 degrees, and 90 degrees (a right angle) is one-fourth of 360, shown in Figure 3.1 as two perpendicular lines.

Angles are commonly used in computer graphics to specify a rotation for a shape. For example, the square in Figure 3.2 is rotated 45 degrees around its center.

diff --git a/content/04_particles.html b/content/04_particles.html index 458e2946..2a29a99e 100644 --- a/content/04_particles.html +++ b/content/04_particles.html @@ -43,7 +43,8 @@

Why Particle Systems Matter

Finally, working with particle systems is also an opportunity to tackle two other OOP techniques: inheritance and polymorphism. With the examples you’ve seen up until now, I’ve always used an array of a single type of object, like an array of movers or an array of oscillators. With inheritance and polymorphism, I’ll demonstrate a convenient way to use a single list to store objects of different types. This way, a particle system need not be a system of only one kind of particle.

A Single Particle

Before I can get rolling on coding the particle system, I need to write a class to describe a single particle. The good news: I’ve done this already! The Mover class from Chapter 2 serves as the perfect template. A particle is an independent body that moves about the canvas, so just like a mover, it has position, velocity, and acceleration variables; a constructor to initialize those variables; and methods to show() itself and update() its position:

-
class Particle {
+
+
class Particle {
   // A Particle object is just another name for a mover. It has position, velocity, and acceleration.
   constructor(x, y) {
     this.position = createVector(x, y);
@@ -63,11 +64,11 @@ 

A Single Particle

circle(this.position.x, this.position.y, 8); } }
+

This is about as simple as a particle can get. From here, I could take the particle in several directions. I could add the applyForce() method to affect the particle’s behavior (I’ll do precisely this in a future example). I could also add variables to describe color and shape, or load a p5.Image to draw the particle in a more interesting way. For now, however, I’ll focus on adding just one additional detail: life span.

Some particle systems involve an emitter that serves as the source of the particles. The emitter controls the initial settings for the particles: position, velocity, and more. It might emit a single burst of particles, a continuous stream of particles, or some variation thereof. The new feature here is that particles born at the emitter can’t live forever. If they did, the p5.js sketch would eventually grind to a halt as the particles add up to an unwieldy number over time. As new particles are born, old particles need to be removed, creating the illusion of an infinite stream of particles without hurting the performance of the sketch.

There are many ways to decide when a particle is ready to be removed. For example, it could “die” when it comes into contact with another object or when it leaves the frame of the canvas. For now, I’ll choose to give particles a lifespan variable that acts like a timer. It will start at 255 and count down to 0 as the sketch progresses, at which point the particle will be considered dead. Here’s the added code in the Particle class:

-
-
class Particle {
+
class Particle {
 
   constructor(x, y) {
     this.position = createVector(x, y);
@@ -91,7 +92,6 @@ 

A Single Particle

circle(this.position.x, this.position.y, 8); } }
-

With lifespan ranging from 255 to 0, it can conveniently double as the alpha transparency for the circle representing the particle. This way, when the particle is dead, it will have literally faded away.

With the addition of the lifespan property, I’ll need one more method, one that can be queried (for a true or false answer) to determine whether the particle is alive or dead. This will come in handy when I write a separate class to manage the list of particles. Writing this method is pretty easy: I just need to check whether the value of lifespan is less than 0. If it is, return true; otherwise, return false:

  isDead() {
diff --git a/content/06_libraries.html b/content/06_libraries.html
index 3f36e684..86cbbf8f 100644
--- a/content/06_libraries.html
+++ b/content/06_libraries.html
@@ -28,7 +28,7 @@ 

Living root bridges (

These activities have yielded a set of motion simulations, allowing you to creatively define the physics of the worlds you build (whether realistic or fantastical). But, of course, you and I aren’t the first or only people to do this. The world of computer graphics and programming is full of prewritten code libraries dedicated to physics simulations.

Just try searching open source physics engine and you could spend the rest of your day poring over a host of rich and complex codebases. This begs the question: If an existing code library takes care of physics simulation, why should you bother learning how to write any of the algorithms yourself? Here’s where the philosophy behind this book comes into play. While many libraries provide out-of-the-box physics to experiment with (super-awesome, sophisticated, and robust physics at that), there are several good reasons for learning the fundamentals from scratch before diving into such libraries.

First, without an understanding of vectors, forces, and trigonometry, it’s easy to get lost just reading the documentation of a library, let alone using it. Second, even though a library may take care of the math behind the scenes, it won’t necessarily simplify your code. A great deal of overhead may be required in understanding how a library works and what it expects from you code-wise. Finally, as wonderful as a physics engine might be, if you look deep down into your heart, you’ll likely see that you seek to create worlds and visualizations that stretch the limits of the imagination. A library may be great, but it provides only a limited set of features. It’s important to know when to live within those limitations in the pursuit of a creative coding project and when those limits will prove to be confining.

-

This chapter is dedicated to examining two open source physics libraries for JavaScript: Matter.js and Toxiclibs.js. I don’t mean to imply that these are the only libraries you should use for any and all creative coding projects that could benefit from a physics engine (see “Other Physics Libraries” for alternatives, and check the book’s website for ports of the chapter’s examples to other libraries). However, both libraries integrate nicely with p5.js and will allow me to demonstrate the fundamental concepts behind physics engines and how they relate to and build upon the material I’ve covered so far.

+

This chapter is dedicated to examining two open source physics libraries for JavaScript: Matter.js and Toxiclibs.js. I don’t mean to imply that these are the only libraries you should use for any and all creative coding projects that could benefit from a physics engine (see “Other Physics Libraries” for alternatives, and check the book’s website for ports of the chapter’s examples to other libraries). However, both libraries integrate nicely with p5.js and will allow me to demonstrate the fundamental concepts behind physics engines and how they relate to and build upon the material I’ve covered so far.

Ultimately, the aim of this chapter isn’t to teach you the details of a specific physics library, but to provide you with a foundation for working with any physics library. The skills you acquire here will enable you to navigate and understand documentation, opening the door for you to expand your abilities with any library you choose.

Why Use a Physics Library?

I’ve made the case for writing your own physics simulations (as you’ve learned to do in the previous chapters), but why use a physics library? After all, adding any external framework or library to a project introduces complexity and extra code. Is that additional overhead worth it? If you just want to simulate a circle falling down because of gravity, for example, do you really need to import an entire physics engine and learn its API? As the early chapters of this book hopefully demonstrated, probably not. Lots of scenarios like this are simple enough for you to get by writing the code yourself.

@@ -47,7 +47,7 @@

Why Use a Physics Library?

Incorporating complex features like collisions into a p5.js sketch while still having time to spend with friends and family—that’s the reason for this chapter. People have spent years developing solutions to these kinds of problems, and beautiful JavaScript libraries like Matter.js and Toxiclibs.js are the fruits of those efforts. You don’t need to reinvent the proverbial wheel, at least for now.

In conclusion, if you find yourself describing an idea for a p5.js sketch and the word collisions comes up, then it’s likely time to learn to use a physics engine.

-

Other Physics Libraries

+

allow-break Other Physics Libraries

A multitude of other physics libraries are worth exploring alongside this chapter’s two case studies, each with unique strengths that may offer advantages in certain kinds of projects. In fact, when I first began writing this book, Matter.js didn’t exist, so the physics engine I initially used to demonstrate the examples was Box2D. It was (and likely still is) the most well-known physics engine of them all.

Box2D began as a set of physics tutorials written in C++ by Erin Catto for the Game Developers Conference in 2006. Since then, Box2D has evolved into a rich and elaborate open source physics engine. It’s been used for countless projects, most notably highly successful games such as the award-winning Crayon Physics and the runaway hit Angry Birds.

One important feature of Box2D is that it’s a true physics engine: it knows nothing about computer graphics and the world of pixels, and instead does all its measurements and calculations in real-world units like meters, kilograms, and seconds. It’s just that its “world” (a key term in Box2D) is a 2D plane with top, bottom, left, and right edges. You tell it things like “The gravity of the world is 9.81 newtons per kilogram, and a circle with a radius of 4 meters and a mass of 50 kilograms is located 10 meters above the world’s bottom.” Box2D will then tell you things like “One second later, the rectangle is at 5 meters from the bottom; two seconds later, it’s 10 meters below,” and so on.

diff --git a/content/10_nn.html b/content/10_nn.html index 61693b32..c1d07627 100644 --- a/content/10_nn.html +++ b/content/10_nn.html @@ -523,10 +523,10 @@

Putting the “Network” in Neur
Figure 10.11: Truth tables for the AND and OR logical operators. The true and false outputs can be separated by a line.

One of the simplest examples of a nonlinearly separable problem is XOR (exclusive or). This is a logical operator, similar to the more familiar AND and OR. For A AND B to be true, both A and B must be true. With OR, either A or B (or both) can be true. These are both linearly separable problems. The truth tables in Figure 10.11 show their solution space. Each true or false value in the table shows the output for a particular combination of true or false inputs. See how you can draw a straight line to separate the true outputs from the false ones?

-

The XOR operator is the equivalent of (OR) AND (NOT AND). In other words, A XOR B evaluates to true only if one of the inputs is true. If both inputs are false or both are true, the output is false. To illustrate, let’s say you’re having pizza for dinner. You love pineapple on pizza, and you love mushrooms on pizza, but put them together, and yech! And plain pizza, that’s no good either!

+

The XOR operator is the equivalent of (OR) AND (NOT AND). In other words, A XOR B evaluates to true only if one of the inputs is true. If both inputs are false or both are true, the output is false. To illustrate, let’s say you’re having pizza for dinner. You love pineapple on pizza, and you love mushrooms on pizza, but put them together—yech! And plain pizza, that’s no good either!

- Figure 10.12: The “truth” table for whether you want to eat the pizza (left) and XOR (right). Note how the true and false outputs can’t be separated by a single line. -
Figure 10.12: The “truth” table for whether you want to eat the pizza (left) and XOR (right). Note how the true and false outputs can’t be separated by a single line.
+ Figure 10.12: The truth tables for whether you want to eat the pizza (left) and XOR (right). Note how the true and false outputs can’t be separated by a single line. +
Figure 10.12: The truth tables for whether you want to eat the pizza (left) and XOR (right). Note how the true and false outputs can’t be separated by a single line.

The XOR truth table in Figure 10.12 isn’t linearly separable. Try to draw a straight line to separate the true outputs from the false ones—you can’t!

The fact that a perceptron can’t even solve something as simple as XOR may seem extremely limiting. But what if I made a network out of two perceptrons? If one perceptron can solve the linearly separable OR and one perceptron can solve the linearly separate NOT AND, then two perceptrons combined can solve the nonlinearly separable XOR.

diff --git a/content/11_nn_ga.html b/content/11_nn_ga.html index ae5f08a4..1e77c164 100644 --- a/content/11_nn_ga.html +++ b/content/11_nn_ga.html @@ -275,13 +275,13 @@

The Bird Brain

}

The neural network’s prediction is in the same format as the gesture classifier from Chapter 10, and the decision can be made by checking the first element of the results array. If the output label is "flap", then call flap().

-

Now that I’ve finished the think() method, the real challenge can begin: teaching the bird to win the game by consistently flapping its wings at the right moment. This is where the GA comes back into the picture. Recalling the discussion from Chapter 9, three key principles underpin Darwinian evolution: variation, selection, and heredity. I’ll revisit each of these principles in turn as I implement the steps of the GA in this new context of neural networks.

-

Variation: A Flock of Flappy Birds

-

A single bird with a randomly initialized neural network isn’t likely to have any success at all. That lone bird will most likely jump incessantly and fly way off-screen, or sit perched at the bottom of the canvas awaiting collision after collision with the pipes. This erratic and nonsensical behavior is a reminder: a randomly initialized neural network lacks any knowledge or experience. The bird is essentially making wild guesses for its actions, so success is going to be rare.

Figure 11.4: A population of birds, each with unique neural networks, navigating through the pipes in the neuroevolution process
Figure 11.4: A population of birds, each with unique neural networks, navigating through the pipes in the neuroevolution process
+

Now that I’ve finished the think() method, the real challenge can begin: teaching the bird to win the game by consistently flapping its wings at the right moment. This is where the GA comes back into the picture. Recalling the discussion from Chapter 9, three key principles underpin Darwinian evolution: variation, selection, and heredity. I’ll revisit each of these principles in turn as I implement the steps of the GA in this new context of neural networks.

+

Variation: A Flock of Flappy Birds

+

A single bird with a randomly initialized neural network isn’t likely to have any success at all. That lone bird will most likely jump incessantly and fly way off-screen, or sit perched at the bottom of the canvas awaiting collision after collision with the pipes. This erratic and nonsensical behavior is a reminder: a randomly initialized neural network lacks any knowledge or experience. The bird is essentially making wild guesses for its actions, so success is going to be rare.

This is where the first key principle of GAs comes in: variation. The hope is that by introducing as many different neural network configurations as possible, a few might perform slightly better than the rest. The first step toward variation is to add an array of many birds (Figure 11.4).

// Population size
 let populationSize = 200;