automata

Technology is definitely known for marching forward, despite obvious risks and reasons for hesitation.

I'm sure we've all read many occasions lately where the use of ChatGPT is engaging in questionable behavior. It is concerning to say the least, and also presents opportunities to consider scenarios where the gut response is dismissive of important nuance pertaining to the problem.

For example, let's say you saw a headline:

Students using ChatGPT to ace entrance exams, officials baffled

Okay, so it sounds like a perfect use for technology to stir up some muddy waters. They may not seem quite so muddy, depending on your perspective and opinion on entrance exams. Personally, I don't think a written essay is a good enough data point to validate a student either for nor against admission into a university, regardless of their major. Even a Communications or English major will need to develop many other skills besides their composition, what does an essay truly reveal about their academic or professional potential? That aside, let's start our little dig right there.

Read more...

As we hurdle into a near-certain future of ultra-capitalistic technocratic climate chaos hell, sometimes I like to stop and think about certain scenarios.

So, here’s the premise:

Let’s say that I set out one day and decided that I would try to minimize the revenue I generated for businesses in all my day-to-day actions and activities. How much could I reduce? Would it make a difference if a large group of people started doing that?

Here onwards, this post will serve as a sort of brain-dump for ways to go about this “RevMin’ing.”

The first way that came to mind when I began thinking about this was food. I think I spend a decent amount of income, typically around 1/5-1/6 of everything in our household, is spent on food of some sort. Some of this is rather unavoidable. Our baby is on formula and it’s not feasible for some reasons to breastfeed, so my wife and I use formula. I don’t think we can safely make it at home, so we are basically forced to buy it or beg for it. We could do more begging, but that doesn’t necessarily reduce revenue in the long run because a lot of so-called non-profits are using kickbacks from the government for their giving in order to pay their employees and fuel big bonuses for their executives. Anyhow, let’s chalk it up to a necessary expenditure.

Well, what about everything else? It would take some upfront work, but I think we could probably grow some of our own food. We have a very small yard, primarily dominated by dogshit from neighbors, so we probably couldn’t grow much here “on-site” as it were, but there’s probably a community garden someplace that we could use. If we were organized a bit more, we could make trips and have some sort of little micro-ag system in place and mimic how large-plot farms do their thing, on a smaller scale. I’ve often heard that it takes a total of three acres to be completely independent when growing one’s own food. I’m not sure how accurate that is but suffice to say I don’t think we could easily manage three acres worth of community garden space without driving a lot. An acre is roughly a square with 210ft sides. So, it’s quite large. Three acres would produce a lot of food, indeed, but then there’s the tasks involved in such a thing. Tilling, planting, harvesting, drying, storing, prepping, cooking, etc. It’s a complex operation and running it on two adults betwixt the responsibilities of full-time employment and caring for a 5mo baby would be quite a large task.

Would this make a difference if a large number of people started doing it? Sure. At the same time, there’s reason to believe that GMO foods prevent a lot of illness and health issues, there’s a lot of power in the economy-of-scale aspect of larger format farming and having huge machines to do what would’ve taken dozens or hundreds of men working to do, and then the issue of each person finding a 3-acre plot of suitable farm land near enough to them for any of this to make sense… it’s a lot. Undoubtedly, it’d make a big difference, but it’s not very practical.

Instead, consider going vegan. Shop smart, shop frugal. Train yourself in the art of being disgusted with extreme sugarification of all your food and snacks and figure out how to make vegetables the main sustenance you’re eating. Remember, this is an act of war. Take care of yourself, think like a soldier. Eat, be merry, but fight the enemy with your wallet.

What about household things? Now that my wife and I have a child, I feel very differently about the volume of physical possessions because of how many things improve our quality of life with the baby. Do we absolutely need a bouncer? No, but it makes life so much easier because Junie can just hang out while I do dishes or while my wife folds laundry, whatever we’re doing. It’s great to have things like that.

Anyhow, this has been a messy post, but I’m going to just let it ride. It’s an interesting thing to think about, if a little anxiety-inducing. Are we fighting hard enough with our money?

