So first thing is housekeeping. There are a few imports that need to happen. I’m on a MacOS and using PyCharm as my IDE. I did get a few errors installing the following:

If you’re getting the same problem, try running

pip3 install numpy

It’s likely numpy was trying to install for Python 2.7 instead of Python 3. Next, we have to set up the plot.

Matplotlib requires a figure object, think “blank canvas”. We can then draw our axes and data points over it. Creating an axes object lets us customize the x-y limit and appearance. Similarly, data points must also be objects. We achieve this by creating zero arrays in numpy. These are

Boidsis an artificial life program, developed by Craig Reynolds in 1986, which simulates the flocking behaviour of birds. His paper on this topic was published in 1987 in the proceedings of the ACM SIGGRAPH conference.^{[1]}The name “boid” corresponds to a shortened version of “bird-oid object”, which refers to a bird-like object.^{[2]}Incidentally, “boid” is also a New York Metropolitan dialect pronunciation for “bird”.

The last line gets me every time. It’s a challenge to say “boid” without saying “cawfee”. With a team of 4, I built a migration simulation around the idea of boids. There exists an array of alphas and a larger array of regular boids. The goal of the regular boids is to follow the alphas and the goal of the alphas is to be removed from all boids. To handle scale, my team built our simulation on a distributed system. This is the general process:

- Boids broadcast their location
- Hosts receive/send information over the wire
- Boids perform a function
- Loop

I was curious about a specific function, namely distance calculations. I want to generate 1,000 birds per host so calculating distance point wise would be computationally expensive. Here’s my original Python code:

random.seed(a = 42)

list_birds = []

for i in range(1000):

x = random.randint(0, 100)

y = random.randint(0, 100)

bird = (x, y)

list_birds.append(bird)

def distance(a, b):

x = (a[0] - b[0]) ** 2

y = (a[1] - b[1]) ** 2

dist = math.sqrt(x + y)

return dist

start = time.time()

for combo in combinations(list_birds, 2):

distance(combo[0], combo[1])

end = time.time()

list_birds = []

for i in range(1000):

x = random.randint(0, 100)

y = random.randint(0, 100)

bird = (x, y)

list_birds.append(bird)

def distance(a, b):

x = (a[0] - b[0]) ** 2

y = (a[1] - b[1]) ** 2

dist = math.sqrt(x + y)

return dist

start = time.time()

for combo in combinations(list_birds, 2):

distance(combo[0], combo[1])

end = time.time()

Traditional Python list with dist function: 0.962867021560669. Normally, less than a second for these ~500,000 computations is pretty good. However, for our real time simulation, one time step being almost a second long would be too noticeable. I was curious if the problem was the distance calculation or iterating through a list. So I ran the following:

start = time.time()

for combo in combinations(list_birds, 2):

pass

end = time.time()

for combo in combinations(list_birds, 2):

pass

end = time.time()

Traditional Python list with pass instead of function: 0.03222298622131348. So it does appear the actual calculations are expensive. I then tried using numpy arrays instead of Python lists, such that:

array_birds = np.random.rand(1000, 2)

start = time.time()

pdist(array_birds)

end = time.time()

start = time.time()

pdist(array_birds)

end = time.time()

Numpy array with numpy functions: 0.004333972930908203. Only 4 milliseconds! For a thousand birds! It’s worth noting that when I used numpy arrays, but still passed it through my Python dist function, I actually lost 10 milliseconds in performance. So why did numpy arrays with numpy functions make my performance time so much faster?

Python is an interpreted language as opposed to a compiled language. This means the computer reads Python line by line, which prevents efficiency through multi-core processing. In a compiled language, the magic box compiler reads all the code first, divides the work, and then executes. Luckily, Python is a wrapper for C (a compiled language), and numpy arrays use the backend C. The distance calculations are all independent of each other, meaning they can be performed concurrently and in parallel. Using numpy arrays, the compiler is able to vectorize computations and gain efficiency. However, if I use numpy arrays with Python functions, then I lose performance because I created more overhead through switching. While Python has some built in threading that makes it great for many things, high performance computing is not one of them.

]]>To start, let us review the definitions of contraction mapping and fixed points:

Let be a metric space and . is a *contraction mapping* if there exists a real number , such that

, where the term is called a Lipschitz coefficient for .

Let be a complete metric space and let be a contraction. There there is one unique fixed point such that

The trick to this proof is to claim an inductive sequence by composing with some times.

We show that the set is convergent to a limit by showing it is Cauchy in a complete metric space. That limit point will be our unique fixed point.

Because we have a complete metric space, we can use the following triangle inequality ,

Because is a contraction, we use the definition to obtain the second inequality.

