Start of topic | Skip to actions

COMP 617S07: (2007_02_07)

Scribe: Angela Yun Zhu Date: 2007-02-07

Bug Report (copy from Joseph's homework)

The following program yields an error:
type 'm:'(nat) snat=
| Z: '(0) snat
| S of let 'm:'(nat) in '(m) snat : '(S m) snat
;;

type exists_snat=E_snat of let 'n:'(nat) in '(n) snat    
;;

let mk_snat (n:int) : exists_snat =
    match n as int in exists_snat with
    | n when n<=0 -> E_snat .|'(0)| Z
    | n when n>0 ->
        match mk_snat (n-1) as exists_snat in exists_snat with
        | E_snat .|n:'(nat)| my_snat->
            E_snat .|'(1+n)| (S .|'(n)| my_snat)
;;  

EXCEPTION:
  Anomaly: assert failure
  (file "parsing/printast.ml", line 1509, characters 6-12). Please report.

This program yields a valid error (mk_snat not defined) when the guard statements "when" are removed.

-- JosephYoung?

Performance Measurement

To measure the performance on sized list and unsized list, here are a bunch of suggestions:

  • Write the sized version and unsized version of all functions (e.g. zip, map, append) together. It will be convenient for comparation.
  • About how many digits you want to keep in your final data: do the experiment several times and throw away those that are varying each time. For example, if you get the time for running function "f" measured as 1.21, 1.23, 1.22. You might want to keep it as 1.2.
  • We might be more interested in the time ratio. You can have all your time normalized to either unsized one or sized one.
    • Daniel: What if the ratio is not varying but the actual data varies from time to time. Like you can have the run time for (unsized_f, sized_f) be (1.2, 1.4), (1.3, 1.5), (1.4, 1.7) ....
    • Walid: That could happen, and ...
  • We are also more interested in significant speed ratio. If we have one always 10 times faster than the another one, then the varying of individual measurement does not matter much.
  • Because of the experiment context, it will also be good to just look at the MINIMUM cycles needed to run the function. In this way, you can get rid of some setup factors like OS processes.
  • Be careful and specific on what you are testing for. Like in the function zip, like we wrote the pattern matching in a way that we first pair the l1 and l2, then do the matching. But pairing will cause a lot overhead. We might want to write aother match to avoid doing the pairing.
  • Also pay attention to the space cost. Sometimes by using optimization like "memorization" you can get benifit for the speed, i.e. you are trading off space for speed. This is also sensiable and sometime might be thought unfair. You need to be clear about space overhead when necessary.

Convert an "if" statement to concoqtion "matching"

Also the use of "if" statement and "match" statement in OCaml can sometime be interchanged, in concoqtion this requirs caution. With "match ... as... in... with...." the concoqtion type will be indicated after "in". But for "if", you don't have a way for that.

This is sometime tricky because you might need to do a conditional checking on the index type. For example, you might want to say: for sized list '(m) listl and '(n) listl,

if (m>n) then....
However you can't do this. One way to do is convert the "if" into "match" which gives you the same semantics.

Type definition for "braun_tree

We know that in DML, a braun tree is defined as:
datatype 'a brauntree with nat =
    L(0)
  | {m:nat, n:nat | n <= m <= n+1}
    B(m+n+1) of 'a * 'a brauntree(m) * 'a brauntree(n)

Since in concoqtion we don't have this "n <= m <= n+1", here is a suggestion to define braun_tree in concoqtion:

datatype ('(n) 'a) brauntree  =
  | Nil
  | Root_1 of 'a * ('(n) 'a) * ('(n) 'a)
  | Root_2 of 'a * ('(S n) 'a) * ('(n) 'a)a brauntree(n)

The trick here is you make a case analysis, which help you with the two optional way to construct braun tree. The potential disadvantage here is that: This two cases might be computational identical. i.e. if we do the map on this two cases Root_1 and Root_2, the functions could be the same or almost the same. One point is that "map" should always preserve the types. Try it out and we will discuss it later.

We also found that "braun tree" is different from "red-black tree", in the way of how they are balanced. It is great since we can try dependent types on these different trings. It is also good when we explain our dependent types to others, we can show how to do one of them and leave the others to the reader.

We will begin with the definition and functions on the easier one: braun tree. And compare it to DML definition. See how things get different in an implementation (concoqtion) that is much concise than the other (DML).

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution 2.5 License. Please follow our citation guidelines.