I read a lot of content online. An absolutely absurd amount, really. It’s the ADHD in me, I need to be constantly absorbing something to ever really come to any kind of rest. I’ve never figured out how else to do it, but I just constantly engage with information wherever I am, under whatever circumstances there are.

Anyhow, all this reading online has given way to an uptick in wanting to read more books, here in meatspace. So, I’ve been trying. I had a realization, and I just thought I’d share it.

It doesn’t really cost me anything to write for the internet. I could spend a really long time, writing a large amount and releasing it piece by piece like a blog or even releasing a 100+ page e-book or something like that, but the reality is that without the intention of materializing the effort into physical books, there’s a lacking.

Is this really true? Maybe not so much as it used to be, especially in the advent of the 20XX GPT-era, but maybe a little bit still.

Publishing a book means that someone has to okay a print. Someone has to source the paper. Someone has to organize the binding, confirm the cover design(s). Someone has to make deals with merchandisers. Someone has to deal with shipping. It just never really ends, when you think about it. A thousand people jump to work once someone has written a book.

Along the way, these things may act like checks and balances to make sure the thing isn’t a piece of shit in the first place. Is the book any good?

I guess all I’m really getting at is that there’s a higher implicit bar for writing quality when you’re reading a book. I guess when you put it that way, we all knew that already.

This will just be a braindump of some things on my mind. It may not interest you, that’s alright!

Before I start, I just want to note that my daughter turned 4mo the other day and is doing very well. She loves to babble and “talk” to me and my wife. It’s very sweet. Already I feel an immense pride for her. I feel this churning sort of desperation for her future. I will do anything for her to have enough, for her safety, for her chance at success, for her to find something worth living for once she can comprehend such things.

Anyhow, I’ll dial it back now.

I hate self-driving car examples, but I can’t really think of another good way to get into this. Let’s consider a car at a stoplight. Actually, I’ve decided it’s a she-car. She waits behind a car at a stoplight, and there is a crosswalk ahead. She receives a discrete (!) stream of images from her sensor, and that’s what allows her to see what’s going on around her. Each image is analyzed by some sort of function in her program that identifies objects. Every second that goes by, maybe that’s dozens or hundreds of images and this allows her to keep track of her surroundings. You may already see where this is going. The person who is crossing the crosswalk is visible to our friend the she-car in each frame that they can be seen. However, they will reach a point in the crosswalk where they are obscured by the car ahead, such that our friend the she-car cannot see the pedestrian at all for those frames.

You and I experience this sort of thing all the time without realizing it. If you see someone walk around a corner, you know that when you turn the corner they will probably be there, walking further or whatever they might be doing. They won’t have just vanished. However, if I showed you or our friend the she-car, a photo of the hallway, would you be able to know what is around the corner?

The next insight for the problem lies in the understanding of what we mean by discrete when it comes to spatial awareness. Do our brains receive a series of frames, this way? I’m not really sure, but I don’t really think so. Our neurons can only fire so quickly, so there must of course be some sort of limit. There is a reckoning with Zeno’s paradox somewhere.

So then, is it continuous? Well, I don’t know if I can be convinced of that either. I’ve never been a big calculus guy; I like statistics and combinatorics and the real world with all its little edge cases and rigidness. It’s usually smart to approach things from a discrete angle.

Neural networks are complex beasts, and I’m not sure I can be convinced that such large amounts of calculation are required for keeping track of such commonalities.

I wondered for a bit if there might be a better way. I love evolutionary approaches to things, as you may well know if you’ve seen my other posts, and so I thought about a genetic programming approach. Perhaps I want to adjust my agent’s behavior by having a little program that is executed for each frame. This can be pretty efficient, despite how it sounds. PushGP can be used for stuff like this as-is, and stack-based programming is among the faster paradigms for performance due to the synchronicity between the program and the machine’s internals. Anyhow, perhaps this little program is trained and put into action, and then there’s some form of memory that it has access to, and that’s how our agent can relate its surroundings with this control mechanism. So, each frame comes in and gets passed to our program, which identifies things and updates/mutates the memory bank with the current understanding of the surrounding environment.

