Blog

  • Examples of the Binary Search Algorithm

    I have published code that shows examples of the Binary Search Algorithm.

    In order for this algorithm to be applicable, we need to assume that we’re dealing with a sorted list to start. As a result, instead of proceeding iteratively through each item in the list, the binary search algorithm continually divides the list into two halves and searches each half for the element.

    It can be shown that the maximum number of iterations this algorithm requires is equivalent to the number of times that we need to divide the list into halves. This is equivalent to a maximum number of iterations along the order of log2(n), where n is the number of items in the list.

  • Queue Data Structure

    I have just published a program that shows examples of a queue data structure.

    This page shows examples of the Queue Data Structure.

    Queues operate under a property of First in First Out (FIFO), which is similar to waiting in a line.

    The two main operations in a queue are to Enqueue (or insert an element) and Dequeue (or remove an element). Just like waiting in line, when an element is enqueued it is inserted at the back of the queue. And also like waiting in line, when an element is removed from a queue, it is removed from the front of the line.

  • Stack Data Structure

    I have just published a program that shows examples of a stack data structure.

    Stacks are an elementary Data Structure where all interaction with the data is done through the looking at the first element.

    There are two main operations on Stacks, Push and Pop.

    The push operation is used to insert an item into the stack. The name push comes from the fact that when an item is inserted into the stack it is put into the first element in the stack, so we think of it as lying on top of the stack.

    Likewise, the pop operation is used to remove an item from the stack. Items are removed from the top of the stack first.

  • Sorting Algorithms (Take Two)

    Sorting is an essential part of our everyday lives. Because of this importance, many people have devoted much time towards improving the performance of different sorting procedures. Previously, I wrote a script comparing many of these algorithms. I decided to break that single script up into several scripts (one for each algorithm) so that the individual algorithms are easier to access and learn more about.

    BubbleSort
    When I first learned about BubbleSort, I thought of being in elementary school and how my teacher would arrange students in line by increasing height. The way she did this was to have us begin by standing in line (in arbitrary order). Then she would start at the beginning of the line and compare the height of each student to that of the student behind him. If the student in front was taller, then she’d have the two students change places. She continued doing this until she reached the back of the line, taking note of whether or not two students had moved or not. If a swap had been made, she would go back to the beginning of the line and start again.

    What my teacher was doing (knowingly or unknowingly) was executing the BubbleSort algorithm. A more formal pseudocode version of this algorithm is listed below:

    BubbleSort(A, start, end):
    swapped <- false while (swapped is false) for (i = start to end) if (A[i] > A[i+1]) then
    temp <- A[i] A[i] <- A[i+1] A[i+1] <- temp swapped <- true end if end for end while end BubbleSort Here is an execution of the BubbleSort algorithm.

    SelectionSort
    One of the more common ways that we do sorting in real life is through something similar to selection sort. Suppose we have a list of graded exams and want to have them in descending order before we pass them back to the students. The idea behind selection sort is to search for the largest element in the list, or in this case the highest test score, move that element to the beginning of the list, and then repeat the same procedure on the remaining portion of the list.

    Here is a more formal pseudocode for the SelectionSort algorithm:

    SelectionSort(A, start, end):
    for (i = start to end)
    min <- i for (j = i+1 to end) if (A[j] < A[min]) min <- j end if end for temp <- A[i] A[i] <- A[min] A[min] <- temp end for end SelectionSort Here is an execution of the SelectionSort algorithm

    InsertionSort
    If we think of the same set of (unsorted) graded exams as in the SelectionSort description that we wish to have them in descending order before we pass them back to the students, an alternative way to sort the exams is to have more of a “sort-as-you-go” type of a procedure where each test is only compared to an already sorted subset of the exams. The way this is carried out is to divide the exams into two piles. Originally, one pile (call it Pile 1) is empty and the other pile (Pile 2) contains the entire set of exams. We take the exam from the top of Pile 2 and compare it to the exams in Pile 1 and place it in the proper location in this pile (removing it from Pile 1). We continue this until Pile 2 is empty, in which case Pile 1 will have all the exams and the set of exams will be sorted.

    Here is the pseudocode for the InsertionSort algorithm:
    InsertionSort(A, start, end):
    for (i = start to end)
    val <- A[i] j <- i while (A[j - 1] > val)
    A[j] <- A[j-1] j <- j - 1 end while A[j] <- val end for end InsertionSort Here is an execution of the InsertionSort algorithm

    MergeSort
    MergeSort is based on a simple “Divide and Conquer” approach. The principle behind it is simple: We want to sort an entire list, but if this entire list is sorted, then each half of this list must also be sorted. It is an easier problem to sort a smaller list than a larger list, so we sort each of the smaller lists. Once these two lists are sorted, we run a merge algorithm which combines the two smaller lists into one larger list. These smaller lists are then sorted using the same principle until our smaller lists are of size 1 or 2, in which case we can simply swap the two items or return the item itself.

    The algorithm itself is similar to the hierarchy at work.
    The boss is given a job – “sort these 8 documents in decreasing order”.
    Boss divides the list into two sets of size 8 and gets two subordinates and says “hey you two, each of you take one of these lists and sort it and get it back to me”.
    Each of subordinates then divide their lists into two distinct lists of size 4 and gets two sub-subordinates to sort these smaller lists.
    The sub-subordinates then divide their lists into two distinct lists of size 2 and gets two sub-sub-subordinates to sort these smaller lists.
    The sub-sub-subordinates now have lists of size 2 which are easy to sort, if they’re ordered, then they say “its already sorted”; if they’re not ordered, they swap the elements and say “here you go”.
    Now that the lists of size 2 have been sorted, the sub-subordinates need to combine them into a list of size 4. This can be done by simply reading both lists and taking the maximum element from each list.
    Similarly, the subordinates can just combine the lists of size 4 into lists of size 8 using that same principle.
    Finally the boss can take the two lists of size 8 and combine it into a sorted list of size 16 using that same principle.

    Here is the pseudocode for the MergeSort Algorithm:
    MergeSort(A, start, end)
    if ((end – start + 1) = 1)
    return A
    end if

    mid <- (end - start) / 2 left <- {A[start], A[start+1], ... A[mid]} right <- {A[mid+1], A[mid+2], ... A[end] left <- MergeSort(left, 0, mid) right <- MergeSort(right, 0, end-mid) return Merge(left, right) end MergeSort Here is an execution of the MergeSort algorithm

    QuickSort
    QuickSort is considered the best sorting algorithm among the ones listed here. Like MergeSort, it operates under a divide and conquer principle. Unlike MergeSort, however, the question of where to divide the list (known as the pivot element) and the recursive calls are a bit more complex decisions.

    The algorithm works by choosing a pivot element in the list (by default we can let this be the middle element in the list, but there are more complex variations that help decide what this should be), and then reordering the list so that the elements to the left (call this sub-list “small”) of the pivot element are all less than the pivot element, and the elements to the right (call this sub-list “big”) of the pivot element are all greater than the pivot element. So after the swap part of quicksort, the largest element of “small” will be less than the smallest element of “big”. We then need to check on whether the sub-lists “small” and “big” need to be sorted, which is true if we have not considered those regions yet. In such a case, we call the procedure Quicksort on each of the sub-lists.

    Here is the pseudocode for the QuickSort Algorithm:
    QuickSort(A, left, right)
    i <- left j <- right pivot <- A[floor((left + right) / 2)] while (i <= j) while (A[i] < pivot) i <- i+1 end while while (A[j] > pivot)
    j <- j-1 end while if (i <= j) tmp <- A[i] A[i] <- A[j] A[j] <- tmp i <- i+1 j <- j-1 end if end while if (left < j) A <- QuickSort(A, left, j) end if if (i < right) A <- QuickSort(A, i, right) end if return A; end QuickSort Here is an execution of the QuickSort algorithm

  • My Life (as a Number)

    A few days ago I went on a nice run that really helped to clear my mind. Afterwards, the song “I Gave You Power” by Nas stayed inside my mind. And I wondered if I could do a similar thing, but more math related. After a quick free-write, what follows is what I came up with.

    My Life (as a Number)
    – by AfterMath

    I’ve been used, abused, and mistreated
    Like a tool for you to do what you’ve got to do.
    But when you’re through, you’re through
    No “how was it for you”
    No asking about what I’ve been through
    Nah, I don’t get a word from you

    Except for those odd days
    When you want to whine and moan and complain
    About how much you don’t like me
    About how much you can’t stand me
    About how much you hate me
    But you keep coming back to me

    And I keep letting you come back to me.
    I keep solving your problems for you
    And when you get into trouble
    I’m the one you turn to.
    But I guess that’s what I was created to do
    At least now you know what numbers go through.

  • K-Means Clustering

    This is how the data looks before the clustering algorithm is run. This is how the data looks after the clustering algorithm is run.

    I have now uploaded my K-Means Clustering Script. The script generates a set of random numbers (as ordered pairs) and asks the user how many clusters we should divide the numbers into and a maximum number of iterations to go through before we stop.

    One of the largest problems that we face today is understanding data. Before we even get to the point of trying to interpret what the data means and making decisions based on that data there is often a problem with the general amount of data. Clustering algorithms seek to solve this problem by defining some notion of similarity and using that notion to group the data into sets or ‘clusters’, where two elements belong to the same cluster if they are considered similar. Once elements are placed into clusters, we can analyze this (generally smaller) set of clusters instead of the entire data set, which should help in understanding the data.

    Finding an exact solution to this problem is computationally difficult. Instead, we can approximate a solution rather quickly using the k-means clustering algorithm. This algorithm attempts to separate a given data set into a user specified (k) number of groups. The k signifies the number of clusters that we will generate. The algorithm works by initially selecting k elements of the data to serve as the “center” of each cluster. Every element of the data is then compared to each cluster center and assigned to the cluster with the closest cluster center. Once every element in the data is assigned to a cluster, the cluster centers may have changed. So the next step is to measure the elements inside each cluster and determine the new cluster center. The process of assigning elements to (new) clusters and determining (new) cluster centers is repeated until either no element changes cluster or we have reached some maximum number of iteration that the user specifies that they do not want to exceed.

    K-Means Clustering can be thought of as an algorithm in the area of unsupervised machine learning. Machine learning is a field of artificial intelligence that focuses on computer programs that have the ability to learn without being explicitly programmed. Unsupervised machine learning seeks to make interpret data without any knowledge of what a “correct” interpretation is. In comparison, supervised machine learning algorithms are useful for data that has been separated into categories. These algorithms generally divide the data into a training set and a test set and seek to produce a function that agrees with the results on the training set.

  • The Simplex Method

    I just added a script which generates a random linear programming problem and executes the Simplex Method Method on it. 

    The Simplex Method, originally discovered by George Dantzig, is one of the most important algorithms in computer science. It literally connects computer scientists to problems in mathematics, engineering, business, economics, transportation, and a host of problems that are faced by everyday people. For many of these problems, no one has yet discovered a pattern or a simpler means of solving it, other than the Simplex Method. Each of these problems has its own difficulties that distinguish it from other problems. While some such problems are important enough to receive their own studies to improve upon the efficiency of the simplex method (Network Flow problems come to mind), there are just too many problems for each one to receive such consideration. Thus we see the importance of the Simplex Method because it can solve these problems as long as they can be formulated as linear programming problems.

    To understand the power of the Simplex Method, we need to understand a class of problems: linear programming problems. A linear programming problem is a problem where we seek to minimize/maximize a linear objective function (over finitely many variables) subject to a finite set of linear inequality constraints over these variables. A general example of a linear programming problem is “The Transportation Problem”.

    The Transportation Problem Suppose you own a manufacturing company and its your job to ship your product from warehouse locations all across the United States to a number of customers. Each customer has ordered a certain quantity of the item, and each warehouse can supply up to a certain amount. Then we define the following variables:

    m = the number of warehouses
    n = the number of customers
    ai = the total amount of item available at warehouse i
    bj the total requirement of customer j
    xi, j = the amount of item shipped from warehouse i to customer j.

    In order for things to work properly, we need that the total amount in supply is equal to the the total amount ordered. If we assumed that we have 3 customers and 2 warehouses, then the following constraints help formulate this problem.

    x1, 1 + x1, 2 + x1, 3 = a1
    x2, 1 + x2, 2 + x2, 3 = a2
    x1, 1 + x2, 1 = b1
    x1, 2 + x2, 2 = b2
    x1, 3 + x2, 3 = b3

    You also know the cost of shipping one unit of the item from warehouse i to customer j and label it ci, j.

    Then the objective function which we seek to minimze is c1, 1x1, 1 + c1, 2x1, 2 + c1, 3x1, 3 + c2, 1x2, 1 + c2, 2x2, 2 + c2, 3x2, 3.

    And we also have that xi, j is nonnegative since we are shipping (and not receiving) goods.

    Because we can state this problem as a linear programming problem, we can solve it using the simplex method. Although this problem was very simple to formulate, the ability to formulate a problem as a linear programming problem is seen as a great accomplishment because there exists so much literature on linear programming problems, and a method on how to solve them, (i.e. the Simplex method). For this reason, much work is often dedicated to finding good linear programming representations of problems.

    Another set of problems of interest are integer programming problems. These problems add the additional requirement to linear programming problems that some or all of these variables can only take on a discrete set of values instead of a continuous realm. Integer programming problems are generally thought to be more difficult to solve than linear programming problems. What makes integer programming problems special is the fact that many problems that are known to be just as difficult as integer programming problems can be formulated as integer programming problems. Although the Simplex Method does not promise to always solve these problems to optimality, it offers a way to approach integer programming problems, and thus every problems that is known to be just as hard these problems which is at least a starting point.

  • New Years is a LEARNINGlover Thing!

    Starting this web site has served as the perfect opportunity to unwind. In particular, two blogs I wrote recently have served different purposes. The first was “The Degrees of Consciousness of a Black Nerd“, where I spoke about many of the things I think about being who I am and relating the the (somewhat unique) set of people that I communicate with on a daily basis. The other was what I’ve been working on since mid December. Its the blog entry I wrote on Sudoku and the Sudoku program that I wrote last month using the Dancing Links Algorithm. Since originally writing that, I’ve updated the program with a lot of Sudoku problems, as well as two types of “hints”. One generates the “possibilities matrix” which basically just shows what is possible for each cell. The other scans the possibilities matrix and searches for isolated cells (cells where some number can only go in one row/column/subgrid). Both those additions were extremely fun and provided a nice opportunity to program in my spare time.

    So I’ve been thinking about these two things and how much I enjoyed the two, but for different reasons. The Degrees of Consciousness of a Black Nerd brought much attention on facebook where the idea was both accepted and rejected and I was able to explain the ideas further and hear similar stories from others who had similar experiences. Sudoku, on the other hand hasn’t generated as much conversation. A few friends have told me that they liked the program, but I don’t know of too many people outside of myself using it. That’s OK. I didn’t really create the program for publication, moreso because I enjoy Sudoku and took it as a challenge to write a program to solve a puzzle.

    That being said, I’ve been thinking about some other things that I would like to do – hopefully they’ll be more than just my opinion, but have some programming, operations research, or mathematical context to them as well. But here’s a list of things that I want to write about in the near future.

    • Connections between math and football (or sports in general). Anybody who knows me knows that I’m a huge sports fan. At other sites, I’ve posted stuff on QB rating systems and the flaws/inaccuracies in them. Part of me would like to look further into this stuff and either do a comparison, create a new rating system, or just try to understand (explain) different scouting metrics, particularly for QBs.
    • I wrote the Sudoku program, but that’s a well studied problem so it was easy to find research that helped me to understand other stuff. I also studied some problems in Ramsey Theory that can be represented by exact covering algorithms and it would be interesting to try to represent these as exact cover problems and to try to use the Dancing Links algorithm to solve these problems as well, maybe to find a comparative analysis to benchmarks.
    • One of the things I’ve picked up on lately is machine learning. While I’ve added flash cards on Bayesian Networks, I would like to add some programs on things like k-means clustering.
    • I added my sorting algorithms a few weeks ago, but would like to also add something on data structures (arrays, linked lists, trees, heaps, hash tables, etc). In undergrad this was called the class that weeded people out of computer science majors, so doing something on this type of stuff I think could be helpful to those who want to understand it better.
    • I have been in the process of writing a linear programming (Simplex) implementation for a while. I would like to get back to that to allow for a solver that can do at least simple algorithms.
    • I’ve written a few drafts that connect math to different areas that I’m interested in (music, sports, philosophy, religion, etc), but I need to find a better way to present the stuff because as they’re currently stated, this stuff can easily be misinterpreted.

    The beautiful thing about this site is that I’m not constrained by any advisor or boss or deadlines. Its more of a how am I feeling right now kind of a thing and these are the things I’m feeling right now. So this list is kind of my “New Years Resolutions” for LEARNINGlover.com, and while I reserve the right to change my priorities any time I feel that something else deserves my attention more, these are the things I’m planning to spend time on in the next few weeks. 

  • My Sudoku Program

    Earlier this week, I was able to write a script that solves the popular Sudoku game. It was a fun experience because along the way I learned about a new way to implement the backtracking algorithm on exact cover problems.

    Say we have a set of items. They could be practically anything, but for the sake of understanding lets think of something specific, like school supplies. In particular lets say that school is starting back and you have a checklist of things you need to buy:

    • a pencil
    • a pen
    • a notebook
    • a spiral tablet
    • a ruler
    • a calculator
    • a lamp
    • a bookbag (or knapsack as I just learned people call them)
    • and some paper

    Suppose also that as you’re shopping for these items you also see that stores sell the items as collections. In order to spend less money, you think it may be best to buy the items in collections instead of individually. Say these collections are:

    • a pencil, a notebook and a ruler
    • a pen, a calculator and a bookbag
    • a spiral tablet a lamp and some paper

    The exact cover problem is a very important problem in computer science because many other problems can be described as problems of exact cover. Because the problem is in general pretty difficult to solve most strategies for solving these problems still generally take a long amount of time to solve. A common technique for solving these problems is called backtracking. This is basically a trial and error way of solving the problem. We try to construct a solution to the problem, and each time we realize our (partial) solution will not work, we realize the error, backup by eliminating part of the current solution and try to solve the problem by constructing another solution. This is basically how the backtracking procedure works. The main caveat to it is that we need to keep track of the partial solutions we have already tried so that we do not continuously retry the same solutions over and over again.

    Example Sudoku Board
    This is an example of a Sudoku board

    In particular Sudoku puzzles can be described as exact cover problems. Doing this involves translating the rules of Sudoku into exact cover statements. There are four basic rules of Sudoku that we need to take into consideration.

    • Each cell in the grid must receive a value
    • a value can only appear once in each row
    • a value can only appear once in each column
    • a value can only appear once in each pre-defined 3 by 3 subgrid.

    In actuality these statements are joined together and what happens is that each position in the grid we (try to) fill in actually has effects in all four sections. We can set up the Suduko problem as an exact cover problem by noting these effects.

    • If a cell (i, j) in the grid receives the value v, then we also need to note that row i,  column j, and the pre-defined subgrid have also received its proper value.

    We can keep track of this by defining a table.

    An Exact Cover Representation of a Sudoku Move
    This is how we construct the new table from a given Sudoku move.
    • The first 81 (81 = 9*9) columns in the table will answer the question of does row i, column j have anything in that position. This will tell us whether the cell is empty or not, but will not tell us the value in the cell.
    • The next 81 columns in the table will answer the question of does row i (of the Sudoku grid) have the value v in it yet.
    • The next 81 columns in the table will answer the question of does column j (of the Sudoku grid) have the value v in it yet.
    • The final 81 columns in the table will answer the question of does the (3×3) subgrid containing (i, j) have the value v in it yet.

    Notice that individually these columns do not give us much information about the grid, but because each value we place into the grid also has a precise location, a row, a column, a value and a subgrid we link together these columns of the new table and are able to understand more about the implications of each Sudoku operation. There are 9 possible rows, 9 possible columns and 9 possible values for each move, creating 729 possible moves. For each possible move, we create a row in the new table which links the columns of this new table together as follows:

    • row[i*9+j] = 1
      (this says that cell (i, j) is nonempty)
    • row[81+i*9+v] = 1
      (this says that cell row i has value v)
    • row[81*2+j*9+v] = 1
      (this says that column j has value v)
    • row[81*3+(Math.floor(i/3)*3+Math.floor(j/3))*9+v] = 1
      (this says that the 3 x 3 subgrid of (i, j) has value v)

    Our goal is to choose a set of moves that fills in the grid. In the exact cover representation of the problem, this means we need to select a set of rows of the new table such that each column of the new table has exactly one 1 in our solution.

    In my script I solve this problem using backtracking and the dancing links representation of this exact cover problem. The way dancing links works is that the exact cover version of this problem is translated from being a simple table to a graphical one where each cell becomes a node with pointers to the rows above and below it and the columns to the left and to the right of it. There is also a header row of column headers which contain information about that column, particularly the column number and the number of cells in that column that can cover it (basically the number of 1’s in the table form of the exact cover version of the problem). There is also a head node which points to the first column.

    Once the graph version of the matrix is set up, the algorithm recursively tries to select a column and then a row in that column. Once these values have been chosen it tries to solve the new version of the problem with fewer cells remaining. If this is possible then it continues, if not then it goes back and chooses another row or another column and row.

    I hope that was an understandable overview of the procedures I used to implement this algorithm. Otherwise I hope you enjoy the script and use it freely to help with your Sudoku   puzzles.

  • Sorting Algorithms

    I just added a script which executes and gives examples of some basic sorting algorithms. Its accessible at Sorting Algorithms

    Right now, the algorithms consist of BubbleSort, InsertionSort, MergeSort and SelectionSort.

    BubbleSort works by comparing items that are next to one another. If the items are not in proper order, they are swapped. The process continues until we pass through the list without making a swap.

    InsertionSort divides an array into two parts, a sorted part and an unsorted part. In each iteration, a new element is compared to all the elements of the sorted part of the array to find where it belongs in this subarray. The algorithm terminates when all elements have been inserted into the sorted part of the array.

    MergeSort is based on the divide and conquer algorithm. It works by calling itself (the function mergesort) on two smaller arrays: the elements in the first half of the array, and the elements in the second half of the array.

    QuickSort is another divide and conquer algorithm. It is based on first choosing a pivot element (we choose the middle element, but it can be any element) and ensuring that all elements that are less than the pivot element are to the left of it in the array, and all elements greater than the pivot element are to the right in the array. Then the quicksort algorithm is recursively called on each part of the array.

    SelectionSort repeatedly finds the minimal value in the list and places it in the first (remaining) position in the (unsorted) array.

    http://www.learninglover.com/examples.php?id=9