Skip to main content

Communicating Operators - The Heart of PM


 
Communicating operators lie at the heart of the PM parallelisation model. They are designed to provide a compromise between the direct access to global data structures (particularly arrays) offered by approaches such as Partitioned Global Address Space and the straightforward synchronisation provided by Communicating Sequential Processes. In common with most data-parallel languages, PM contains a parallel version of the for statement which runs all invocations of its enclosed statement list concurrently:

      for element1 in array1, element2 in array2 do  
           element2=process_element(element1)  
      endfor  

Most real models will require some interaction between adjacent array elements. In PM this is achieved by using either a local or a global communicating operator. The global operator @v returns an array whose elements comprise the values of loop-local variable v in each invocation of the enclosing for statement. The neighbourhood operator v@{nbd} provides a more localised array view of v, containing only the local value and those of its neighbours, as defined by the array domain topology.

A very simple example is the implementation of a mean filter over a rectangular array. A 3x3 mean filter simply replaces each element of a grid by the mean of itself and its eight immediate neighbours. In PM this could be coded:

  for element in array do  
    element = sum(element@{-1..1,-1..1})/count(element@{-1..1,-1..1})  
  endfor  

Here sum and count are straightforward array operations. It is necessary to use count rather than simply dividing by nine since off-edge array elements are returned by @ as missing values. The communicating operators both request and supply values for the given variable, thus providing logical synchronisation between concurrent invocations.

There are also reduction versions of the communicating operators, which apply an operation globally or over a neighbourhood, rather than returning an array. The above example may be more efficiently coded as:


  for element in array do  
    element = sum::element@{-1..1,-1..1}/count::element@{-1..1,-1..1}  
  endfor  


The :: @ pair is the reduction version of the neighbourhood @ operator. The global reduction operator just uses ::. To normalise an array so that the sum of its elements sum to one:

 for element in array do  
  element = element/sum::element  
 endfor  


There is more to communicating operators, including their interaction with nested conditional/looping statements and their packaging into ‘loop procedures’. I will come back to this topic in later posts.

 

Comments

Popular posts from this blog

Compile time, run time, coffee time

[ Please note that in the following discussion I will be using PM 0.5 notation, which is slightly different to PM 0.4 and also in some flux as PM 0.5 is still in development. ]   Many programming languages (and most newly developed ones) include some form of compile-time programming, ranging from simple preprocessors ( #define , #if in C) to fully blown macro systems capable of re-writing the abstract syntax tree during compilation (Rust, Julia, etc .). In line with its philosophy of keeping things as simple as possible, but not simpler, PM takes a middle road with compile-time programming supported primarily through the type system. There is nothing too radical here – this is not an area where the language aims to break new ground.  The PM approach centres around the use of compile-time types. Many languages use special types to denote literal values and PM follows this trend. Literal integers, reals, strings and Booleans each have their own types: literal(int) , litera...

All change .. not quite

With the recent release of PM 0.4 and the positive reception to my PM presentation at CIUK2023 , it seems like a good time to bring back the PM blog after a long hiatus. Another good reason for its resurrection is that I feel that I now have built the basic semantics of the language into something like a coherent whole, giving me something concrete to write about. There have been a few major changes to the language since my last blog entry. The main syntactic change has been the shift from keyword-delimited control statements to curly-brackets. This is not a statement on my part as to the merits of the two approaches, I am generally agnostic in this debate which can border on the religious. It was simply that with the way that the language was developing, the keyword approach was getting cumbersome – frequently used constructs were taking up far to much space and impeding readability. PM now uses curly brackets to terminate statements and semicolons to separate (and optionally terminat...

‘Tis the season

… to give an end-of-year update of what is happening with the PM language. It is a long time now since I wrote a PM blog. However, behind the scenes there has been a lot of work done on the guts of the compiler with new inference and optimisation passes added and others taken apart, polished, and put back together again. New language features have also been implemented, including methods, improved object lifetime management and, most importantly, a radically simplified approach to coding stencils. The handling of stencils was one aspect of PM-0.4 with which I was least happy. Since these are a key requirement for nearly all numerical modelling, I have long been looking for a way to make their coding as straightforward as possible. However, this has been one of the greatest challenges in terms of implementation, since the amount of code restructuring need to make a stencil operate efficiently (separating out halo computation, overlapping computation and halo exchange, tiling and the in...