How similar is that to the way that we think? Again, or still, I don’t know.

I like to think that it might be something close to that.

Have you ever wondered about the way we remember things? It’s sort of peculiar. If I ask you something like, “Who is your favorite movie star?” then your brain rifles through a lot of folders all in an instant. Without digressing too much, let’s just point out some layers of abstraction:

  • Hearing the sound of my voice
  • Parsing the words from the sounds
  • Parsing the meaning of the words from the grammar and structure of the language
  • Turning those words into some sort of mental objective. Our brain must decide what next to think, which is insane to think about in the first place
  • Who IS my favorite movie star? What movies would they have been in? What makes them my favorite? Is it because of how they made me feel? Is it because of the way they look or act in the movie, or something else entirely?

This is just a few. I could easily come up with a hundred or more, but it defeats the point I’m making. If our memory is some sort of database, then this is an absolutely astronomical demonstration of query optimization and recursion. It can’t be that complicated.

Now, notice something else, if I were to say “Who is your favorite red-headed movie star?” then a different pattern of thought entirely occurs, again in an instant.

What might be happening in that mesh of neurons and bioelectricity? Is it even possible that such a thing could be computed?

I think there’s something to do with graphs here. That may seem like a rather arbitrary thing to say. I think graphs of nodes with properties is an unusually accurate medium for describing thought. Mind maps have been a thing for many decades at this point, but maybe there’s to them then just being useful for organizing.

Doesn’t this match with how it feels to think about this situation? To me it seems like we use our knowledge maps whenever we are making judgments. There’s not a big spreadsheet or anything like that but rather a sea of nodes that we traverse.

There’s plenty of people working on Graph Neural Networks, and Knowledge Graph approaches to machine learning right now. From an anecdotal perspective I am very hopeful that these approaches will flourish.

What happens when an agent can incorporate huge banks of knowledge like Wikipedia into its decision-making process? I don’t mean search; the way computers commonly do, scanning through the bytes for some target string. I can Ctrl-F for anything I want, that’s not the same as incorporating the information. I think that reasonably soon there will be agents able to make judgment-esque decisions based on huge graphs, all while building their own graph as they learn from their mistakes. Probabilistic approaches are great for making use of existing data and approximating, but there are holes like the problem we discussed earlier with the pedestrian in the crosswalk. The knowledge graph can even be attached to these problems, given a sufficiently creative agent to traverse it. When I round a corner after someone, I know they’ll likely be there in the same way I know a car doesn’t disappear to the rear-left of my vehicle on the freeway. They’re in my blind spot and out of my field of vision, but they’re still on my knowledge graph and in my decision-making process.

Anyhow, that’s all for now from me. I’ve been thinking a lot about this sort of thing to distract from the possibility of getting nuked each day. I never thought we’d have to think about that again as a species. One would think, with the capability to just blow up a whole planet and make it unlivable, that we’d all be in agreement to just leave those kinds of weapons off the table entirely. For the love of money, war, and bloodshed, I suppose the show must go on in spite of that tidbit of common sense.

Be safe, thanks for reading.

Good evening.

I haven't written here in a bit.

There is a lot of negativity in the news. More and more, all the time. I just read an article on Invisible People about how private prisons are funding and lobbying pushes to criminalize homelessness. They become slaves in prison.

Don't buy into the centrist rhetoric, “they made their choices” bs. If they ask you if you'd rather do 5 years behind bars or 2 in a farm, what are you supposed to say? That's not much of a choice, if you ask me! I hear this from people here in the midwest all the time when I'm speaking to them about issues of homelessness. There's a lot of working-class people who've never had to really scrape by on the streets or truly rely on the kindness of others who seem to have strong opinions about those that do. It's tricky to navigate this, because these people have projected a light onto these people that's inaccurate whilst simultaneously training themselves to not feel empathy for the groups in question.