Consider two points in the sequence such as . We can bound their distance using the simplified inequality from above by substituting such that

We can prove the second inequality through a proof by induction. See the Appendix. For now we conclude

where . We know by the metric space definition and the fraction because is bounded by . Therefore, our arbitrary points, is a Cauchy sequence for some . Cauchy sequences are convergent in a complete space so there exists

The next step is to show that is a fixed point. Recall the definition of fixed point . Since we can now define , let us substitute the following

These steps work because we so the limit of one is equal to the limit of the other. This shows is a fixed point. Lastly, we must show this point is unique. Suppose we have another fixed point such that , then we have

This is a contradiction because cannot be both greater and lower than itself. Therefore we claim is a unique fixed point.

This section is focusing on the claim that

The condition we show is

We hope to do this intuitively by showing a pattern and then claiming by induction that this is true for any

This inequality is from the definition of contraction mapping. Let us extend this inequality

Notice the pattern of the power. One less of the power is the th iteration of the first function and the power matches the th interation of the second function. By simplifying the last inequality, we have

]]>

1.) I briefly mention in the Jupyter Notebook that I use S&P 500 over treasury bills as the risk free benchmark data. The use of the benchmark data *changes the degree* of the Sharpe Ratio, but it does not change the* relative comparison* of two Sharpe Ratios using the same benchmark data. If A has a greater Sharpe Ratio than B, it will always be true regardless of the benchmark data. However, depending on the benchmark data, the degree of how much greater A is than B will change.

2.) This code can be scaled and automated relatively easily. One of the things that should happen is adding the Google Stock Market API to be read over hardcoded csv files. The current data is from 2016. Then it should be a simple process to compare several different companies in real time.

3.) I’m still thinking of ways to correct the risk measurement problem. By adding a regression line that fits the growth and then calculating standard deviation, that should help mitigate some of the problem. For this point, I would need to write a proof to show that one way is better than the other.

]]>The bots seemed to approach the game differently than the humans. While we (the bots and the humans) both know that the goal of the game is to destroy the ancient, we approach that goal differently. For example,

def Human(x): try: last hitting creeps

except: group as five

except: group as five

As opposed to

def OpenAI(x): try: group as five

except: last hitting creeps

except: last hitting creeps

Is the above a true simplification of the process? I checked OpenAI’s website and found this. This page details the values given to the bots’ reward functions. It appears the numbers are randomly generated at first, but over large empirical datasets, the optimal value is found. One of the important things to notice is the priority given to buildings. In contrast, last hitting is small. However, let’s take a look at the total weight given to buildings versus last hitting when accounting for gold and xp earned.

score for last hitting creep wave =

number of creeps * last hit weight + xp of creeps * xp weight + gold of creeps * gold weight

melee creeps = 3 * .16 + 57 * 0.002 + 150 * 0.006 = 1.49

range creep = 1 * .16 + 69 * 0.002 + 55 * 0.006 = 0.304

creep score = 1.49 + 0.304 = 1.794

This is the basic formula for 1 pre 5 min creep wave with no denies.

score for last hitting tower = tower bounty * gold weight + t1 tower weight

score for last hitting tower = 150 * 0.006 + 0.75 = 1.65

This is the basic formula for 1 T1 tower.

From the bot match I played, we lost our first T1 around 3 mins. The bots were efficient, only trading about 1 wave for 1 tower. They move quickly from the objective back to lanes or to the next objective. On napkin style math, it appears a perfectly CS-ed wave is worth a little more than a T1 tower. One element I did not weigh, however, is what OpenAI calls “team spirit”. Bots value their teammates scores very highly. How often have I played a pub where my safelane carry refuses to TP because “it wouldn’t be worth it for me to miss this wave”? In contrast, bots are happy to rotate early (their mid laner left the lane at level 4 to secure T1 top). It is not in their code to push as 5, but it is learned that cooperation supersedes individual success. This was also seen by the cores letting supports last hit in lane.

So what about game 3 in casters vs bots? Why did the bots lose so badly? One of the problems Purge noted is the bots were not prioritizing farming other lanes. They would cut creeps and hit towers, but they weren’t TP-ing away as soon as they saw an enemy. Slark was close to his shadow blade for so long, yet didn’t clear some camps to buy it. My brother noted this as a fatal flaw of generality. The bots were not able to adapt to poor game situations and therefore are not as good as he thought. I am here to defend our future overlords (may the bots remember my piety).

