XML

kent logo

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.


Question 15:

Submission reference: IN2167

In the last lecture (Friday, 19 Oct), someone asked about the position of the replace gadget in the integrate process with a reset line ("Choice" slide 52): could it have been placed on either of the other two internal channels instead? Could you go over that again please?

Answer 15:

I don't think I answered that question very well, changing my mind to say: "yes, it doesn't really matter where the replace is placed in the circuit". That's true ... but only if we take a fairly relaxed view of the semantics of the device. If we take a strict view, there are low-level differences in the behaviours possible from the device, depending where that replace is placed – see below. However, for real-time control applications, such as the inertial navigation component described in "Choice" slides 53-56 (and in the "occam Approach to Transputer Engineering" paper), we can take the relaxed view – see the end of this answer.

A simpler system to consider first is the numbers.reset circuit in slide 49. If no resets are sent, this just generates: 0, 1, 2, 3, 4, 5, etc. Suppose we send the number 42 down the reset line just once. The output sequence depends, of course, on when that reset happens. Possible output sequences are:

    42, 43, 44, 45, 46, 47, ...
     0, 42, 43, 44, 45, 46, ...
     0,  1, 42, 43, 44, 45, ...
     0,  1,  2, 42, 43, 44, ...
     0,  1,  2,  3, 42, 43, ...
     0,  1,  2,  3,  4, 42, ...
     etc.

However, if the replace gadget were spliced into the d channel (between succ and prefix), there is no way the 42 could ever get in quick enough to prevent the first 0 from coming out – i.e. the first output sequence line above would not be possible.

If replace were spliced into the c channel (between delta and succ), not only could the first 0 not be replaced but the reset sequence could only start from 43. Possible output sequences are:

     0, 43, 44, 45, 46, 47, ...
     0,  1, 43, 44, 45, 46, ...
     0,  1,  2, 43, 44, 45, ...
     0,  1,  2,  3, 43, 44, ...
     0,  1,  2,  3,  4, 43, ...
     etc.

So, the actual reset number, 42, would not come out.

Compare the above with what the numbers.reset serial implementation (slide 50) can do with the same scenario (a single reset of 42). If the reset happens early enough, the 42 will overwrite the variable n on the first loop and will come out first – the 0 will not be seen. I hope it is clear that the possible output sequences are the same as the first set above – i.e. the same as those produced by the parallel implementation (slide 49), with the replace gadget between prefix and delta. So, for this scenario anyway (and actually for all), the two implementations of numbers.reset (slides 49 and 50) give rise to the same component – at least, if we are only considering the possible output sequences they produce. If the position of replace in slide 49 is changed, we have noted differences in the possible output sequences, which may or may not be significant (depending on the application in which it is used).

The "at least" qualification two sentences back needs explaining. The full semantics of a device is more than just the outputs it makes for given inputs and the timings of those inputs. We need also to know about the patterns of all events (i.e. input and output communications and, later, barrier synchronisations) in which it can engage. For instance, how may the inputs events interleave with output events? In many circumstances, we need this information to avoid deadlock.

When we consider possible interleavings for the numbers.reset implementations of slides 49 and 50, some differences do emerge. In the serial implementation (slide 50), here is the sequence of events when a single reset event occurs:

                    ...
                    out ! x
                    out ! x + 1
                    out ! x + 2
        reset ? y
                    out ! y
                    out ! y + 1
                    out ! y + 2
                    ...

where time is flowing downwards and x and y represent generic values. Note that the output of the reset value is the next event following the reset input. No other interleavings of input and output events are possible.

Now, consider the parallel implementation (slide 49). The above sequence is certainly a possibility but so, also, is the following:

                    ...
                    out ! x
                    out ! x + 1
                    out ! x + 2
        reset ? y
	            out ! x + 3
                    out ! y
                    out ! y + 1
                    out ! y + 2
                    ...

It all depends on where the previously cycling number is in the feedback circuit when the reset is taken by replace. If it is in succ or prefix, we will get the first pattern. If it is in delta, we will get the second.

So the parallel and serial implementations of number.reset are different. The serial form is more constrained in the way it syncrhonises with its environment (i.e. the other processes in the network in which it is embedded). Everything it does can also be done by the parallel version, but the parallel version may choose to do things differently.

Note: when considering the semantics of a process, it is only its impact on its environment that is relevant. That is why, when thinking about the patterns of events in which a process can engage, it is only those that interact with its environment (e.g. external input and output channels) that are important. Hence, in the above sequence (and the ones that follow), we only include events involving the channels from the parameter list – not the internal ones.