I myself, have experienced hunger during homelessness. I can't tell you just with words what it feels like when you know you won't eat anytime in the next 48 hours, and that nobody is coming to help you. Every human being deserves three hearty meals a day, there's more than enough resources for all of us, period. There's no need for anybody to have to starve. Don't buy into the rhetoric. “Earn a living?” That's the most evil phrase I've ever heard. Earning a living implies that the default state is deserving to die. I have a nearly 3-month-old daughter at home. My wife and I love her dearly. Sometimes, I rock her while she's sleeping, and I just think about the future for her. I think about bosses telling her to come in on her off days, about all the evil she'll have to endure in this world, about the hustle-culture she'll be thrust into and the indoctrination she'll hear from her own schools.

Listen, at the end of the day, I worship Jesus Christ as my lord and savior. He brought me through alcoholism, He brought me out of homelessness, He underpins my beautiful family, and He is there for me. I am called by His word to act as a minister in my behavior and in all that I do in this world. I am not meant to call for violence, for disruption, for revenge, even for justice!

I try my best to let myself correspond with these beliefs. I hope that people who really know me, see that I am touched and moved and am given power in the name of Christ. I hope they can see that I am trying to care for the least among us.

Even still, there has to be a line. I am intensely fearful about the next decade in America. I see very strong predictors of regression, both financially and socially, as people are polarized further and further into their pitiful mind-camps. More and more politicians are calling for violence against their opposition. This is incredibly toxic behavior and mark my words, the knock-on effects of this will be absolutely brutal in this country. How long before conservatives look at someone like me, who wants to take care of poor people regardless of circumstances, and see me as a target for violence?

I am readying myself. I am exercising more and more, lately. I want to be able to run 7-8mi at a moment’s notice, to carry a grown adult several miles if needed, and if possible, lift up 1.5x my bodyweight. It's like that saying goes, “Pray for peace, prepare for war.” Well, now is the time to be preparing. I am working overtime a lot. I am gathering up financial resources as well as physical ones. However which way the war against the homeless is waged, I will be there fighting for them. They will not make slaves of the poor without opposition.

I am not sure how to fix America. I don't know if America can be easily fixed. The people of this country have a long and storied tradition about not dealing with significant societal problems until it's dire and widespread. I suspect that homelessness will only even begin to be addressed at the proper level of concern once ¼ or more of the population becomes homeless. It's coming. All the private housing is being bought up and rented back out. The rich grow richer while slowly tightening the financial nooses around all of our necks. The prices of groceries is going up, the price of gas is going up, all the while the average person is making less and less money from working. Wages aren't keeping up. Nobody should NEED to work more than 30~ish hours a week. Back in the 1980s, there were theories that we'd be working ten hours or less each week by now, because robots would take care of all the crappy jobs. It's worked out the wrong way. The robots aren't replacing us because in subduing the human population by inundating the average person with a burden requiring 40-50+ hrs/wk of labor they've automated something much more important than labor: political participation. Are you going to work a 12-hr shift and then go sit in a council meeting for 2-4 hrs after work? Are you going to work six days a week for 3-4 months straight and then use one of your days off to go vote? Keeping in mind that your day off would typically be spent shopping for groceries, taking care of your household, doing laundry, spending some time with your family, etc. There's no time left for any of that. There's no time left for anything except working, which is the thing that benefits the elite class the most in the first place.

A universal basic income could rapidly fix some of the most drastic situations of income inequality, but it's not a panacea on its own. Universal healthcare would rapidly benefit at least ¾ of the people in this country be healthier and would have tremendous knock-on effects economically as healthy people want to do more, travel more, spend more, etc, but it's not a panacea on its own. Taxing the rich and imposing strict, disciplined regulations on huge corporations to keep tax dollars from leaving the country to offshore accounts would make an astronomical difference in terms of available tax budget, but it's not a panacea on its own. The pattern is obvious, right? There are multiple problems in multiple areas that need to be addressed and repaired to lift up the people of America. They need to be handled fairly cohesively because of the interdependent nature of each of these problems as they relate to the everyday lives of 99% of Americans. In order to enact such a series of coordinated legislative refactoring pushes, there would need to be strongly organized voters willing to participate in the political process in every step of the way. Not just voting but being at meetings. Not just being at meetings but taking off work for protests and demonstrations. Not just taking time off work but picketing the elites at their homes and hiding places. Not just picketing the elites but using the strength of their communities to lift the poorest people up in situ, where they are.

