Felix supports a radical new programming paradigm -- programming
with circuits. In this game, the players are wires and chips:
we have a powerful concept of modularity and components.

Below is a 'realistic' example. Two things need to be noted.

The first is that the technique can be difficult to use.
I got it wrong first time.. but no error, the circuit just
didn't do anything. This is what you expect when you connect
the wrong pins of some chips together of course.

The second thing to note is that we need more sugar!
But we need examples to see what to provide.

The chip based example is slighly more abstract and
modular than the traditional code, however this is just
an accident: standard functional techniques like currying
could have provided more abstraction.

The key difference is in the control protocol. The functional
code 'just works' but it is impossible to control invert.
The fibrated code (chips and wires model) is already control
neutral. The components *cooperate*: none is a 'subroutine'
called by another 'master'. This control neutrality is
a *mandatory* property of a component, and this discredits
subroutines, and in particular it destroys any notion that
basic functional programming is any good. It explains why
functional code rapidly turns into switch spaghetti.

Advanced techniques like continuation passing don't have
this problem .. but then that is just what Felix is doing!

I'll make more comments in subsequent emails in this thread.


The code here provides a procedure for integrating an
arbitrary function based on Newton's method. This
works by viewing the graph of the function as a bar graph,
and adding up the area of the bars.

We then try to guess how many bars we need to get
an accurate integral by increasing the number until
the difference between two successive approximation
is small enough. This procedure does not work, as you 
will see by examining the output, but that is beside
the point :)

////////////////////////////////////////////////////////////
#import <flx.flxh>

comment """
  integrate f from a to b by drawing a bar chart with n
  bars and adding the areas of the bars up: Newton method
""";

fun newton (
  f: double -> double, 
  a:double, b: double, 
  n:int
  when a <= b and n>0
): double =
{
  width := b - a;
  barwidth := width / double n;
  var sum = 0.0;
  var i:int; forall i in 0 upto n-1 do
    x := a + width * (double i + 0.5)/double n;
    height := f x;
    sum += barwidth * height;
  done;
  return sum;
}

proc test1
{
  comment """
    Since integral (sin x) = -cos x, integral (sin x) from 0 to x
    is -cos x - -cos 0 = -cos x - -1 = 1 - cos x
  """;

  print "Newton integral, n=200\n";
  var x = 0.0;
  val pi = 3.141;
  while {x < pi} 
  {
    y := newton (sin of (double), 0.0, x, 200);
    r := 1.0 - cos x; // the right answer
    e := y - r;      // error
    print$ 
      f"x=%f, sin x = %f, 1-cos x = %f, integ (sin x)= %f, error = %f\n"
      (x, sin x, r, y, e)
    ;
    x += 0.1;
  };
}
test1;


comment """
  Now, we use a Cauchy condition to evaluate a definite
  integral. We start with n = 4, and calculate 
    y' = integral (f,a,b,n)
  Then increase n and calculate
    y = integral (f,a,b,n)
  and 
    delta = abs(y-y')
  is difference between the two terms. We continue until
  the difference is less than some given epsilon
""";

fun cauchy(
  f:double -> double,
  a: double,
  b: double,
  epsilon: double
  when a <= b and epsilon > 1.0e-14
): double =
{
  var n = 4;
  var y0 = newton (f, a, b, n);
retry:>
  n = n * 7/4;
  var y1 = newton (f, a, b, n);
  if abs (y1 - y0) <= epsilon do 
    return y1;
  else 
    goto retry;
  done;
}

proc test2
{
  print "Newton integral with feedback and Cauchy termination\n";
  var x = 0.0;
  val pi = 3.141;
  while {x < pi} 
  {
    y := cauchy (sin of (double), 0.0, x, 1.0e-12);
    r := 1.0 - cos x; // the right answer
    e := y - r;      // error
    print$ 
      f"x=%f, sin x = %f, 1-cos x = %f, integ (sin x)= %f, error = %f\n"
      (x, sin x, r, y, e)
    ;
    x += 0.1;
  };
};
test2;

comment """
  remodel the whole thing using chips
""";

typedef idouble = ischannel[double];
typedef odouble = oschannel[double];
typedef iint = ischannel[int];
typedef oint = oschannel[int];

proc Sin(i:idouble, o:odouble) {
again:>
  var &x : double <- read i;
  y := sin x;
  write (o,y);
  goto again;
}

proc Newton(
  fout:odouble,fin:idouble,
  a:double,
  bin:idouble,
  nin:iint,
  res:odouble
)
{
again:>  
  var &b : double <- read bin;
  width := b - a;
  var &n : int <- read nin;
  barwidth := width / double n;
  var sum = 0.0;
  var i:int; forall i in 0 upto n-1 do
    x := a + width * (double i + 0.5)/double n;
    write (fout, x);
    var &height : double <- read fin;
    sum += barwidth * height;
  done;
  write (res,sum);
  goto again;
}

proc Cauchy(
  bin:idouble,
  bout:odouble,
  nout:oint,
  yin:idouble,
  epsilon:double,
  y2out:odouble
  when epsilon > 1.0e-14
)
{
again:>
  var n = 4;
  var &b:double <- read bin;
retry:>
  write (bout, b);
  write (nout, n);
  var &y0 : double <- read yin;

  write (bout, b);
  n = n * 7/4;
  write (nout, 4);
  var &y1 : double <- read yin;

  if abs (y1 - y0) <= epsilon do 
    write (y2out,y1);
    goto again;
  else 
    goto retry;
  done;
}

proc make_circuit (input: &odouble, output: &idouble) 
{

  //  xin--> [sin] --> yout
  //
  //  b2in, nin, yin -> [Newton] -> xout, y2out
  //
  // bin, y2in -> [Cauchy] -> b2out, nout, rout
  //
  // 

  // define the wires
  var xin, xout = mk_ioschannel_pair[double](); 
  var yin, yout = mk_ioschannel_pair[double](); 
  var y2in, y2out = mk_ioschannel_pair[double](); 
  var bin, bout = mk_ioschannel_pair[double]();
  var b2in, b2out = mk_ioschannel_pair[double]();
  var nin, nout = mk_ioschannel_pair[int]();
  var rin, rout = mk_ioschannel_pair[double](); 

  // define the chips
  spawn_fthread { Sin (xin, yout); };
  spawn_fthread { Newton (xout, yin, 0.0, b2in, nin, y2out); };
  spawn_fthread { Cauchy (bin, b2out, nout, y2in, 1.0e-12, rout); };
  *input = bout;
  *output = rin;
}

proc test3()
{
  print 
    "FIBRATED Newton integral"
    " with feedback and Cauchy termination\n"
  ;
  var bout: odouble;
  var rin: idouble;

  make_circuit(&bout, &rin);

  var x = 0.0;
  val pi = 3.141;
  while {x < pi} 
  {
    write (bout, x);
    var &y : double <- read rin;
    r := 1.0 - cos x; // the right answer
    e := y - r;      // error
    print$ 
      f"x=%f, sin x = %f, 1-cos x = %f, integ (sin x)= %f, error = %f\n"
      (x, sin x, r, y, e)
    ;
    x += 0.1;
  };
};
test3;


-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to