By not letting the bots draft their own heroes, it renders their empirical dataset useless. The reward functions are specifically created to maximize their probability of winning a game given certain assumptions– such as drafting. Purge asks why they don’t finish their items and split the map better. It’s because they can’t. It is not in their learned behavior of how to win games. In a situation where they have their optimal lineup, it would be a waste to farm a lane and finish an item. One of my friends argues that changing the draft conditions is as severe as adding a new hero. It changes the immensely complex landscape that is Dota 2 and the bots have never seen it before. The early OpenAI blog posts tell us the first few agents wandered around the map aimlessly before even learning to last hit. Similarly, the bots in game 3 stayed in trees or die backed because they didn’t know what to do.

In summary, given a model the bots have trained, they will always win. Change the fundamental assumptions of that model, and sure, humans will win.

I’m going to walk step by step through my 13 min game against the bots.

The bots were permitted to draft their 5 line up after our 5 line up. We did not have an opportunity to counter their draft. However, I also did not know we were playing a previous patch. Necro only recently received some much needed buffs. Additionally, we picked Slark because one of our players was only comfortable playing that or Sven. I remember hearing Blitz say the bots group early, but I didn’t say anything more about the Slark pick despite it being a very weak early team fighting hero. One of the challenges a human captain always has to balance is comfort versus optimality.

The bots know Slark is a weak laner so they tri-laned against him, despite dual lanes being the meta. This might seem small, but humans are so prone to following the status quo. Dual lanes are the meta? We go dual lanes. In order to protect our weak carry, CM tp’s top to help the lane. I’m left in a 1v1 as Necro vs DP. Because we didn’t see the trilane top until later, CM tp’s top after 1.5-2 creeps in my lane. The result is DP hits level 2 before me and I get zoned out of the lane early, missing a range creep. The bot is already ferrying salves to himself, but my first courier has a null talisman recipe and a wand recipe. The bot has higher base damage, a level advantage, and now more regen. Additionally, the bot did not seem to mind missing a few last hits in order to trade hits with me more. One of the interesting things I noticed is walking into fog immediately stops the bot from trading with me as long as I wasn’t in kill potential range.

The bots push hard and push early as five. As a human, I saw DP leaving my lane as potential to hit a few creeps. I did not defend my tower and they just continued to push. They always had the threat of ravage, the strength of DP ult, and the sustain from WD. With a slark, viper, and 2 disables, our team didn’t have enough damage to get someone bursted low enough to throw a necro ult. We lacked the ability to reach. The bots were happy to throw spells and just damage us, making it hard to defend. If they saw we weren’t as 5, they commited and killed one of us. A popular human dota technique is sending one person to defend while the cores push out the lanes more. The bots don’t allow that. They know you’re out of range and they’re in range. The tower pattern they went for was T1, T2 safe, T1 mid, T3 safe, ranged rax, melee rax. A classic sequence for seasoned players.

yeah right. What late game?

The bots are not afraid of going high ground early, something humans are often taught to fear. They do not rosh then high ground, as humans are drilled to do. How often has my team been in a momentous push mid, but we backed to secure rosh first? (Often delaying the next push by a few minutes). Is it possible humans are just risk adverse? They don’t want to suffer the potential consequences of a failed high ground push. Or possibly that the humans don’t prioritize pushing as much as farming?

The bots also make me view the traditional roles differently. To them, they don’t have a 1, 2, 3, 4, 5. They have someone with reach, someone with damage, someone with control. Who farms the lane is whoever needs something to help the game towards victory. As a drafter, I often say things like “Ok now I need to pick a carry” or even worse, “Ok now I need to pick a Frempo hero” or whoever. The bots think about heroes in terms of who’s going to add the greatest marginal benefit. They don’t think about roles or comfort picks.

When I get home, there are a few things I want to try. 1.) lane mechanics. This means trading more with the other core, playing with different levels of regen. 2.) open-minded drafting. Less concern about the meta and more focus on “how do I win this game?”. What does my next pick need to offer my team?

]]>

I’m open about my bitter childhood because it makes my current all the sweeter. I never talk about my current bitters because they haven’t yet yielded fruit. Talking about my current trails would detract from the overall persona I want to present.

That reason is precisely why I want to start documenting those struggles. It is not so simple as foot of the mountain to high horse. In the process, I hope I will become a better mentor.

A few days ago I did a code sprint competition on HackerRank with my friend Steven, a second year CS major. With fresh Starbucks coffees and muffins in hand, we had one hour to answer 3 increasingly difficult questions. I’ll provide the link for the full description if you want to read them, but I’ll also sum up the question and my problem solving approach to them.

**Question 1**: *Chess Board. Rated: Easy. First place time: 1 min 03 sec. Our time: 14 min 23 sec.*

The input is a 8 by 8 binary array. Determine if the board is a valid chess board.