Time will tell whether we fix all this or become a giant slave camp run by corporations and the disaffected elites who point out that a vocal minority of people supported the feudalizing of America all the way down. The people who point and sneer at the homeless today are likely to be the strongest advocates for a better way of doing things once the elites rip their lives in half and they become homeless themselves. Show compassion to them, and to everyone, lest you make enemies out of potential friends.

I spend a fair amount of time thinking about interesting uses for computers. I consider myself maybe 1/3 idea-guy, 1/3 code-junkie, 1/3 people-skills. Sometimes, an idea coalesces from amongst my feeble neurons that tickles all three of those little personality sectors.

It may seem bleak, but history has proven me right on this: At the intersection of what is possible, what is not-quite-too-unethical-to-imagine, and what would be profitable comes the future. Typically, no more than 18mo ahead.

I read this article today about a scam involving computer-generated music on Spotify. The details aren’t particularly interesting, nor is the general architecture of the issue novel in any way. There’s a bunch of spam being generated; each song pays out a certain amount based on how many times it is played to customers; it’s freakishly easy to orchestrate the generation of large amounts of fake music with meager programming skills.

Most creatives wouldn’t do something like that. If you bought 1000 canvases, it would seem wasteful and silly to just randomly splatter paint across them all and put them all up on Ebay. Quantity over quality is typically just bad business, plain and simple.

Computers can change that equation a little bit due to the scale of what’s possible. If I wanted to, I could generate thousands of detailed, nuanced, unique, color-theory aware abstract paintings. Per minute.

What do creatives normally do with generation tools?

There’s a talk about procedural content generation by Kate Compton, it’s quite good.

You might not be that interested in game-development, totally understandable, but if you’re interested in a quick overview of what kind of interactive content computers can come up with, it’s a great 30min overview.

People have been sounding this alarm for decades. It’s something that’s inherently understood about computers and how many millions of tasks they are able to do in such short amounts of time. That’s now news to anybody. It’s a lot like the global discussion about automation. It’s been a concern on the radar for decades, even centuries in certain niches, and now that computers have reached this weird apogee of accessibility, things are different.

Automation won’t create jobs forever. Consider horses. On one hand, they didn’t really fare that well economically from the invention of the automobile. There’s an argument to be made that the horses remaining are living better lives as a result, and that’s a good thing. My point being that cars didn’t create any financial opportunities for them. The same is true for human beings. There's only so far that we can go once the robots start advancing faster. When the robots can perform maintenance and installation work, that's a huge turning point for human work, because most of the jobs that were dissolved in favor of robots would have been “replaced” by jobs for humans maintaining and installing those bots. There's a consolidation towards robo-mechanized work that will happen, the way a lot of people that had been in traditional trade work become factory workers to make ends meet. There were fewer shoe cobblers, more shoe-making-machine assembly line workers.

We'll save the diversion into UBI and socialism for another day. Let's instead go to our automation parallel metaphor.

Within the next few years, and likely sooner, large swathes of creative media are going to primarily be generated rather than created by human beings. Digital media obviously faces the most aggressive attacks, but it has company in its misery.

3D printers are set to disrupt more and more materials-related creativity. Software makes it possible to just ask the computer for whatever geometry you need, the code spits it out with almost no regard for how complex it is, and the printer can print it in just a few hours or less.

Architecture will be commoditized to the algorithms. It happens in warehouse planning, grocery store planning, and other locales already. Retail is an interesting niche that has a big head start on this sort of thing, because it has been valuable to know how to plan a grocery store for optimal routing for some time.

I think we might not be far off from AIs that have a more intuitive understanding of how human beings perceive and experience all different forms of art. It's one thing to note the geometric and color-theoretic aspects of works of art, it's another thing altogether to be able to describe how it makes one feel.

Saturn Eating His Own Son – Francisco Goya

How does that image make you feel?

Here’s an image I generated in about 90 sec using a web browser:

The prompt was “giant eating his own son, bleak colors, red blood, eyes wide with rage.” It is a work that has shortcomings, but I daresay that *something* is being evoked here.

And again, that’s just with a laptop and a web browser. You can imagine a creator with just a little more resources than that, maybe $50 of cloud compute or something, would be able to create much more coherent works.

It’s disingenuous to declare “this time it’s different!” every time there is an advancement in technology, but there’s something to be said about the times when a certain technology settles itself in the reach of everyday people. Computers weren’t that big of a deal until everybody had one. Less than a century later, we all carry unbelievably advanced machines with us in our pockets and spend non-trivial amounts of time looking at pet photos. My phone has more computing resources in a minute of its existence than did NASA have for months, if not years, during the sixties. The scale is mind-boggling, but I’m probably preaching to the choir here, we all know computers are powerful these days.

Sometime soon, all that I may write, all that I may think, all that I may say, could just be generated by a sufficiently creative AI. It will never tire as I have become tired. It will never hunger, never thirst. It will be my essence and spirit on demand, with a million times more throughput than I could ever provide.

Am I crazy for wondering what will happen to me when that version of me comes online? When it’s attached to a website and can be browsed for fun?

Time will tell.

Have you played wordle? Yeah, me too. I actually play Xordle everyday now. It’s pretty tough. Anyhow, let me pose you a question and maybe it will spark your imagination. I encourage you to try and program it yourself if you’re interested.

The problem is simple: Out of a list of valid 5-letter words, your task is to assemble a list of five of those words, such that between the five you choose, 25 unique letters are represented amongst them. For example, [Salad, Lunch] only represents 8 letters: [A, C, D, H, L, N, S, U]

Here’s a link to the word list.

So, there’s 12973 words. That’s quite a few. Sadly, we need a rather complex subset, because we need a non-repeating combination of those words. How many combinations are there, anyways?

367,453,247,900,259,316,093.

367 quintillion, as it were.

Wolfram Alpha reports this number as approximately equivalent to 8.5 times the PSPACE of a typical 3x3 Rubik’s cube.

There’s a lot of ways in programming that you might deal with such a large number of possibilities when you need to find only one. One way you might start is by reducing the number of candidates to start with.

We need first a function to determine how many unique letters a word actually has.

def unique_letters(word):
    return sorted(list(set([ltr for ltr in word])))

Nice.

So, thinking about the problem logically, we know that no matter what words we use, there will be five words in the solution. This means that each word MUST have 5 unique letters in it. So, we can reduce our problem space by just removing all the words like “salad,” which have a letter repeated!

aux_words = open("words.txt").read().split("\n")

words = []
for word in aux_words:
    if len(unique_letters(word)) == 5:
        words.append(word)

I use “aux_” to show that a variable is still being built. Also, you could totally throw this into a function or a context manager if you wanted to make your solver even cleaner. I chose not to, because it works either way and this is the first way that I wrote it.

If you’ve never written a genetic algorithm before, there are some concepts you need to know.

The premise is to use the principle of natural selection to gradually arrive at a “fit” solution, given some fitness function or approximation. You generate a bunch of possible solutions upfront; these are typically just randomly selected from a generator.

def generate_random_population(n, words):
    return [random.sample(words, 5) for x in range(n)]

That’s the way I chose to do it. Using random.sample ensures that we won’t have duplicate words in our candidates.

The next step is also the first step of the life-cycle of the genetic algorithm. Evaluation. The premise is that all the candidates would have their fitness calculated so that further steps of the algorithm can be executed. I used a very simple fitness function that just counts up the unique letters in each solution.

def fitness(word_list):
    return len(set([c for c in "".join(word_list)]))
 

As an aside, in most cases, this is where the bottleneck of your program is going to be. You might want to spend some effort making your fitness function as efficient as possible or consider using an approximation.

Historically, genetic algorithms have been effective when searching for single, formulaic solutions to problems that have a lot of possible inputs. One of the coolest known successes is in the case of this space antenna.