Now, let's get back to the integrate process, first comparing the serial and parallel versions of the original process – the one without any reset channel. Consider the serial version (slide 57). Its synchronisation pattern is tightly constrained: a strictly alternating sequence of inputs and outputs:

                    ...
                    out ! r                   -- running total, so far
        in ? x
                    out ! r + x               -- running total, so far
        in ? y
                    out ! r + x + y           -- running total, so far
        in ? z
                    out ! r + x + y + z       -- running total, so far
                    ...

This serial version "buffers" one item of the flow of numbers from its input channel to its output (i.e. in any state, the number of inputs it has taken is either the same as its number of outputs or one more).

As noted in "Basics" slide 94, the parallel version "buffers" two items of the flow of numbers from its input to output (i.e. in any state, the number of inputs it has taken is either the same as its number of outputs or one more or two more). This allows it greater flexibility in the way it synchronises. The above pattern can certainly happen, but so can:

                    ...
                    out ! r                   -- #in? = #out!
        in ? x                                -- #in? = #out! + 1
        in ? y                                -- #in? = #out! + 2
                    out ! r + x               -- #in? = #out! + 1
        in ? z                                -- #in? = #out! + 2
                    out ! r + x + y           -- #in? = #out! + 1
                    out ! r + x + y + z       -- #in? = #out!
                    ...

