CO538 Anonymous Questions and Answers |
This page lists the various questions and answers. To submit a question, use the anonymous questions page. You may find the keyword index and/or top-level index useful for locating past questions and answers.
We have taken the liberty of making some minor typographical corrections to some of the questions as originally put. Although most of the questions here will have been submitted anonymously, this page also serves to answer some questions of general interest to those on the course.
When asking questions, please do not simply paste in your code and ask what is wrong with it, as these types of question are hard to answer in a public forum (resulting in either no answer, or an answer which will only be of use to the person asking the question). In many cases, a question about code can be formulated in general terms. For example, if you have an `IF' block that results in an `incorrect indentation' error, you might ask, ``what is the correct syntax for an occam `if' statement ?''. Questions of this form are easier to answer, and are meaningful to all.
Questions that are not suitable for these public pages (i.e. those that contain assignment-specific code), should be mailed to your seminar-leader.
When will the q4 model answer become available?
Done! Also for q5. See:
answers/a4_slow.occ answers/a4.occ answers/a5.occ
in the usual place.
Keywords: q4
You say the q6 program can be compiled and the read.data sends to straight to display. Then why is there no output displayed?? Shouldn't it display something as it's getting the correct protocol and data within it.
Well, I just compiled your q6.occ file on raptor and ran it:
raptor% ./q6 < nn_tiny.txt Name Mark ---- ---- Fred -10 Alison 944 Fred 720 George 628 Alison 20 Peter 331 raptor%
So, it displays output for me! I've left the q6 executable in the course exercises directory, so you can check ... although it's trivial to compile the starter file yourself in your own directory.
Keywords: q6
I am a little confused to as what happens in the cell process of sort pump:
BYTE x, n: WHILE TRUE SEQ in ? x out ! end.marker WHILE x <> end.marker ... body of inner loop
Why do you send the end.marker down the out channel?
This was explained in the lecture covering this topic.
Groups of numbers, separated by end markers, are fed into the sort pump. This means they are fed into the pipeline of cells by which it is implemented. So, groups of numbers, separated by end markers, are fed into the first cell in the pipeline. Each cell looks out for that end marker (which, to save one test in the inner loop, we know is greater than any of the numbers in any group). When it finds that end marker, the inner loop ends and the cell gets ready for the next group (by looping back in the outer loop).
But that first cell must pass on the end marker ... otherwise the next cell (and the next cell (and the next cell ... )) will not get that end marker between the groups -- and they need them!
But I agree that outputting the end marker before processing the group is a little odd! It makes no difference since the next outer loop does the same (and provides the end marker following the first group). However, it does mean that there is a funny start-up effect in that a stream of end markers (as many as there aare cells in the pipeline) are the first things out of the pump. That just indicates a bunch of zero-length groups, which are harmless and ignored by whatever is consuming them. Following this, the pump behaves as expected (i.e. it produces sorted groups of numbers separated by a single end marker).
I changed this code in the Powerpoint Chapter 5 slide 19, so that it outputs the end marker after processing each group. This is more logical and does not give rise to the start-up flow of end markers. Here is that revised structure. Note: I've changed the name 'x' to 'max' and moved its declaration inside the outer loop. I've also moved the declaration of 'n' inside the inner loop (which is not shown below). Variables should not be declared where they are not needed -- 'max' does not need to be known outside the outer loop and 'n' is only needed in the body of that inner loop:
WHILE TRUE BYTE max: SEQ in ? max WHILE max <> end.marker ... body of inner loop out ! end.marker
Keywords: sort-pump
Two questions in one here. First of all waht is a counted array?
Second currentley I am trying to create a cell for q6. All I am trying to do at the moment is read in the protocol then just output what ever comes in. So just like the ID in the lego.occ. Looking at Fred's Occam tutorial as the protocol is a tagged-protocol I need to do something like:
PROC cell(CHAN OF NAME.NUMBER in, out) in ? case string; INT::[]BYTE; INT ... do something poison ... do something else :
How do I read in the "string; INT::[]BYTE; INT" and the "poison" into a varible.
First question: section 7.4 of the "occam2 Checklist". Also, slides 5-45 through 5-47.
Second question: section 7.3 of the "occam2 Checklist". Also, slides 10-18 through 10-21 (in the Powerpoint Chapter 10, these are currently slides 20 through 25).
Please look through your notes before asking questions here!
I was looking through the questions on arrays and as you said arrays have to be of a fixed size and are not initialised by default. So how do you initialise them to be empty or the equivalent of java's null ? Also can arrays of a smaller size be assigned to a larger capacity array (assuming they are of the same type) ? For example:
[num]BYTE temp := "":
does not work (and neither does ":= []")
There is no concept of null in occam! There are no objects in occam!!
When we declare an occam array:
[num]BYTE my.array:
This is (roughly) similar to declaring and constructing a Java array:
byte[] myArray = new byte[num];
occam variables, including array variables, always refer to allocated space. Whether that space has defined values set in them is up to our program. No default values (e.g. zero) are set. To initialise array values, it's the same as in Java -- simply iterate over the elements, setting them in turn. For example:
SEQ i = 0 FOR SIZE my.array my.array[i] := 0
[Aside: the statement above (that "occam variables ... always refer to allocated space") is strictly true for classical occam. The new occam-pi has mobile data types, space for which is dynamically allocated. So, mobile variables from time to time may not refer to allocated space. However, in that case, the occam-pi language rules (enforced by the compiler) do not allow us to attempt to access their values -- so there remains no concept of null (and null pointer error) that you can fall into, :).]
You can't assign a smaller array to a larger array -- or a larger array to a smaller one. The size of an array is part of that array's type in occam, so different sized arrays are not assignment compatible.
occam does however support something that helps here, that Java doesn't: array segments (someimes called slices -- see the last paragraph of section 5 in the "occam2 Checklist"). A segment expression allows a portion of an array to be used, instead of the whole array. For example:
[my.array FROM 2 FOR 4] := "fred"
will assign those bytes to 4 bytes of `name', starting at index 2. It is the same as the code:
VAL []BYTE tmp IS "fred" SEQ i = 2 FOR 4 my.array[i] := tmp[i-2]
or:
SEQ my.array[2] := 'f' my.array[3] := 'r' my.array[4] := 'e' my.array[5] := 'd'
but the segment expression is much more succinct. The other elements of my.array are untouched. Should the above my.array have less than (2 + 4) elements, of course there would be a range error.
Couple of other bits of syntax for these segment expressions: either the FROM part or the FOR part are optional -- but not both! The expression "[my.array FOR n]" means the first n elements of my.array (i.e. "[my.array FROM 0 FOR n]"). The expression "[my.array FROM m]" means the last m elements of my.array (i.e. "[my.array FROM m FOR (SIZE my.array) - m]").
If you want more (!) and like puzzles, check out Question 44 (2002).
Other things raised by your question. In occam, "" and [] represent an array of zero elements -- though these only have limited use. The new KRoC (occam-pi) now recognises `[]' as an empty array of any type ("" is specifically an zero-length array of BYTEs). These are useful as arguments to PROCs or FUNCTIONs that require array arguments, but the particular call does not need to pass any data.
Initialisation and declaration can be combined, but requires a slightly different syntax than what you've got above:
INITIAL []BYTE name IS "fred": -- declares and assigns a [4]BYTE array
The LHS and RHS types of the `IS' must match. But I doubt this will be useful here.
Keywords: arrays , array-segments
I "think" I am nearly there with q6 I just have one problem left. If all the names are the same size then my code works fine :-). However if the names are different sizes it goes a bit wonky. Say I have:
Mandy 551 Mandy 976 Sonya 577 Hubert 969 Mandy 127
And I have "[INT]BYTE temp:", where the max length for a name is 8 and a space is represented as ~, "temp" would hold values something like this:
1) Mandy~~ 2) Mandy~~ 3) Sonya~~ 4) Hubert~ 5) Mandyt~
The `t' of "Hubert" is not being cleard when I push "Mandy" into it. Well thats all I can come up with why it is not working. How would I clear a string to make it all spaces?
Any tips would be great!
To clear all the elements of a byte array to spaces is trivial (and obvious!):
SEQ i = 0 FOR SIZE my.array my.array[i] := ' '
But it sounds like you're not calling "make.string" correctly. Whenever you read from the tagged protocol channel into the byte array (along with the number of bytes, say "count", communicated for the name and the associated mark), only the first "count" elements of the array are changed -- the rest are not touched. You must call the "make.string (name, count)" procedure, where "name" is the name of the byte array. This clears any bytes left over in "name" to zero (the ASCII NUL character) -- that is all bytes apart from the first "count" elements. That will erase your left-over `t~'.
Keywords: q6 , string-handling
I've finished my version of question 6, and sometimes when I run it with the .txt files I get this error in the shell window:
USERPROC: can't read KBDPROC's go-ahead ''
But then if I run the same .txt file again the error disappears and everything is fine and I get a correct list. Should I worry about this ?
Is this on raptor's KRoC ? This problem existed years ago, but should have been fixed years ago too -- I can't seem to reproduce it. Please could you mail me (frmb) with the details (kroc version, UNIX version, etc.).
Keywords: kroc
Good afternoon; Just wanted to know if we can add additional procs to "q6.occ", or if everthing should be implemented within "collate.marks". I am referring to a cell process that takes in a "name.number", then makes some appropriate comparison/action.
Also, am I right in thinking the first and last cell cannot be replicated as they connect to non-cell channels. Finally, I am unsure how the replicator works/fits in -- do we create the maximum number of cells to correspond to the maximum number of different names, as we don't know in advance how many unique names there are. If so, isn't this inefficeient ? i.e. if we replicate 14 cells and there are only 2 different names, or is our main concern speed ?
Yes, you can add additional PROCs to "q6.occ". You can declare such PROCs either above "PROC collate.marks", or inside it -- up to you (but outside and above is usually clearer).
As replication goes, yes, you are right in that the first and last cells in the pipeline connect slightly different -- these connect to the external channels. It would be possible to arrange this differently, with all the cells generated using a replicated PAR, but then you'd need two "id" type processes to connect the two end channels to the external channels. Separating out the first and last cells is just a bit simpler.
As far as efficiency is concerned, the use of unnecessary cells isn't a problem. Occam is extremely light-weight in its implementation: a sort-pump containing 500,000 processes will get data through it in under 1 second on most systems. The current performance "micro-benchmark" for communication/context-switch time is under 100ns (on an 800 MHz P3) -- meaning that over 10,000,000 processes can be scheduled per second on this hardware.. :-). Compare this with the threading support offered by languages such as Java -- you'd be lucky to get 1000 parallel processes to work (either at all, or in useful time).
Keywords: q6
I am having trouble installing the vim extensions on my linux machine at home. My version does not highlight keywords or auto-indent etc. :( Do I just copy the vim-extensions folder into my vim directory as suggested on the vim website, or are there other things I need to do ? (the info on their website is very brief). I wasn't sure if vim would automatically detect and use the new folder/extensions.
The kent vim extensions by default will replace your "~/.vimrc" file. This is where Vim looks for things when it starts up. You don't actually need the kent Vim extensions, however, since occam syntax highlighting is now included in the Vim distribution (as shipped for Linux distributions). You do need to turn syntax highlighting on, however (and this is generally a good idea for any editing in Vim, assuming you have a colour-capable terminal). My own "~/.vimrc" file contains, amongst other things:
syntax enable set foldmethod=marker map <F2> zc map <S-F2> zC map <F3> zo map <S-F3> zO map <F4> zM map <F5> zR
The first command turns on syntax highlighting. The second tells Vim to use folding, based on the "marker" method (the fold markers are, by default, "{{{" and "}}}"). The remaining commands map my mostly unused function-keys to fold-operations. E.g. F2 and F3 close and open folds respectively. F4 and F5 open all and close all folds respectively.
The "~/.vimrc" file that the kent-vim-extensions should install is on raptor in "/usr/local/courses/co516/kent-vim-ext/-kent-vim-ext-vimrc". If you look at this file you'll see it sets up some things before loading other .vim initialisation files.
Hello, I'm really struggling with q6. I have read all the q6 anon Q's and have got a start, but I don't know where to continue from there:
[snip code]
I don't know what do here; am I just suppsed to store the names in an array of array of bytes, iterate and check if they are equal to each other then update the marks ?
Please help! any step by step instructions would be immensely helpful (or anything at all).
You're actually on the right lines here. Yes, if you implement "collate.marks" as a single serial (sequential) process, then you'll need a large 2D array of BYTEs to hold the names (as well as other arrays to hold the marks, etc.). And yes, when a new name comes in, iterate over the array looking for a match. Programming this way is not nice, however. The other approach is to use parallelism, and to a large extent follow the logic of the sort-pump (except that sorting isn't the main task here).
This assessment has been extensively discussed in the last two seminars. Step-by-step instructions were presented there ...
Keywords: q6
Hello. I think I have almost got a solution for q6, just that it's not terminating nicely even though I think I have dealt with the "poison" end marker by changing the state of the BOOL controlling the WHILE loop. Its just deadlocking.
If it's deadlocking it means that something hasn't terminated properly. Trace your code for a bit of data (i.e. several 'string; ...' variants) and then 'poison' to see where it might be getting stuck. Don't forget to pass on the 'poison'.
If you've got KRoC/Linux or KRoC/cygwin, compile with the "-d" flag (debugging) and the deadlocked process(es) will be reported.
Keywords: q6
Concerning q6, we are required to compare two names -- one of which will be passed in through the "in" channel of a particular cell and the cell will itself contain the other.
In order to reference the incoming name, I understand that some temporary variables need to be used along with pattern matching in order to get the actual name from the "NAME.NUMBER" protocol.
I am having trouble referencing the name within the current cell to compare with this... do we need to create other procedures to separate out the components of "NAME.NUMBER" and to write back to them or is there a better way?
The whole point of a protocol structure such as NAME.NUMBER is that it presents its components to you very simply. There is absolutely no need to write procedures to separate them out ... that makes no sense ... they are already separated! Look at the code in display to see how to input the components into separate variables. The language does not allow you to input them into anything else (e.g. some structure from which you have to separate things).
You don't need any clever pattern matching! You just need the equal.string function, which is documented in your q6.occ starter file (and the "libsrc" course library directory) and has been explained in your seminar groups. Some, of course, will use the compare.string function instead (for producing a sorted list of collated names and marks).
Keywords: q6 , tagged-protocol
This may sound silly but there are no questions about using "CASE", could you please tell me a bit more about it and when it's used please. Thanks.
The "CASE" construct is much like C and Java's "switch". In occam, "CASE" can be used in three places: as a "switch" on some variable/expression; in tagged protocol definitions; and in tagged protocol input. There are plenty of examples of "CASE" usage -- see the past questions, course notes, the model answer to Q4 (its "keys" process) and this occam tutorial. It would also be neater to use a "CASE" for examining the result of a "compare.string" function, rather than an "IF", in Q6.
Keywords: tagged-protocol , case , q4 , q6
I have nearly finished the first CO516 occam assesment, but I am getting couple of error messages which have bewildered me.
I am getting two types of error. The first one is "incorrect indentation". I am getting this error in reference to the two lines indicated below, but as far as I can see they are ok.
I am also getting an error which states that "a" and "b" (which refer to PROCs) are "not declared" in "PROC q1".
My code follows, I would be very grateful for any pointers.
PROC q1 (CHAN OF BYTE keyboard, screen, error) CHAN OF INT aToB: PAR a (aToB) -- a not declared b (aToB, screen) : PROC a (CHAN OF INT aToB) INT num: SEQ num := 0 WHILE TRUE SEQ IF (num = 0) num := 1000 aToB ! num -- indentation error (num <> 0) num := num - 1 aToB ! num : PROC b (CHAN OF INT aToB, CHAN OF BYTE screen) INT num: WHILE TRUE SEQ aToB ? num out.int (aToB, 10, screen) out.string ("*n", 0, screen) :
In occam, the scope of PROC declarations follows that of other (e.g. variable) declarations. Specifically that a "name" (as declared by any declaration) may not be used until it has been defined. This applies to PROC and FUNCTION definitions, DATA TYPE and PROTOCOL declarations, and ordinary variable/channel/etc declarations. The "undefined" error you get in "PROC q1" is correct -- "a" and "b" are not defined yet. To correct this, the declarations of "PROC a (...)" and "PROC b (...)" should be moved above the declaration of "PROC q1 (...)". Thus they will be defined when referenced by q1.
Unlike C and Java, the "main" procedure in occam (where the program starts) is not defined by any special name (e.g. "main" in C and Java programs). Instead the last PROC definition in the file is used, and must have the formal parameters:
PROC q1 (CHAN OF BYTE keyboard, screen, error)
in that order. The name of the PROC and names of the parameters are largely unimportant. The Linux version of KRoC allows some of these parameters to be omitted, but does place restrictions on what the parameters may be called. The standard KRoC top-level process interface (as above) will work perfectly (except for warnings about unused parameters).
The indentation error in your code arises because that line of code is incorrectly indented. It is incorrectly indented because it is incorrectly structured. Whenever you have more than one process in occam (e.g. the assignment and output), you need to explicitly state whether they are to be run in sequence or in parallel. See the other questions relating to incorrect-indentation for examples of correct usage.
Although the code for "PROC a" is largely fine, it could be improved somewhat. Firstly, the brackets around the "IF" conditions are not necessary --- brackets in expressions are only required when there is ambiguity (since occam does not have any operator precedence -- see below). "IF" conditions are just boolean expressions. Secondly, the "num <> 0" condition would probably be better as just "TRUE". This is because "num <> 0" can't possibly be false, but also because "TRUE" is more meaningful as "otherwise do this" than some expression. Finally, you have duplicated code in both branches of the "IF" (the output). It would be better to "pull" these outside the IF" (and this sort of thing applies to any programming language). I'd also query the use of "aToB" as a sensible formal parameter name in "PROC a" here. Using "aToB" strongly implies that channel connects this "A" process to some "B" process. Although this turns out to be the case here, it might not be always, and that could be misleading. Better to pick a name that has relevance for "PROC a", but is completely unrelated to any actual usage in a process network (i.e. where the process is "placed"). For example:
PROC a (CHAN OF INT out) INT num: SEQ num := 0 WHILE TRUE SEQ IF num = 0 num := 1000 TRUE num := num - 1 out ! num :
Aside: the reason occam has no precedences set for its operators is because many of us cannot remember what they are in those languages that do have them. For instance, how does the following parse in Java:
if ( a > b + 1 << 4 && 3*a + 2 == x) {...}
? Can you remember the relative precedence between all those operators?? Just what does that expression mean?!
In occam, we don't have to remember anything -- but we do have to bracket our expressions explicitly to give the bindings we want. What-you-see-is-what-you-get:
IF (a > (b + (1<<4))) AND (((3*a) + 2) = x) ... do something
Keywords: incorrect-indentation , variable-scope , q1
Hi, can you talk me through what is happening with the outputs here? Thanks very much.
string; name.length::name; mark SEQ out.string ([name FOR name.length], max.name.length, out) out.int (mark, max.name.length, out) out.string ("*c*n", 0, out)
This code-fragment is not a valid occam process -- to be meaningful it needs a bit more context (in particular the "in ? CASE" above it, since the line starting "string" is part of the tagged protocol input). As for the outputs: in sequence, this outputs the first "name.length" characters of "name", in a field-width of "max.name.length", then outputs the value held in "mark" (again in a field-width of "max.name.length") and finally outputs a carriage-return/newline pair (strictly speaking only the newline bit is required, so you could just write "out ! '*n'" instead (or "out.string ("*n", 0, out)"). See the course library documentation for a detailed description of these procedures. And the related questions about array-segments for information on the "[name FOR name.length]" expression.
Keywords: out.int , out.string , array-segments
Fred 500 Sue 200 Fred 450 Jack 200 Fred 600 Fred 900 ...
and Fred's total came to say 11000. Can this be stored sensibly in occam using INT ?
Both the maximum length of a single name and the maximum number of different names are defined as constants in the source file -- "max.name.length" and "max.diff.names" respectively. As for integers, these are 32-bit signed integers in occam (or whatever word-size your hardware happens to be, but KRoC only supports 32-bit machines at the moment). From your maths classes last year, this gives a range of around negative 2 billion to positive 2 billion -- quite enough for most purposes. If this isn't enough, occam has an INT64 type too.
Is it not possible to run q6.occ before making any changes to it ? I've just tried and it says permission denied.
That's because you need to compile "q6.occ" first. Occam sources, like sources for most other programming languages, are not directly executable.
Keywords: compiling
Haviing major problems with Q6 -- the coding for cell, what I have done is:
[snip code]
Can you please tell me what's wrong with my code?
You can't ask questions like this! You must ask questions that are much more specific. You have made no attempt to analyse your code.
Ask yourself the question: what is right with my code?. This is not a silly question! For all of us, we must be able to justify why we write every single line ... what is it supposed to be doing ... what grounds do we have for thinking that that line will do it?!!
Only once we have done this, satisfying ourselves that our code is correct ... yet finding that it doesn't work ... can we try asking what is wrong with our code.
Keywords: q6
Do we need to paste the code for the sort pump or only include the modified code for the sort pump?
The sort pump was implemented as a pipeline of cells. The collate.marks process may also be implemented as a pipeline of cells ... but it has a different number of them.
So, you may find the code implementing sort pump useful as a guide for implementing collate.marks. But why should you want to paste in the code for sort pump in your solution?
Keywords: q6
Just out of style are there any differences between the two layouts below:
PROC q6 (CHAN OF BYTE keyboard, screen, error) CHAN OF NAME.NUMBER a: PAR read.data (keyboard, a) display (a, screen)
and
PROC q6 (CHAN OF BYTE keyboard, screen, error, CHAN OF NAME.NUMBER a) PAR read.data (keyboard, a) display (a, screen)
i.e. are they both syntactically the same ?
I think you mean are they semantically the same (i.e. have the same meaning). Syntactically the same would mean they are identical. But no, these two programs express very different things. In fact, the compiler will reject the second due to invalid usage of "a".
In the second code fragment, "CHAN OF NAME.NUMBER a" is a formal parameter of "PROC q6" -- i.e. whatever calls this procedure must pass "a" as a parameter. If you draw diagrams for both these versions of "q6" you will see that there's something wrong in the second -- some channel "a" that connects "read.data" to "display" also connects to the outside (which you can't draw sensibly and which the compiler rejects). The first code fragment has the declaration of "a" entirely within the body of the process, thus it is entirely internal to that process (which you can draw easily). Diagrams (usually scribbled on a handy bit of paper) are most useful when programming in occam :-).
Keywords: variable-scope
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License. |