This is from the 2006 NASA ST5 satellite. In space, there are special conditions that define the way radio signals interfere with themselves. It’s possible to model this interference function but it’s very difficult for human intuition to approach an optimal solution to what geometry to use for the antenna as a result. Scientists used a special design program to run a genetic algorithm against this interference function and this wonky little antenna is the result. Would you have thought to try this particular shape? In a way, this creativity can set machines apart from humans. They try everything without hesitation and are only acting on what objectively works or not, rather than following intuitions or emotions.

The next step is crossover. Now, in the code we will read shortly, I didn’t end up using a crossover approach, but I might as well explain what it is anyways, in case you end up seeing this approach in the wild.

Crossover involves splitting a candidate up into two or more parts and then recombining those parts into a descendant candidate. In simplistic terms, it’s like taking half of your mother’s DNA, and half of your father’s DNA, and then mashing them together, and that’s *your* DNA. Real life doesn’t really work like that, but the approach can be effective occasionally in implementations of the genetic algorithm.

Mutation is another “genetic operator” that is used in GAs. Mutation is exactly what it sounds like, you are taking candidates and tweaking them just a little bit. Maybe that means slicing a little bit off, maybe that means adding a little bit on, maybe that just means changing the order that some things are in, anything goes.

def mutate_candidate(c):
    # candidate is just a list of 5 strings
    res = list.copy(c)
    res.remove(random.choice(res))
    res.append(random.choice(words))
    return res

So, I used list.copy here to avoid mutating the original candidate. The structure I am using for this is essentially going to be just one big loop in a boring, plain script. To that end, the population will be stored in some variable, and if mutate is changing the original list by-reference, then it throws off the fitness calculation for the next round.

There’s one more function I need to show before we get to the big, juicy part of our program. It’s a simple helper function that just grabs the n most-fit candidates from our population. I will explain why we need it shortly.

def most_fit(pop, n=50):
    return sorted(pop, key=fitness, reverse=True)[:n]

That’s it!

Before we drop head-first into the big function, let’s talk about a few things. I highly recommend that you try to implement this algorithm on your own sometime. It can be on a simpler problem, if that makes it any easier. Start with a sentence, and then evolve random letters until they match the sentence. That sort of thing can be a nice exercise to learn the concept.

I’ve played with this a *lot* and so I know some of the pitfalls and shortcomings of this approach. One of these pertains to the idea of local optima. If we think of all the possible candidates and all the fitness’ of those candidates as a geometric space, it will resemble a mountain range. There will be high peaks where the solution is most fit and low valleys where the solution is least fit, with jagged parts in-between. If we’re not careful, it could be possible for the algorithm to get “stuck” in some of the peaks. Imagine if we were running this program, and the candidates only mutated if their next descendant was fitter. This sounds favorable at first glance, but let’s think about it a little more. If we have picked four words, maybe just [First, Second, Third, Fourth] for example. Ignore the fact that they are different lengths. This might leave us in a position where no possible fifth word can increase the fitness of the candidate as a whole. So every generation, no matter what word is mutated, it will never get more fit and it will never die off.

Our use of random.choice in mutate_candidate technically prevents this, but we can take it a step further and design some categories. There’s probably a technical word for this, in my head I call it “tribes.”

Let’s get into some code now.

def evolve(n, words):
    finished   = False
    highest    = 0
    gen        = 0
    population = generate_random_population(n, words)
    while not finished:
        gen += 1
        
        print(f"gen: {gen} highest: {highest} pop_size: {len(population)}")
        
        elites = most_fit(population, 25000)
        babies = generate_random_population(25000, words)
        worsen = [mutate_candidate(c) for c in list.copy(elites)]
        legacy = random.choices(population, k = (n - 75000) + (100 * gen))
        legacy = [mutate_candidate(c) for c in legacy]
        
        population = elites + babies + legacy + worsen

        gen_highest = max(population, key=fitness)
        
        if fitness(gen_highest) > highest:
            highest = fitness(gen_highest)
            print(f"new highest is {highest}: {gen_highest}")
        if highest == 25:
            finished = True
            print(f"solution: {gen_highest}")

Don’t panic! It’s simpler than it looks. Let’s start at the beginning.

