H

#### Hendrik Maryns

I wrote a method which completes a partial method, as part of a function

builder class. I really don´t like what it looks like right now, though

I think it is correct (almost, probably).

So if anybody would like to give some comments on how I can do this more

efficiently, but more important, more readably, you´re very welcome.

Here it is, it is no SSCCE, but I suppose you can infer what the other

methods do from their names...

It is rather long, but I do a lot of documenting, so I think it is readable.

I especially want to get rid of the array of iterators, (make this into

a list? Doesn´t seem much better/clearer), and nake the extracted

private function a bit slimmer.

Thanks in advance if anyone is wanting to read this through, otherwise

I'll look into trimming it a bit more.

H.

/**

* Keeps track on whether this function is complete. Mainly to avoid doing

* the computational intense complete function when unnecessary.

*/

private boolean complete = true;

/**

* Returns whether the function is complete.

*/

public boolean isComplete() {

return complete;

}

/**

* Complete the function with respect to the states it returns, the

* signature symbols that are already present in an argument it is defined

* on, and the states that are already present in an argument it is

defined

* on. All transitions that are newly added go to a new state, the dead

* state. New transitions are also added for the dead state.

*

* @post No transitions that were present have changed.

* | for arguments in FunctionInputTuple

* | if ( hasTransition(arguments) )

* | then new.apply(arguments) == apply(arguments)

* @post The domain now contains a new state, the dead state.

* | new.getDomain().getStates().size() ==

* | getDomain().getStates().size() + 1

* @post For each signature symbol that already occurred and for every

* possible combination of states that already occurred, its number

* conforming to the symbol's arity, a transition is registered

* going to a new state, the dead state.

* | let domain = getDomain() in

* | let domainExpansion = new.getDomain().getStates().removeAll(

* | domain.getStates())) in

* | let deadState = domainExpansion.get(0)

* | for arguments in FunctionInputTuple

* | let argStates = arguments.getStates() in

* | if ( domain.getSignature().contains(arguments.getSymbol()) &&

* | for each 0 <= i < argStates.length

* | domain.getStates().contains(argStates

*) )*

* | then if ( ! hasTransition(arguments) )

* | then new.apply(arguments) == deadState

*/

public void complete() {

complete(new State());

}

/**

* Complete the function with respect to the states it returns, the

* signature symbols that are already present in an argument it is defined

* on, and the states that are already present in an argument it is

defined

* on. Existing transitions are untouched, newly added transitions all

* go to the given dead state. New transitions are also added for the

dead

* state.

*

* @param deadState

* The dead state to which all newly added transitions go.

* @post No transitions that were present have changed.

* | for arguments in FunctionInputTuple

* | if ( hasTransition(arguments) )

* | then new.apply(arguments) == apply(arguments)

* @post The domain now contains the dead state.

* | new.getDomain().getStates().size() ==

* | getDomain().getStates().size() + 1 &&

* | new.getDomain().getStates().contains(deadState)

* @post For each signature symbol that already occurred and for every

* possible combination of states that already occurred, its number

* conforming to the symbol's arity, a transition is registered

* going to the given dead state.

* | let domain = getDomain() in

* | for arguments in FunctionInputTuple

* | let argStates = arguments.getStates() in

* | if ( domain.getSignature().contains(arguments.getSymbol()) &&

* | for each 0 <= i < argStates.length

* | domain.getStates().contains(argStates

* | then if ( ! hasTransition(arguments) )

* | then new.apply(arguments) == deadState

*/

public void complete() {

complete(new State());

}

/**

* Complete the function with respect to the states it returns, the

* signature symbols that are already present in an argument it is defined

* on, and the states that are already present in an argument it is

defined

* on. Existing transitions are untouched, newly added transitions all

* go to the given dead state. New transitions are also added for the

dead

* state.

*

* @param deadState

* The dead state to which all newly added transitions go.

* @post No transitions that were present have changed.

* | for arguments in FunctionInputTuple

* | if ( hasTransition(arguments) )

* | then new.apply(arguments) == apply(arguments)

* @post The domain now contains the dead state.

* | new.getDomain().getStates().size() ==

* | getDomain().getStates().size() + 1 &&

* | new.getDomain().getStates().contains(deadState)

* @post For each signature symbol that already occurred and for every

* possible combination of states that already occurred, its number

* conforming to the symbol's arity, a transition is registered

* going to the given dead state.

* | let domain = getDomain() in

* | for arguments in FunctionInputTuple

* | let argStates = arguments.getStates() in

* | if ( domain.getSignature().contains(arguments.getSymbol()) &&

* | for each 0 <= i < argStates.length

* | domain.getStates().contains(argStates

*) )*

* | then if ( ! hasTransition(arguments) )

* | then new.apply(arguments) == deadState

*/