where "#in?" means the number of inputs so far and "#out!" means the number of outputs so far. Other patterns may occur, so long as:

    0 <= (#in? - #out!) <= 2

Note that, viewed separately, the output sequence for any given input sequence is the same for both the serial and parallel versions. However, the difference in buffering capacities may be significant for deadlock analysis. The more constrained pattern of synchronisation forced by the serial version increases the potential for deadlock in a poorly designed application that uses it.

Now consider the serial and parallel versions of integrate.reset ("Choice" slides 51 and 52). The serial version still buffers only one running total (either the most recently computed value or one that's just been reset). Its synchronisation pattern is also tightly constrained: a strictly alternating sequence of either an input or reset event, followed by an output event. For example:

                    ...
                    out ! r                   -- running total, so far
        in ? x
                    out ! r + x               -- running total, so far
        in ? y
                    out ! r + x + y           -- running total, so far
        reset ? a
                    out ! a                   -- the reset running total
        in ? z
                    out ! a + z               -- running total, so far
                    ...

The parallel version (slide 52) can buffer up to three running totals: one in plus (the most recent), one in replace (either the second most recent or a reset value) and one in delta (the oldest). This gives much greater flexibility to the patterns of synchronisation possible. Again, the above pattern is possible. But also:

                    ...
                    out ! r                   -- running total, so far
        in ? x                                -- 'r+x' moves through 'replace' to 'delta'
        in ? y                                -- 'y' only gets into 'plus' (which needs its other input)
        reset ? a                             -- 'a' gets into 'replace'
                    out ! r + x               -- running total, so far
		                              -- 'r+x' fed back through 'prefix' to 'plus'
					      -- 'r+x+y' computed, moves to 'replace' and is discarded
					      -- 'a' moves into 'delta'
                    out ! a                   -- the reset running total
        in ? z
                    out ! a + z               -- running total, so far
                    ...

and many others. Notice that in the above sequence, one of the running sums of input values (r+x+y) never emerged. Whether missing this value is significant depends on the application.

Now, consider what happens if the replace gadget in the parallel implementation (slide 52) were positioned elsewhere. For one thing, the buffering capacity between the in and out channels drops back to two. If replace were spliced into the channel between prefix and plus, the reset value would never emerge as itself – it would always first have been added to the next input value. For example:

                    ...
                    out ! r                   -- running total, so far
        in ? x                                -- 'r+x' moves to 'delta'
        in ? y                                -- 'y' only gets into 'plus' (which needs its other input)
        reset ? a                             -- 'a' gets into 'replace' and moves on to 'plus'
	                                      -- 'a+y' computed in 'plus', cannot move on yet
                    out ! r + x               -- running total, so far
		                              -- 'r+x' fed back through 'prefix' to 'replace', which discards it.
					      -- 'a+y' moves to 'delta'
                    out ! a + y               -- the reset running total (with added 'y')
        in ? z
                    out ! a + y + z           -- running total, so far
                    ...

In the previous example, the contribution of 'y' was never seen in the running sum outputs. This time it is, but added to the reset value (which is not seen directly).

If replace were spliced into the channel between delta and prefix, the reset value would never emerge as itself – it would always first have been added to the next input value (as for the previous version). The difference is at start-up – there is no way a reset could happen fast enough to prevent the first output from always being the first input added to the initial 0 from prefix (i.e. the first output is always the first input).

  Brief Note on Formal Semantics

A sequence of events (channel communications and, later, barrier synchronisations) in which a process can engage is called a trace.

The last 7 sequences above show extracts from traces of the processes being considered. For clarity, we've listed them in two columns: one for input and one for output. For traces, consider them listed in one column, keeping the ordering.

CSP (Communicating Sequential Processes), the formal algebra that underlies occam-pi, defines three semantic models with increasing capabilities: traces, failures and divergences. The simplest is the traces model, which enables verification of safety properties (e.g. that a process will not do something bad). The other two concern liveness properties (e.g. that a process will actually do something): failures enable deadlock analysis and divergences address livelock.

In the traces model, the semantics of a process is just defined by: the set of all its possible traces. Two processes are equivalent if their traces are the same set. A process, P, is a refinement of a process, Q, if the traces of P are a subset of the traces of Q. This is where safety analysis comes in: if a process Q is known to have safe behaviour and we implement a process P and prove that it refines Q, then we know that P also must be safe (because every trace that P can do, Q can do and Q only does safe things). In such a scenario, Q is usually described as a specification for P.

  Summary

The position of the replace component in the parallel circuits of numbers.reset (slide 49) and integrate.reset (slide 52) does impact on their formal semantics.

The serial numbers.reset (slide 50) is a traces refinement of the parallel implementation in slide 49. The serial integrate.reset (slide 51) is a traces refinement of the parallel implementation in slide 52.

If, however, the replace component is repositioned somewhere else in the circuits, there is no formal relationship between the serial and those parallel versions. Whether the differences (see earlier) matter depends on the applications to which they are put.

For the inertial navigation component (slides 53-56), they don't matter. All the versions of integrate.reset (serial or any of the three parallel implementations considered above) deliver running sums and allow resets at any time. The precise interleaving of inputs, resets and outputs doesn't matter – the important matter is the accuracy of the input sample values and the accuracy of their sampling times (which must be evenly spaced). If some running sum is discarded when a reset happens, it doesn't matter: that value was suspect anyway, which is why integrate.reset was being reset. If the reset value does not get output itself, it doesn't matter: the value that comes out is the reset value plus the latest input, which is more up-to-date than the reset value alone. Finally, if we can't reset before the first number appears after integrate.reset is switched on, who cares?

Keywords: q4 , csp , formal-semantics , reset


Question 14:

Submission reference: IN2166

I have had a little bit of trouble implementing the flip behavior to pairs expressed in Q4. I understand what it is meant to do but struggling at finding a way of implementing it that isn't long and overly complicated. I wanted to avoid a modified plus process inside pairs2 and wanted to introduce the new component to do the job as this makes the most logical sense in terms of the rest of the program. It also suggests that a suitable process has been described and from looking through those available I felt that the closest match would be the (Ed: rest of sentence deleted as it gives too much away).

I simplified my (Ed: name deleted) process slightly and with my code currently looking like this I get no output. Confused at what's going on! I've tried running through process diagrams on paper and still stuck ...

    PROC pairs2 (CHAN INT in?, flip?, out!)
      CHAN INT a, b, c, d, flip.decision:
      INT any:
      ...  (Ed: variable declaration hidden, used in flip response below)
      WHILE TRUE
        SEQ
          PRI ALT
            flip ? any
              ...  (Ed: response to flip guard hidden)
          PAR
            delta(in?, a!, c!)
            tail(a?, b!)
            ...  (Ed: process instance hidden)
            plus(b?, d?, out!)
    :

Answer 14:

Your pairs2 has two errors.

The biggest one is that you start a PAR network of processes – all of which run forever – in the body of a WHILE loop. The first time that loop is entered, once it reaches that PAR all the components of that PAR start up and never finish. So the loop never loops, only executing the PRI ALT (at the start of its body) just the once. That's probably not what you meant to happen.

The second error is that your PRI ALT only has one guard. That means just wait until that guard is ready. The code may as well have been written:

    PROC pairs2 (CHAN INT in?, flip?, out!)
      CHAN INT a, b, c, d, flip.decision:
      INT any:
      ...  (Ed: variable declaration hidden, used in flip response below)
      WHILE TRUE
        SEQ
	  flip ? any
	  ...  (Ed: response to flip guard hidden)
          PAR
	    delta(in?, a!, c!)
	    tail(a?, b!)
	    ...  (Ed: process instance hidden)
	    plus(b?, d?, out!)
    :

Again, that may not be what you wanted.

These two misunderstandings need correcting. Hopefully, what needs to be done then becomes much clearer. Your modified (Ed: name deleted) process looks good.

Keywords: q4

Referrers: Question 25 (2012)


Question 13:

Submission reference: IN2165

In question 4, we have to deal with an array of channels. I was wondering what the syntax is for doing so in regards to the parameter that goes in the call to print.streams?

Answer 13:

See "Basics" slide 101. That instance of print.streams takes the input-ends of an array of 4 channels. In Q4, print.streams needs the input-ends of an array of 3 channels. The syntax for this is the same – the number of channels in the array doesn't matter.

Keywords: q4


Question 12:

Submission reference: IN2164

I'm currently working on Q4 and while my freeze/error-inducing process in Q3 works exactly as specified/intended, I can't seem to get the control working in Q4 for reasons I don't understand.

Here is the code for my monitor process, which is only trying to enable my numbers2 process to be reset:

    PROC monitor (CHAN BYTE in?, CHAN INT numbers!)
      ...  (editor) code omitted
    :

It should do, as far as I can see, run round the loop doing nothing until an 'n' is pressed – when it should output a 0 to the numbers! channel. The problem is that when I try and insert it in to the network it causes all output to stop from the numbers2 process, defined as such:

    PROC numbers2 (CHAN INT out!, reset?)
      ...  (editor) code omitted
    :

The process will also not respond to any keyboard input.

If I remove my monitor process from the network, the numbers2 process functions fine ... so it certainly feels like it should be my monitor process that's causing the issues. Am I missing something very obvious?

Answer 12:

Your monitor is not running "round the loop doing nothing until an 'n' is pressed". It is busy polling the keyboard channel! It uses a PRI ALT governing that channel against a SKIP guard. If no key press has been made, the keyboard input guard is not ready and the PRI ALT takes the SKIP guard. The latter was defending only a SKIP (i.e. do nothing) process, so execution loops around back to the PRI ALT.

Your monitor process is continually active, racing round this polling loop over 100,000 times per second on the Transterpreter (or more than 100,000,000 times per second with the KRoC runtime), consuming every processor cycle available. The other processes can make little headway against this torrent of (useless) activity – the system is effectively livelocked. Take a look at the processor loading (e.g. on the Windows Task Manager) when this is running – one of the cores will be almost at 100%, with the others mostly idle (the Transterpreter does not multicore schedule). If you're using KRoC (which does multicore schedule), the system will work ... but one of the cores will be at 100% loading and getting rather hot. All that work is quite unnecessary and unacceptable for a real-time system (with hard deadlines to meet) or an embedded system (with limited battery life).

This is a classic mistake – see the warning at the bottom of "Choice" slide 30.

Solution: save the planet and don't poll for keyboard input! Just wait for one to arrive (i.e. all you need is the input line). Waiting for a channel input costs nothing in processor loading and the waiting process jumps to life when something arrives.

Keywords: q4


Question 11:

Submission reference: IN2163

How exactly is keyboard input performed in occam-pi?

It is my understanding that keyboards input a BYTE character, but how does the key press register in the monitor process?

Answer 11:

A physical keyboard outputs ASCII codes corresponding to keys that are pressed on it. On a PC/laptop, the operating system grabs these codes and buffers them for delivery to the application in the window on which the PC/laptop user has current focus.

If this application is the Transterpreter runtime system (because you have focus on the "occplug") or the KRoC runtime system (because you have focus on the terminal window in which you started the occam-pi system), that runtime system takes the ASCII code (which is an occam-pi BYTE) from the operating system and sends it down the CHAN BYTE input channel in the parameter list of the last PROC declaration in your main compilation unit.

We have not told you about building separately compiled units (libraries), so you only have main ones – e.g. q4.occ. All your starter files have as their last PROC declaration something like:

    PROC q4 (CHAN BYTE keyboard?, CHAN BYTE screen!, CHAN BYTE error!)

So, to get keyboard input from a user interacting with an occam-pi system running on a PC/laptop, your code simply inputs from this keyboard? parameter channel. Your monitor process needs keyboard input. To enable this, your q4 process (see above) must invoke monitor, passing its keyboard? channel as one of the arguments. Of course, q4 will be invoking several other processes in parallel with monitor.

Keywords: keyboard


Question 10:

Submission reference: IN2162

Question 4 for the assessment states: "New processes, numbers2 and integrate2, must be made that accept the new reset signals and respond appropriately. Maintain the same style of implementation as before. Don't modify any internal processes – but insert an extra one somewhere to do the job."

It also states earlier that numbers, integrate and delta are accessible from the course.module included. If we have to redefine numbers2 and integrate2 based on the ones included, is there anywhere on raptor etc. where we can look them up and copy the code from course.module into our q4.occ file and then make changes to them?

Answer 10:

Sorry, I thought the source files for course.module were in the Transterpreter release, which most have downloaded. They certainly are in the Kroc release, which is worth getting if you have Linux or a Mac (look for modules/course/libsrc).

Of course, you must have these source files and I have copied them to raptor (and swallow) at:

    \courses\co538\course-module\             (read the README.txt)

You don't really need these files to copy numbers, integrate etc. to your q4.occ starter file and then edit into the extended versions needed for the exercise. They are only 7 lines of code each and, anyway, can be copy-pasted from "Choice" slide 88.

You need these files for curiosity browsing and studying. Many of the processes have implementations that are really complex and scary (e.g. course.REAL32TOSTRING in float_io.occ, which converts a 32-bit floating-point real into ASCII text – a task that just is complex and scary). Ignore those! But there are a lot that will reward reading. Be curious. We are always here to answer your questions.

Keywords: q4


Question 9:

Submission reference: IN2161

I am trying to start working on question 3 and have read all of the lecture slides about deterministic and non-deterministic choice from choice slides 1-29 but am still really confused on where to start ...

I think that I will need a BYTE variable that is set permanently to 'f' so that I can use this for comparing the keyboard? with to know when an 'f' is pushed? This confused me because I don't know how I would properly compare the BYTE value from keyboard? with the fixed VAL BYTE f I declared... Would it be the same as comparing numbers?

I then think that I will need a WHILE TRUE loop to run forever and then directly inside that I will need a PRI ALT to decide what to do. I don't know where to start with what else goes inside the PRI ALT (I know the structure of the the PRI ALT from the lecture slides) but how do I start demo running immediately, pause it when an 'f' is inputted (possibly an input guard?), actually get the demo process to pause and then resume when another character is inputted on keyboard?

I've flicked through the rest of the choice slides and couldn't find any other examples where similar code could be found to base my answer to this problem.

Answer 9:

We don't really need to declare a named VAL BYTE holding the constant 'f' – we can just use the literal 'f' in your code. Having said that, it's usually a good idea to give names for literal constants, so let's do it:

    VAL BYTE freeze.char IS 'f':

Then use freeze.char henceforth in our code. Now, should whoever is specifying the system we are programming change their minds and decide that 'F' would be more cool (than 'f'), all we have to do is change the above line. Otherwise, we have to hunt throughout our code and change 'f' to 'F' wherever we find it and hope we don't miss any.

How do we compare freeze.char with whatever value is received from the keyboard? channel? Well, if ch is the BYTE variable into which data was received from keyboard?, just test the condition:

    ch = freeze.char                  -- or: ch = 'f'

within an IF process.

You are correct: in the control process, you will need a WHILE TRUE and, in its loop body, a PRI ALT. You must decide for what guards the latter needs to be waiting and what the responses must be when/if it gets them. To do this, you must think on what control has to do: normally forward anything coming in from demo to the screen! ... unless a freeze.char arrives from keyboard? (in which case, it must wait for another BYTEany other BYTE – from keyboard?). Note: control does nothing to "get the demo process to pause and then resume" other than refusing its output for a while – demo is unchanged and unaware of its connection to control or the impact that has (which is irrelevant to its semantics). Note: programming this behaviour into your PRI ALT guarded processes of control takes around 10 lines (including local variable declarations for each guarded process). Programming the full behaviour of control (responding to 5 special characters from the keyboard) takes a few, but not many, more.

Starting the demo process running is not the responsibility of control (which may assume that demo, or something, has been started and will be sending BYTEs to one of its input channels – its other input channel receiving BYTEs only occasionally from the keyboard).

Starting demo and control running and connecting them up correctly is the responsibility of the q3 process, as shown in the diagram at the bottom of page 1 of the "more.exercises" sheet. The q3 process is declared as the last process in your starter file.

Keywords: q3


Question 8:

Submission reference: IN2160

How do I change the path of skroc.exe in the transterpreter?

Answer 8:

We suspect you are using an old version of the Transterpreter – the new ones do not use skroc.exe.

On public room PCs, make sure you are using the one whose link icon has been copied from raptor at:

    \courses\co538\Transterpreter.lnk

Please make sure your are not using the Transterpreter icon set up for the Lego Mindstorms RCX (used in the Freshers' week workshop).

On your own machine, make sure you are using the latest version from transterpreter.org (20110201.1855).

If you are using the correct version and your problem still persists, please contact me or Fred Barnes or your class supervisor and make an appointment. Thanks.

Keywords: transterpreter


Question 7:

Submission reference: IN2159

In Question 5 (2012), we have to write the process differentiate. I've read the anonymous Q&A and you said that if we have to call differentiate only with an input channel = 0, 1, 2, 3 ,4.. etc, the output should be 0, 1, 1, 1, 1.. etc. But my output channel turn out to have 0, 1, 1, 2, 2, 3, 3, 4.. etc. I can't seem to find the problem and fix it.

Is this caused by my minus process (where I simply changed PLUS to MINUS within the code body), or my differentiate process (where I have called delta, prefix and minus)?

Answer 7:

Let's first get the language correct. If the stream of integers supplied to a differentiate process is 0, 1, 2, 3 ,4, etc., then its output stream should be 0, 1, 1, 1, 1, etc. For the reason why, see the last paragraph of the answer given in Question 5 (2012).

The reason why your differentiate is producing a different stream of integers is that your circuit for it is incorrect. Your minus process, modified as you describe, is certainly one of the components needed for a correct circuit – as stated in the question. But I suspect that you have just reused the integrate circuit, substituting your minus for its plus. Why should that work?

You need to work out, first, what is the transformation differentiate has to make on its input stream. Its definition implies that if the input stream is:

    a, a+b, a+b+c, a+b+c+d, a+b+c+d+e, ...

then its output stream should be:

    a, b, c, d, e, ...

In which case, if the input stream is:

    p, q, r, s, t, ...

What should its output stream be? Once you have written that list of formulae, you will know what has to be done and the circuit should become reasonably obvious, :).

Keywords: q2


Question 6:

Submission reference: IN2158

Relating to exercise 1 of the occam exercises (preliminary) worksheet.

I've managed to get my program outputting all the numbers fine but can't get it to implement a filter process. Currently my code looks like this:

    PROC filter (CHAN INT in?, out!)
      ...  declare some variables (some are given INITIAL values)
      SEQ
        ...  two primitive processes (one input and one assignment)
	IF
          v > 0
	    out ! n
          TRUE
	    out ! v
    :

    ...  [snip rest of code]

This runs and outputs "5" and then crashes (presumably deadlocked?). I understand why it is outputting 5 — because in the IF loop of filter it is doing ..[snip text].., but why does it deadlock after that on the next iteration?

Any Help Appreciated - I know my code's messy but I've been pulling bits in and out for so long now that I just want to get it working then condense it later. Thank you.

Answer 6:

I think you have a slight misunderstanding about how an IF process works in occam-pi.

You mention an "IF loop", but the IF has no loop behaviour — it only happens once. Thus, your "filter" process does its thing once (which produces the value '5') and then terminates — which means it disappears from the network. The rest of the system cannot now continue, because the processes before and after (where filter used to be) will be stuck trying to communicate on channels whose other ends are dangling (i.e. connected to no process). Processes trying to communicate with those stuck processes also become stuck and, very soon for this system, all processes are stuck and we have deadlock.

For this (and other) exercises, we're happy for things to run continuously — any process which needs this behaviour must have a loop in somewhere, as your S0 and S1 processes presumably do. [Aside: you can get the same looping behaviour with recursion, but we haven't told you how to do that in occam-pi yet!].

Final thought: "I know my code's messy ... I just want to get it working then condense it later." This always leads to tears. Messy code is very very very much harder to get working than clean neat code. Always always write clean code, neatly spaced and indented. If you write code that doesn't work as soon as it compiles (and this should not happen), look at it and ask yourself: "Why should it work?" — do not ask yourself: "Why doesn't it work?". Looking at clean neat code gives yourself a chance to understand what it is that your code is really doing, compared with what you want it to do. Looking at messy code hugely reduces that chance.

Keywords: q1


Question 5:

Submission reference: IN2156

In q2, we have to write the process differentiate. Does this process have to be dependent on the integrate process?

Basically, if we have to call differentiate only, with an input channel "in" = 0, 1, 2, 3, 4....., is the output channel "out" = 0, -1, -3, -6, 10, ... ?

Answer 5:

The question says that pipelining a differentiate process following an integrate process results in no change to the stream of numbers flowing through them – i.e. the output stream is the same as the input stream. Now, integrate emits running sums of the numbers from its input stream. Therefore, differentiate must do something with such running sums to retrieve the original stream. Working this out, implementing it in the required style (i.e. one similar to the parallel implementation of integrate, "Basics" slide 9) and, then, demonstrating its correct working in the test network given in the diagram for process q2 is what you are asked to do.

Of course, differentiate can be used in any network – it does not have to be pipelined with an integrate, nor need any integrate be present! However, if the input stream of numbers to differentiate were:

    0, 1, 2, 3, 4, ...

the output stream from differentiate would need to be:

    0, 1, 1, 1, 1, ...

To understand why, imagine this second stream as the input to an integrate process: the output (running sums) would be an increasing sequence of numbers starting from 0 (the first stream). So, pushing that second stream though integrate and then differentiate gets it back again – differentiate has done its job correctly!

Keywords: q2

Referrers: Question 7 (2012) , Question 7 (2012)


Question 4:

Submission reference: IN2155

From Exercise One:

    out.string ("*c*n", 0, out!) 

What do the "*c*n" bytes mean please? The documentation says this is the string to be returned via out?

Answer 4:

A string literal in occam is almost the same as in Java: text enclosed between double-quotes ("). One difference is the expression of special characters, such as carriage-return and new-line. In Java, these are introduced by the escape-character backstroke (\). In occam, the escape-character is an asterisk (*). So, "*c*n" is a string containing two characters: carriage-return followed by new-line. By the way, to get an asterisk into an occam string, just precede it with the escape-character – for example, "****" is a string containing two characters: an asterisk followed by an asterisk. Here is a list of the common special characters for occam strings:

    *c (carriage-return)
    *n (new-line)
    *t (tab)
    ** (asterisk)
    *" (double-quotes)
    *' (single-quote)

Note: the documentation for out.string does not say that anything is a "string to be returned via out". out.string is not a function that returns anything. out.string is a process that runs for a short while, outputting the string (given in its first parameter) down the channel (given in its third parameter), right-adjusted (i.e. padded with spaces) in the field width (given in its second parameter). The field width is only relevant if it is greater than the number of characters in the string – so 0 is always ignored. The output goes one BYTE at a time, in separate communications.

Documentation to the occam-pi libraries is linked from the "Practical Resources" box on the Moodle page for this course. Here is a shortcut to the course module, which contains the out.string process. This is the library made available to your code by the line:

    #INCLUDE "course.module"

Keywords: q1 , out.string


Question 3:

Submission reference: IN2154

In q1, a diagram shows that S0 and S1 must be input into alternate. I can't seem to figure out how to turn S0 and S1 into inputs, or how to implement them into the process alternate. Could you possibly give an example of one PROC being fed into the input of another?

Answer 3:

First, let's correct the language in your question. This is important because asking the right question shows the way to an answer. Asking the wrong question shows a misunderstanding that needs to be corrected – otherwise, our answer will not be understood.

You write: "In q1, a diagram shows that S0 and S1 must be input into alternate". But S0, S1 and alternate are all processes. And alternate has (two) input channels that deliver integers. Therefore, it makes no sense for a process (e.g. S0) to be input into alternate – only integers can be input into alternate.

You write: "I can't seem to figure out how to turn S0 and S1 into inputs, or how to implement them into the process alternate". But turning processes (e.g. S0 and S1) into inputs makes no sense – neither does implementing them into another process (e.g. alternate).

A correct description is as follows: S0 and S1 are processes with output channels supplying integers; the diagram shows instances of S0, S1 and alternate, where channels connect the outputs from S0 and S1 to the inputs of alternate.

To implement this diagram as the code body for the q1 process, compare with the system and coding in "Basics" slide 9. This shows a process, integrate, with external channels in? and out!. Internally, there are three sub-components (process instances): plus, delta and prefix. These sub-components are connected to each other by three internals channels (a, b and c) and to the external channels (in? and out!). Study the coding carefully.

The diagram in your question is the second diagram on page 2 of the assessment sheet for q1. This shows a process, q1, with external channels keyboard?, screen! and error!. Internally, there are four sub-components (process instances): S0, S1, alternate and print.stream. These sub-components are connected to each other by three internals channels (for which names need to be invented) and to just one of the external channels (screen!). Use the coding of integrate (from "Basics" slide 9) as a template for implementing this version of q1.

Note: the simpler version of q1 in the diagram on page 1 of this question should, of course, be done first!

Note: leaving external channels unconnected ("dangling") is generally not a good idea and the compiler will complain about (though allow) it. Unfortunately, the Windows host version of the Transterpreter requires exactly those three channels as the interface for the main occam process in your program (always the last PROC in your file). The q1 process only needs the screen! channel, but has to have all three.

Your last question was: "Could you possibly give an example of one PROC being fed into the input of another?" You meant: "Could you possibly give an example of the output from one PROC being fed into the input of another?" See "Basics" slide 20 (and 21-25).

Keywords: q1


Question 2:

Submission reference: IN2153

The reading list is about OCCAM 2.1. Is this not very different to occam-pi?

Answer 2:

occam-2.1 is an intact subset of occam-pi (i.e. the occam-pi compiler will compile occam-2.1 programs correctly). Most of the occam-pi teaching in this module is focussed on the occam-2.1 subset, so books on occam-2.1 remain relevant.

However, there are two low-level differences in the syntax occam-pi provides for its occam-2.1 subset.

First, declaring a channel in occam-2.1 requires two key words – for example:

    CHAN OF INT c:

In occam-pi, the "OF" has been dropped – for example:

    CHAN INT c:

Secondly, CHANnel parameters in occam-2.1 do not require the post-fix qualifier (? or !) specifying the direction of use (input or output) of the channel. For example:

    PROC integrate (CHAN OF INT in, out)
      ...  code body of this process
    :

The occam-2.1 compiler worked out the direction of use as it compiled the code body and raised an error if the code used any channel parameter in more than one direction. If the first use of a channel was the wrong way around (e.g. for output rather than input), this would be accepted and subsequent correct usages would be flagged as errors.

In occam-pi, a PROC declaration must specify the direction of use for all its parameter channels. For example:

    PROC integrate (CHAN INT in?, out!)         -- "Basics" slide 5
      ...  code body of this process
    :

Now, if the code anywhere uses a channel parameter in the wrong direction, that usage is correctly flagged as an error. Correct usages are always accepted.

Further on this, code for building a PARallel network of processes requires plugging connecting-ends of channels into the processes that need them. In occam-pi, the channel-end is specified by post-fixing the channel name with the direction of its use (? or !) by the process into which it is being plugged. For example:

    PROC integrate (CHAN INT in?, out!)         -- "Basics" slide 9
      CHAN INT a, b, c:
      PAR
        plus (in?, c?, a!)
        delta (a?, out!, b!)
        prefix (0, b?, c!)
    :

Simple inspection of this code shows consistency and completeness. Each channel-end parameter is plugged in to just one sub-component. The second line declares three channels, each with two ends. Each end is plugged in to just one component. No channel-end (parameter or internal) is left unused and dangling.

In occam-2.1, there are no post-fix channel direction specifiers – for example:

    PROC integrate (CHAN OF INT in, out)
      CHAN OF INT a, b, c:
      PAR
        plus (in, c, a)
        delta (a, out, b)
        prefix (0, b, c)
    :

This code is less clear. To work out the direction of message flow, we need to know something of the semantics of the three sub-components (in which direction do they use their channels?). In the previous occam-pi code, this information is transparent.

Final Note: as said at the start of this answer, the occam-pi compiler still compiles occam-2.1 code. Therefore, your code will compile if you omit channel direction specifiers (? or !) in places where we teach you they are needed: formal channel-end parameters (in PROC declarations) and actual channel-end arguments (in PROC instances). However, your assessments will lose marks if these direction specifiers are omitted in your code.

Final Final Note: apart from the above (minor) syntactic differences, occam-pi is the same as occam-2.1 for (almost) all the material covered in the slides in the files: "Basics", "Replicators", "Choice", "Applying" and "Protocol". occam-2.1 does not have STEP sizes in replicators (see "Replicators" slides 96-102, when we get there!). The materials in the "Shared-etc" and "Mobiles" slides are all new to occam-pi.

Final Final Final Note: all necessary materials for engaging in this course successfully will be provided through links on the Moodle page. Checking out the books in the reading list (e.g. from the library) will give other views and insights – but the assessments and exams will presume this has not happened!

Keywords: books , occam-2.1 , occam-pi


Question 1:

Submission reference: IN1477

How many swallows does it take to change a parallel process?

Answer 1:

Twelfty.

Valid CSS!

Valid XHTML 1.0!

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
Last modified Mon May 20 13:50:21 2013
This document is maintained by Fred Barnes, to whom any comments and corrections should be addressed.