So, finished, highest, and gen. These are just some pieces of state that we will keep track of to have good output as the solver is running.

Finished is a boolean that tells our loop when to stop running. We know that 5 x 5 is 25, so you’ll see at the bottom of the function

if highest == 25:
            finished = True
            print(f"solution: {gen_highest}")

We stop, and print out the solution. Very simple.

Highest is our state for keeping track of the best fitness found so far. We don’t *need* to do this, but I like to see visually how quickly it’s finding improvements. If we were working on a problem-space that had more complexity then it would be helpful to see if it’s finding improvements every few minutes, or once every 12hrs.

Gen is just our generation counter. We increment it at the beginning of every cycle, and that tells us how many times the natural selection cycle has occurred.

Now, let’s move on to our tribes.

elites = most_fit(population, 25000)
        babies = generate_random_population(25000, words)
        worsen = [mutate_candidate(c) for c in list.copy(elites)]
        legacy = random.choices(population, k = (n - 75000) + (100 * gen))
        legacy = [mutate_candidate(c) for c in legacy] 

So, let’s dig in.

Elites are the fittest candidates out of the bunch. This was what we wrote that helper function for. These candidates are the most fit of the bunch and will likely all be the same fitness. If your highest fitness is 24, likely *all* of these candidates will also have a fitness of 24.

Babies are brand new solutions. I’m including them to ensure additional randomness in the gene pool. These babies are just randomly generated from scratch and will likely not be very fit. However, this means that there is constant “motion” in each generation, because next generation these babies will be mutated into possible fitter descendants.

Worsen is a copy of the list of elites, mutated. This is to help the elites from getting stuck, like we learned about earlier.

Finally, we have the legacy. The legacy group is just the mixing pot of the remaining n candidates. You can see that we are using (100 * gen) in our call to random.choices. This lets the total size of population grow each generation. I run this simulation with 400,000 as the initial population size, you can use any number above 75000 and it should still run as expected.

Those are our tribes. I’ve used these tribes because I have played with them before and I have a half-baked intuition for what will work and what won’t, and I felt confident that these would work.

population = elites + babies + legacy + worsen

Here, we shove all the tribes together as the new population and that completes the cycle.

gen_highest = max(population, key=fitness)
        
        if fitness(gen_highest) > highest:
            highest = fitness(gen_highest)
            print(f"new highest is {highest}: {gen_highest}")
        if highest == 25:
            finished = True
            print(f"solution: {gen_highest}")

We find out what our highest candidate is, update our highest variable from before and check to see if we’re finished.

You can find a link to this script here. The word list is up at the top.

I hope you enjoyed reading this, maybe you’ve learned something along the way!

Automata is a website. I chose the name because it represents some special thing that I feel technology has gotten away from.

I intend on writing about anything orthogonal to my personal interests:

  • Genetic Algorithms / Genetic Programming
  • Capacity Planning / Queue Theory
  • Solo Entrepreneurship
  • Game AI / Programming Puzzles
  • Psychology, particularly as it pertains to decision-making, behaviors and attention

Motivations

It seems that just a few generations ago we as humankind believed that technology would soon free us from our toil. As recently as the 1990s there was a theory that we'd only be working 20hrs or so each week, because developments in robotics and automation would make human labor redundant.

Looking around and taking just an anecdotal survey of the work landscape, I see something entirely different today. I see algorithms opposed to people trying to get by. I see this hyperparameter optimizing sludge, filling in every little statistical crevice to maximize some wealthy corporation's pockets. It's like some sort of fungus. Slowly, it fills up its surroundings in search of nutrients. Then, it spikes out its protoplasm and sucks it all out back to homebase.

What will happen when the fungus gets too large? What happens when humans aren't effective anymore? I'm not talking about this AI singularity you've heard about. I'm talking about plain old-fashioned robots doing repetitive work. When cars drive themselves, what will people who drove for a living do? When kitchen-bots cook any meal in a database in minutes, when solar panels power them all for free, when humans cost too much to exist, what happens then?

The sludge is growing even now.

Contact

I can be reached by opening an issue on my github.