public void complete(State deadState) {

if (isComplete()) {

Domain domain = getDomain();

Set<State> allStates = domain.getStates();

allStates.addAll(getTransitions().values());

addCompletionOf(domain.getSignature(), allStates, deadState);

}

}

/**

* Add transitions to the function for every symbol and combination of

* states in the given signature and set of states. Existing transitions

* are untouched, newly added transitions all go to the given dead state.

* New transitions are also added for the dead state. </p>

* <p>This method is used in the completion process. It is rather useless

* to supply any non-initial state, as newly added states are

unreachable.

* Nevertheless, one can remove some transitions and replace them later.

* That is the only reason to make this a public method.

* TODO: privaat maken?

*

* @param signature

* The signature which should be included in the completion.

* @param states

* The set of states which should be added.

* @param deadState

* The dead state to which all newly added transitions go.

* @post No transitions that were present have changed.

* | for arguments in FunctionInputTuple

* | if ( hasTransition(arguments) )

* | then new.apply(arguments) == apply(arguments)

* @post For each signature symbol that was supplied and for every

* possible combination of the states that were supplied, its

* number conforming to the symbol's arity, a transition is

* registered going to the supplied dead state.

* | for arguments in FunctionInputTuple

* | let argStates = arguments.getStates() in

* | if ( signature.contains(arguments.getSymbol()) &&

* | for each 0 <= i < argStates.length

* | states.contains(argStates* | then if ( ! hasTransition(arguments) )

* | then new.apply(arguments) == deadState

*/

public void complete(State deadState) {

if (isComplete()) {

Domain domain = getDomain();

Set<State> allStates = domain.getStates();

allStates.addAll(getTransitions().values());

addCompletionOf(domain.getSignature(), allStates, deadState);

}

}

/**

* Add transitions to the function for every symbol and combination of

* states in the given signature and set of states. Existing transitions

* are untouched, newly added transitions all go to the given dead state.

* New transitions are also added for the dead state. </p>

* <p>This method is used in the completion process. It is rather useless

* to supply any non-initial state, as newly added states are

unreachable.

* Nevertheless, one can remove some transitions and replace them later.

* That is the only reason to make this a public method.

* TODO: privaat maken?

*

* @param signature

* The signature which should be included in the completion.

* @param states

* The set of states which should be added.

* @param deadState

* The dead state to which all newly added transitions go.

* @post No transitions that were present have changed.

* | for arguments in FunctionInputTuple

* | if ( hasTransition(arguments) )

* | then new.apply(arguments) == apply(arguments)

* @post For each signature symbol that was supplied and for every

* possible combination of the states that were supplied, its

* number conforming to the symbol's arity, a transition is

* registered going to the supplied dead state.

* | for arguments in FunctionInputTuple

* | let argStates = arguments.getStates() in

* | if ( signature.contains(arguments.getSymbol()) &&

* | for each 0 <= i < argStates.length

* | states.contains(argStates

*) )*

* | then if ( ! hasTransition(arguments) )

* | then new.apply(arguments) == deadState

* @post The domain now contains the supplied signature, set of states

* and the dead state.

* | new.getDomain().getSignature().containsAll(signature) &&

* | new.getDomain().getStates().containsAll(states) &&

* | new.getDomain().getStates().contains(deadState)

*/

@SuppressWarnings("unchecked")//$NON-NLS-1$

