1

I am trying to write pre and post conditions to find the maximum value of a collection 'col'. I'm not really sure how to go about it, recursively so I was wondering if someone could help!

pre: true 
post: result = ...
mark
  • 2,841
  • 4
  • 25
  • 23

4 Answers4

3

What I would do:

pre:  not col.isEmpty()
post: col -> includes(result) and col -> forAll(a | a <= result)

EDIT2: I discussed this question with some OCL experts. They pointed out that it's necessary to have col -> includes(result) in the post condition. Otherwise result may be any value greater than all elements of col, but is not necessarily an element of col.

EDIT:

The post condition means: for each element a of col, it is true that a <= result The forAll operation is defined on page 45 of the OCL Specification 2.3.1. Its syntax is

collection->forAll( v | boolean-expression-with-v )

Its semantics is:

This forAll expression results in a Boolean. The result is true if the boolean-expression is true for all elements of collection. If the boolean-expression-with-v is false for one or more v in collection, then the complete expression evaluates to false. For example, in the context of a company:

Examples:

 context Company
      inv: self.employee->forAll( age <= 65 )
      inv: self.employee->forAll( p | p.age <= 65 )
      inv: self.employee->forAll( p : Person | p.age <= 65 )
gefei
  • 18,922
  • 9
  • 50
  • 67
  • I don´t think this answer is correct since a forAll returns a boolean value and not an element of the collection – Jordi Cabot Jan 04 '13 at 18:43
  • @Jordi I edited my answer and pasted the definition of `forAll` from the Specification. In my post condition I do NOT need this function to return an element of the collection. – gefei Jan 04 '13 at 19:18
  • I still don't understand your solution. Your postcondition is true for any value of result (though I'm not sure you can use result as you do) greater than the elements of the collection, not necessarily the max value – Jordi Cabot Jan 04 '13 at 19:35
  • 1
    if for every `a` in `col`, `a <= result`, then `result` is the max value – gefei Jan 04 '13 at 19:37
3

post: result= col -> any(a | col->forAll(a2 | a >=a2))

where "any" returns one of the elements that satisfy the condition, i.e. like a select but guarantees that only a single element is returned, randomly selected if several elements in the collection satisfy the condition;

the condition inside the "any" guarantees that the selected element "a" is the maximum value in the collection by comparing it with all the others

Check also this OCL tutorial . In fact, the limitations of OCL to deal with aggregates and other kinds of statistical functions is one of the open issues with this language.

Jordi Cabot
  • 8,058
  • 2
  • 33
  • 39
  • +1 for the detailed description of the OCL query, and the additional resources –  Jan 04 '13 at 13:49
  • @Jordi In fact, this answer is problematic. Just suppose the collection has two maximal elements `e1` and `e2`, that is, suppose there exist `e1` and `e2`, and it holds that `col->forAll(e|e<=e1 and e<=e2)`, then your formulation has a problem – gefei Jan 04 '13 at 19:24
  • @gefei, that's why I use an any and not a select iterator. If there are several elements with the max value, any returns one of them (randomly) – Jordi Cabot Jan 04 '13 at 19:32
  • 1
    @JordiCabot `any` returns either `e1` or `e2`, you don't know. and the result can also be either `e1` or `e2`, you can't tell either. therefore `result = any(...)` is not necessarily true. Recall that OCL is declarative, not imperative. – gefei Jan 04 '13 at 19:33
  • I see that we are not reaching an agreement so let´s just let the readers to decide themselves. – Jordi Cabot Jan 04 '13 at 19:38
  • @JordiCabot I've been thinking of it. You are right, the answer is OK. The point is that `col->forAll(e|e<=e1 and e<=e2)` implies `e1 <= e2 and e2 <= e1` and therefore `e1 == e2`. I missed this when writing the above comment. – gefei Jan 04 '13 at 21:03
1

OCL defines Collection::max() as

post: result = self->iterate( elem; acc : T = self.first() | acc.max(elem) )

where "the max operation -supported by the elements- must take one parameter of type T and be both associative and commutative".

I understand that it should be post: result = self->iterate( elem; acc : T = self.asSequence()->first() | acc.max(elem) ) because first() is not defined for Collection.

The collection is converted to a sequence. An accumulator (acc) is initialized with the first value of the sequence. The iterate expression updates the accumulator as the max between the current value of acc and the iterator elem. If the collection is empty the result is self.first(), which is invalid.

Javier
  • 12,100
  • 5
  • 46
  • 57
0

If I understand you correctly than maybe this can help: http://math.hws.edu/eck/cs124/javanotes6/c4/s6.html#subroutines.6.1

Precondition is something that must be meet before your method is executed. This will mostly be some asserts about input data, for example the collection is not null. Post-condition defines what will be true after the method has finished. In your case this can be for example: the method returned element with value maximum value in given collection.

Kamil
  • 411
  • 3
  • 9