• No results found

5.3 Implementation Details: Back-end

5.3.3 Graph Class

Having investigated the QuickGraph library, it was decided to not to use this and write our own to have the functionality we needed. This class has 3 noteworthy methods. Two, GenerateEdges and RecursiveFinder, work together to add Edges to the graph, and the third, GetShortestPath, attempts to find a route through these Edges.

GenerateEdges with RecursiveFinder

This method examines every unit in the graph. If its FMP is non-null, that is, it has a definition, it uses the assumption that the FMP will be of the form <eq, unitName, formula for getting to other unit>, and therefore only looks in the third part of the FMP. It passes this to RecursiveFinder, which recursively sets anything that is not an OMS or an Operator to null, and return this. GenerateEdges takes this, and determines whether it is a simple OMS or an application. If it is a simple symbol (such as with 1 foot = 0.3048 metre), then it ensures that the symbol is one that is known to the system, and if it is, adds an edge between the two units. If the definition is to an application, and is to a compound unit, then this unit will not be in the same graph, and an edge cannot be created between the two. If the unit is not known, then an exception is thrown reflecting this, so that the front-end can ask the user to supply a definition.

GetShortestPath

After the Literature Survey’s investigation of various shortest path algorithms (section 2.6.2, on page 21), it was decided to implement our own Breadth First Search, which will always find the shortest route between two units if it exists. A description of the algorithm follows.

CHAPTER 5. DETAILED DESIGN AND IMPLEMENTATION 50 It first ensures that the units are both in the graph. It then uses the method GetEdgesCon- taining to get an array of the Edges which start or end with the first unit. From now on, when this description talks about “the edges”, it means the subset of edges that the first unit is part of. It then looks through all of these edges to see if the other end is the other unit. If one of them is, then this is the only edge required, so a list containing this single edge is returned. If none of the edges fulfil this, then the method takes the “other” unit of each of the edges in turn, and calls GetShortestPath with this unit and the second unit the user specified. In addition, the edge used to pass between these two units (the user’s source unit, and the potential second unit) is specified, and this is passed to GetEdgesContaining as an edge not to include in the list. This is to ensure that an infinite loop, going forwards and backwards along the same edge, cannot occur. In this recursive manner, the inner GetShortestPath returns the route for the “rest”, so the outer GetShortestPath takes this route, if it is not null, prepends the first edge, and returns the complete list. If it is null, then the outer GetShortestPath tries the next edge in the list, and so on. Eventually, either a route will be found, or it will be determined that there is no route between the two. This algorithm will now be demonstrated with an example.

Let us say we are trying to convert between mile and mile us survey, which will both be in the length graph. Looking at the definitions of the units, it is clear that we should get a route from mile to foot, then foot to metre, then metre to foot us survey then foot us survey to mile us survey. Due to space constraints, in this example, “us survey” units will simply be referred to as “us”. The algorithm does indeed obtain this route, as follows:

• Enter GetShortestPath with source unit = mile and destination unit = mile us, pre- ceding edge = null

• Check both mile and mile us are in the graph—they are

• Get a list of edges containing mile, excluding the preceding edge (null in this case). This is a single edge whose other end is foot.

• This edge (mile to foot) does not reach mile us, so continue

• Go through all the edges in the sublist. This is still only one, (mile, foot). • For this edge, set the new source unit to be the other end of this—that is, foot. • Try to get the shortest path between foot and mile us

– Enter GetShortestPath with source unit = foot, dest. unit = mile us, preceding edge = (mile, foot)

– Check both foot and mile us are in the graph—they are

– Get a list of edges containing foot excluding the preceding edge (mile, foot). There are three of these: (yard, foot), (foot, metre), (inch, foot)

– Examine each of these in turn. As can be seen, none reach mile us, therefore continue

CHAPTER 5. DETAILED DESIGN AND IMPLEMENTATION 51 – Taking the first edge, set the other end (yard) to be the new source.

– Try to find a route between yard and mile us.

∗ Enter GetShortestPath with source unit = yard, dest. unit = mile us, pre- ceding edge = (yard, foot)

∗ Check both yard and mile us are in the graph—they are

∗ Get a list of edges containing yard, excluding the preceding edge. This is a single edge whose other end is furlong.

∗ This edge (furlong, yard) does not reach mile us, so continue

∗ Go through all the edges in the sublist. This is still only one, (yard, furlong). ∗ For this edge, set the new source unit to be the other end of this—furlong. ∗ Try to get the shortest path between furlong and mile us

· Enter GetShortestPath with source unit = furlong, dest. unit = mile us, preceding edge = (furlong, yard)

· Check both furlong and mile us are in the graph—they are

· Get a list of edges containing furlong excluding the preceding edge. This is an empty list, so return null.

∗ The returned route was null, so continue onto the next item in the list. However, the list only contained the (yard, furlong) edge, so there are no others to try. Therefore, return null.

The route from yard to mile us failed, so try the next edge. This is (foot, metre), so set the new source to be metre, and try to find a route from metre to mile us. ∗ Enter GetShortestPath with source unit = metre, dest. unit = mile us,

preceding edge = (foot, metre)

∗ Check both metre and mile us are in the graph—they are

∗ Get a list of edges containing metre, excluding the preceding edge. There are lots of these, as all the prefixed versions of metre are in the graph, with an edge to metre. However, due to space constraints, we will ignore these for now, because they fail in the same way that the other routes have done so far. We will focus on the only other item in the list, the edge (foot us, metre).

∗ This edge (foot us, metre) does not reach mile us, so continue

∗ Go through all the edges in the sublist. Again, in this walkthrough we will only consider the edge (foot us, metre).

∗ For this edge, set the new source unit to be foot us. ∗ Try to find the shortest path between foot us and mile us.

· Enter GetShortestPath with source unit = foot us, dest. unit = mile us, preceding edge = (foot us, metre)

· Check both foot us and mile us are in the graph—they are

· Get a list edges containing foot us excluding the preceding edge. These are the edges (mile us, foot us) and (yard us, foot us).

CHAPTER 5. DETAILED DESIGN AND IMPLEMENTATION 52 · Take the first edge in this list, (mile us, foot us). This edge DOES reach

mile us, so return this edge.

∗ The returned route is not null (it is the single edge (mile us, foot us)). Therefore add the current edge (foot us, metre) to the list to return, and then add the returned route. Return the resulting list.

– The returned route is not null (has two items), so add the current edge (foot, metre) and then the returned route to the list to return, and return it.

• The returned route is not null (has three items), so add the current edge (mile, foot) to route list, and then add the returned list. Return the resulting list.

We now have the list from mile to mile us, ready to use in the conversion.