public void addCompletionOf(Set<SignatureSymbol> signature,

Set<State> states, State deadState) {

Set<State> localStates = new HashSet<State>(states); // This might be

unnecessary. but safer because of possible NoSuchMethodException

localStates.add(deadState);

try {

/* Go through all possible combinations of symbol.getArity() states,

* and add a transition if one isn't present yet.

* @invar all symbols so far are completely processed, i.e. all

* possible combinations of states of number arity are in

* the function

* | for each symbol in localSig

* | for all input in State[symbol.getArity()]

* | if for all 0 <= i < input.length

* | localStates.contains(input* | then if ( ! hasTransition(arguments) )

* | then new.apply(arguments) == deadState

* @post The domain now contains the supplied signature, set of states

* and the dead state.

* | new.getDomain().getSignature().containsAll(signature) &&

* | new.getDomain().getStates().containsAll(states) &&

* | new.getDomain().getStates().contains(deadState)

*/

@SuppressWarnings("unchecked")//$NON-NLS-1$

public void addCompletionOf(Set<SignatureSymbol> signature,

Set<State> states, State deadState) {

Set<State> localStates = new HashSet<State>(states); // This might be

unnecessary. but safer because of possible NoSuchMethodException

localStates.add(deadState);

try {

/* Go through all possible combinations of symbol.getArity() states,

* and add a transition if one isn't present yet.

* @invar all symbols so far are completely processed, i.e. all

* possible combinations of states of number arity are in

* the function

* | for each symbol in localSig

* | for all input in State[symbol.getArity()]

* | if for all 0 <= i < input.length

* | localStates.contains(input

*)*

* | then hasTransition(

* | new FunctionInputTuple(symbol, input))

* @var the number of symbols to be processed

* (Java takes care of this one!)

*/

for (SignatureSymbol symbol : signature) {

State[] inputStates = new State[symbol.getArity()];

Iterator<State>[] iters = new Iterator[symbol.getArity()];

Arrays.fill(iters, localStates.iterator());

/* Initialise the input array with the first state, at the same

* time keeping all the iterators synchronised.

* @invar The first state is assigned to inputStates[j] for

* every 0 <= j < i.

* | for all 0 <= j < i

* | inputStates[j] == iters[j].next()

* @var The number of slots to be initialised.

* | inputStates.length - i

*/

for (int i = 0; i < inputStates.length; i++) {

inputStates* | then hasTransition(

* | new FunctionInputTuple(symbol, input))

* @var the number of symbols to be processed

* (Java takes care of this one!)

*/

for (SignatureSymbol symbol : signature) {

State[] inputStates = new State[symbol.getArity()];

Iterator<State>[] iters = new Iterator[symbol.getArity()];

Arrays.fill(iters, localStates.iterator());

/* Initialise the input array with the first state, at the same

* time keeping all the iterators synchronised.

* @invar The first state is assigned to inputStates[j] for

* every 0 <= j < i.

* | for all 0 <= j < i

* | inputStates[j] == iters[j].next()

* @var The number of slots to be initialised.

* | inputStates.length - i

*/

for (int i = 0; i < inputStates.length; i++) {

inputStates

*= iters**.next();*

}

// add the first transition if it is not yet present

FunctionInputTuple input = new FunctionInputTuple(symbol,

inputStates);

if (!hasTransition(input)) {

addTransition(input, deadState);

}

/* Cycle through all iterators and have it assign each possible

* state to its corresponding slot in the input array, for all

* possible states of the iterators before it; thus producing

* the cross product of the state sets.

* @invar For all configurations for the input array where

* only a state in position 0 <= j < i is different,

* this configuration has a transition.

* | for all input in State[symbol.getArity()]

* | if ( for all 0 <= j < i

* | localStates.contains(input[j]) &&

* | for all i <= j < input.length

* | input[j] == inputStates[j] )

* | then hasTransition(

* | new FunctionInputTuple(symbol, input))

* @var The number of iterators we have to cycle through.

* | iters.length - i

*/

for (int i = 0; i < iters.length; i++) {

loopIteratorAndPrevious(localStates, deadState, symbol,

inputStates, iters, i);

}

}

} catch (Exception e) {

// cannot occur

e.printStackTrace(); // I leave this in for testing TODO: remove this

}

//TODO refactor this method.

}

/**

* Loop through the iterator, adding all arguments generated to the

* function, invoking this same function on the previous iterator after

each

* step. Thus, recursively, the cross product is built.

*

* @param localStates

* The set of states of which the iterator stems.

* @param deadState

* The state to which all new transitions go.

* @param symbol

* The symbol for new transitions are added.

* @param inputStates

* The array of states that is used as input for the add method.

* @param iters

* The array of iterators of the localstates.

* @param i

* The index of the current iterator in iters.

* @post The recursion stops for i < 0.

* | if ( i < 0 )

* | then true

* @post

*/

private void loopIteratorAndPrevious(Set<State> localStates,

State deadState, SignatureSymbol symbol, State[] inputStates,

Iterator<State>[] iters, int i) {

if (i >= 0) {

try {

/* Step through all states in iters}

// add the first transition if it is not yet present

FunctionInputTuple input = new FunctionInputTuple(symbol,

inputStates);

if (!hasTransition(input)) {

addTransition(input, deadState);

}

/* Cycle through all iterators and have it assign each possible

* state to its corresponding slot in the input array, for all

* possible states of the iterators before it; thus producing

* the cross product of the state sets.

* @invar For all configurations for the input array where

* only a state in position 0 <= j < i is different,

* this configuration has a transition.

* | for all input in State[symbol.getArity()]

* | if ( for all 0 <= j < i

* | localStates.contains(input[j]) &&

* | for all i <= j < input.length

* | input[j] == inputStates[j] )

* | then hasTransition(

* | new FunctionInputTuple(symbol, input))

* @var The number of iterators we have to cycle through.

* | iters.length - i

*/

for (int i = 0; i < iters.length; i++) {

loopIteratorAndPrevious(localStates, deadState, symbol,

inputStates, iters, i);

}

}

} catch (Exception e) {

// cannot occur

e.printStackTrace(); // I leave this in for testing TODO: remove this

}

//TODO refactor this method.

}

/**

* Loop through the iterator, adding all arguments generated to the

* function, invoking this same function on the previous iterator after

each

* step. Thus, recursively, the cross product is built.

*

* @param localStates

* The set of states of which the iterator stems.

* @param deadState

* The state to which all new transitions go.

* @param symbol

* The symbol for new transitions are added.

* @param inputStates

* The array of states that is used as input for the add method.

* @param iters

* The array of iterators of the localstates.

* @param i

* The index of the current iterator in iters.

* @post The recursion stops for i < 0.

* | if ( i < 0 )

* | then true

* @post

*/

private void loopIteratorAndPrevious(Set<State> localStates,

State deadState, SignatureSymbol symbol, State[] inputStates,

Iterator<State>[] iters, int i) {

if (i >= 0) {

try {

/* Step through all states in iters

*, adding transitions*

* if necessary, in the meantime iterating over all

* preceding iterators.

* @invar TODO

* @var The number of states of this iterator to be

* processed. (No formal statement possible due to

* restrictive interface of iterators.)

*/

while (iters* if necessary, in the meantime iterating over all

* preceding iterators.

* @invar TODO

* @var The number of states of this iterator to be

* processed. (No formal statement possible due to

* restrictive interface of iterators.)

*/

while (iters

*.hasNext()) {*

inputStatesinputStates

*= iters**.next();*

FunctionInputTuple input = new FunctionInputTuple(symbol,

inputStates);

if (!hasTransition(input)) {

addTransition(input, deadState);

}

loopIteratorAndPrevious(localStates, deadState, symbol,

inputStates, iters, i - 1);

}

// reset the iterator and the input slot

// they don't necessarily get reset to the same value

// each time, (see the Set.iterator contract), but that

// doesn't influence the correctness of the algorithm.

itersFunctionInputTuple input = new FunctionInputTuple(symbol,

inputStates);

if (!hasTransition(input)) {

addTransition(input, deadState);

}

loopIteratorAndPrevious(localStates, deadState, symbol,

inputStates, iters, i - 1);

}

// reset the iterator and the input slot

// they don't necessarily get reset to the same value

// each time, (see the Set.iterator contract), but that

// doesn't influence the correctness of the algorithm.

iters

*= localStates.iterator();*

inputStatesinputStates

*= iters**.next();*

} catch (Exception e) {

// cannot be thrown

e.printStackTrace(); //TODO remove this.

}

}

}

--

Hendrik Maryns

==================

www.lieverleven.be

http://aouw.org} catch (Exception e) {

// cannot be thrown

e.printStackTrace(); //TODO remove this.

}

}

}

--

Hendrik Maryns

==================

www.lieverleven.be

http://aouw.org