A chess board needs to alternate values and the following row needs to be the opposite of the values above it. In pseudo code, I know I needed to do these steps:

1.) Check if the first row is alternating

2.) Flip the values for the second row

3.) Check that all even rows are the same as row 0

4.) Check that all odd rows are the same as row 1

5.) If the above are satisfied, return True, otherwise False

We wrote a loop to check each element with the next element in the first row. We wrote a helper function flip(x) that would allow us to loop through a good row and return the opposite for each element, thereby producing the next good row. We then iterate through the whole array row by row instead of element by element to check row equivalence. It was clean code that ran without problems on the first try and scored us full marks.

There will be some who regard our method as overly complicated and others who feel we skipped a few steps in explaining the method. A good teacher can simplify or explain as needed to suit the individual—something I hope to eventually do.

**Question 2**: *Coprime sets. Rated: Medium. First place time: 8 min 20 sec. Our time: 46 mins, did not finish.*

The input is an array of varying integers up to a million or so. Find the number of coprime set pairings that can be made from the given array, meaning the gcd of the geometric sum of both sets is 1. In addition, return the answer as in modulo form.

Unlike the chess board problem, I did not have an immediate plan. I did not even have an immediate understanding of the question. The first thing that came to mind was the math library in python has a gcd function, but that would mean running possibly thousands of iterations through the gcd function and sorting by values == 1. For the extremely large inputs, we would probably time out. It would also be a question if we could even generate all the possible sets that need to be inputted to the gcd function. Then I thought about Euclidian’s algorithm and prime numbers. Finding the gcd is basically simplifying factors until only prime numbers remain. So in any given array, we could get rid of all composite numbers first. And if we get rid of all composite numbers, the gcd of all prime numbers is 1 because primes are all coprime. That was our plan. Steps:

1.) Remove composite numbers from an array so only primes remain

2.) Take the factorial (using python math library) to calculate the total number of “pairs” we can make. **

3.) Convert answer to modulo form

**Sets are unique collections of unordered elements. So even though we are finding “pairs” of sets, it’s basically just different ways of rearranging the same prime array. The number of ways of rearranging a list is the factorial.

We ran out of time typing up this solution and didn’t convert our answer to modulo form, earning 0 marks. Even then, I’m not sure it would have worked on the first try.

**Question 3:** Did not attempt. Did not read.

In summary, I got wrecked. I ranked 1173 out of 1906.

]]>Cavity = 1,862

I use cavity and root canal because there’s a direct relationship between the two, instead of say, cleaning and root canals. A root canal is treatment for a cavity that penetrated the nerve of a tooth. A cleaning is cheaper, but there’s not substantial evidence that shows it’s actually effective at reducing cavities. There’s also not a hard length of time it takes for a cavity to reach the root of a tooth. To be generous, I’ll use 2 years.

1862 = 225(1 + 2r)

r = 363.77% annual

r = 363.77% annual

In this scenario, the cost of poverty charged a simple annual interest rate of 363.77%. In comparison, credit cards hover around 15% APR.

This anecdote is personal. A few years ago, while relaxing at my college dorm, I experienced intense pain on a back molar. I was in such severe discomfort that I went to the hospital and they numbed my mouth until I could see an emergency dentist the next morning. The dentist charged about $2,500 for a root canal, crown, and the accompanying works. I didn’t have that money and neither did my parents. Back home, I would have been using Medicaid and received dental treatment for free. I thought about flying home and missing school, but I would have missed a final exam and thrown away a whole class’s worth of credit. So I opened a new credit card and charged the cost of the root canal. Maybe if I had paid out of pocket for a dentist earlier, I could have avoided the interest rate of poverty.

This is one of the reasons the poor stay poor. I’m very fortunate to attend a selective college that has grants to help cover medical costs. With their help, my root canal did not put me in a spiral of debt. It is one of the privileges of attending a good college– but I’ll talk about diversity in higher ed another day.

]]>Amount

Property

Number of records

**ProPublica puts a disclaimer that government agencies have fought to not disclose their spending so it is likely that this dataset is incomplete.

It seems our President is a businessman, after all.

]]>So how much is the difference between the Amazon affiliate sellers versus your small online merchant? Using the same dataset from the article, I made some histograms showing the difference in display price versus the total price (price + shipping). For the Amazon goods, you should expect, on average, another $7.69 to the sticker price.

And for consistency, here is the third party histogram. There is no difference between the sticker price and the actual price because Amazon’s algorithm chooses to display the full price.

However, this doesn’t mean Amazon goods are always more expensive than third party goods. Even with the shipping cost, Amazon goods can be cheaper. The main point is prices are misleading on purpose because the firm’s goal is to maximize profit, not consumer surplus.

]]>