I have created a gist which prints out the sequence of operations as well as the goal which each step is trying to solve, which should complement my explanation of the Fischer-Wagner algorithm.
To be able to understand the Fischer-Wagner algorithm you have to keep in mind that it is belongs to the family of dynamic programming algorithms. This means that it will compute partial solutions to a bigger problem, store the partial solution and use the result of the partial computation for the next computation.
So what does this mean for the Fisher-Wagner algorithm? In this context this means that each element of the distance matrix d contains the best possible trace of operations to get you from your current string A to another string B. This explanation is still a little bit abstract, so let me explain what I mean by that by walking you through an example.
Lets assume you want to calculate the Levensthein distance of the two strings "ABV" and "FV" using the Fischer-Wagner algorithm. Then your distance matrix will look like this:
+-----+---+---+---+---+
| |j->| 0 | 1 | 2 |
+-----+---+---+---+---+
| i | | # | F | V |
+-----+---+---+---+---+
| 0 | # | | | |
| 1 | A | | | |
| 2 | B | | | |
| 3 | C | | | |
+-----+---+---+---+---+
The first row/column of this table name the indices of the distance matrix, the second name the characters of the strings. '#' is the empty string (i.e. a string with zero length).
Each element of this distance matrix marks a subproblems that you want to solve. For example, the entry [i=0, j=2] contains the shortest distance from arriving from an empty string "" to "FV" the entry [i=2, j=1] contains the shortest distance for the problem "AB" => "F".
Let's fast forward the algorithm to the subproblem [i=2, j=2], i.e. how to get from "AB" to "FV". In this case, the distance matrix looks like this.
+-----+---+---+---+---+
| |j->| 0 | 1 | 2 |
+-----+---+---+---+---+
| i | | # | F | V |
+-----+---+---+---+---+
| 0 | # | 0 | 1 | 2 |
| 1 | A | 1 | 1 | 2 |
| 2 | B | 2 | 2 | |
| 3 | C | 3 | 3 | |
+-----+---+---+---+---+
"B" and "V" are not equal, which means we need to perform one of the following three operations to make them equal:
- delete "B". We take the cost of the cell above d[i=1, j=2], because we know that this cell is the cheapest sequence of operations that gets us from "A" => "FV". However, our problem is getting from "AB" => "FV", not from "A" => "FV. We do know that we can replace "A" by "FV" by applying the operations of cell d[i=1, j=2] (we solved this subproblem earlier), which leaves us with a string "FVB" for the cost of 2. We then deleted the "B" ("FVB" => "FV") and we are done. The cost of this operation is 2+1.
- insert "V". Similar as delete "B", only we take the value to the left d[i=2, j=1] because we know it is the cheapest sequence of operations to get from "AB"=>"F". Since our problem is to get from "AB"=>"FV", we only need to add the cost of inserting "V" and we are done.
- substitute "B" with "V". Similar to the previous cases. We know that d[i=1, j=1] contains the cheapest sequence of operations to change "A"=>"F". Applying this operation changes our problem changes to "FB"=>"FV", which can be solve by substituting "B" with "F".
After considering these 3 options, we pick the cheapest one, which is substituting "B" by "F" (1+1).
After solving all subproblems in that fashion, the output will produce the final result, which is the minimal edit distance from "ABC
=> "FV".