|
cs205: engineering software? |
(none) 20 September 2010 |
1. (8.375 average out of 10) What abstraction function and rep invariant are needed to make the implementation of degree above satisfy its specification?
public int degree () {
// EFFECTS: Returns the degree of this, i.e., the largest exponent
// with a non-zero coefficient. Returns 0 if this is the zero Poly.
return terms.lastElement ().power;
}
We need these properties to ensure the code will execute without any
possible run-time exceptions:
terms != null (otherwise terms. could give a null object exception)This is not enough to know the implementation meets its specification. We also need to know also that the last element in the vector corresponds to the element with the largest exponent with a non-zero coefficient. A sufficient rep invariant would state that no element in the terms array has a power higher than that of the last element and a non-zero coefficient:
terms.size > 0 (otherwise lastElement () could give a NoSuchElementException)
terms does not contain null (otherwise .power could give a null object exception)
for all 0 <= i < terms.size - 1:A more reasonable rep invariant would require that the terms are sorted by their power value, and that all the terms have non-zero coefficients (except for representing the zero poly):
terms[i].power < terms[terms.size - 1].power \/ terms[i].coeff == 0
/\ terms[terms.size-1].coeff != 0
terms.size == 1 && terms[0].power == 0 && terms[0].coeff = 0In an alternate implementation with the same rep (that is, the abstraction function and rep invariant may be different), suppose this is the implementation of coeff:
\/ for all 0 <= i < terms.size:
terms[i].power >= 0
terms[i].coeff != 0
for all 0 < j < i, terms[j].power <= terms[i].power
public int coeff (int d) {
// EFFECTS: Returns the coefficient of the term of this whose
// exponent is d.
int res = 0;
for (TermRecord r : terms) {
if (r.power == d) { res += r.coeff; }
}
return res;
}
terms != null (otherwise terms. could give a null object exception)Nothing else is needed to be convinced the implementation is correct.
terms does not contain null
If we made the rep invariant even stronger:
terms[i].power = i for 0 <= i < terms.size(that is, the vector contains a term record for every power in order) we could implement coeff with just:
public int coeff (int d) {
if (d >= terms.size ()) return 0;
else return terms.getElementAt (d).coeff;
}
Note that this rep invariant does not work well for sparse polys (e.g.,
representing 3x2034 now requires a terms
vector with 2035 elements).
Vector<String> nodes; boolean [][] edges;The most obvious interpretation of this representation is that the boolean value at edges[i][j] determines if there is an edge from nodes.elementAt(i) to nodes.elementAt(j). This means the nodes vector must not contain duplicates (otherwise there could be different edge values for the same node pairs). It also means the size of the edges array must be at least as big as the nodes vector in both directions. It would be reasonable to require it to be equal in size instead, but that would be overly restrictive since it would require copying the edges matrix into a new, bigger matrix everytime a node is added.
Abstraction function:
Nodes = { nodes[i] | 0 <= i < nodes.size () }
Edges = { { nodes[a], nodes[b] } |
forall 0 <= a, b < nodes.size()
where edges[a][b] = true }
Rep Invariant:
nodes != null; edges != null
no duplicates in nodes
edges.length >= nodes.size ()
forall 0 <= i < nodes.size: edges[i].length = edges.length
The last two clauses state that edges is a square matrix,
at least as big as nodes (but possibly bigger).
b. (4.0 / 5)
Set<String> nodes; Set<Edge> edges;where Edge is a record type containing two String values:
class Edge {
String a, b;
Edge (String p_a, String p_b);
}
This one maps very naturally onto the abstract notation. The only
important invariant is that all the names of nodes in the Edge
objects in edges match names of nodes in nodes:
Abstraction Function:
Nodes = nodes
Edges = edges
Rep Invariant:
nodes != null
edges != null
for all e in edges, e.a and e.b are in nodes
c. (3.5 / 5)
Set<NodeRecord> rep;where NodeRecord is a record type that records a String and an associated set of Strings:
class NodeRecord {
String key;
Set<String> values;
}
Here, the abstraction function is more complicated since we need to
extract the nodes and edges from the NodeRecord objects:
Abstraction Function:
Nodes = { el.key | el is an element in rep }
Edges = { { el.key, value } | el is an element
in rep and value is an element in el.values }
or, more precisely
Edges = {}
for (NodeRecord r: rep) {
for (String val: r.values) {
Edges = Edges U { { r.el, val } }
}
}
Rep Invariant:
rep != null
elements of rep are not null
all elements in e.values where e is an element of rep match the
value of f.key for f some element of rep
If efficient means the actual running time on a particular Java implementation, then it is hard to know without knowing details of the underlying Vector and Set implementations.
If efficient means minimal memory usage, then they are all equivalent (all need to create the Set to return), unless we allow the rep to be exposed. If rep exposure is allowed (that is, we modify the spec for getAdjacent to require that the called may not modify the result or use it after the graph is modified), then C can be implemented most efficiently by just returning the corresponding values Set.
The other part of the efficiency question depends on what types of graphs we are representing. If the graphs are very dense (the number of edges is scaling as the square of the number of nodes), then the first representation may be best since it represents the edges with a fixed size matrix. If the graphs are sparse (there is a large number of nodes, but most nodes are just connected to a few other nodes), then we are better off with either B or C.
public void removeNode(String s) throws NoNodeException // MODIFIES: this // EFFECTS: If s is not a node in this, throw NoNodeException. // Otherwise, remove s from the nodes of this, and removes // all edges from the edges of this where either endpoint // of the edge matches s.