Add all the A tasks
This commit is contained in:
parent
2dd7375f96
commit
051504d65b
1608 changed files with 18584 additions and 0 deletions
17
Task/Active-object/0DESCRIPTION
Normal file
17
Task/Active-object/0DESCRIPTION
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
In [[object-oriented programming]] an object is active when its state depends on clock. Usually an active object encapsulates a [[task]] that updates the object's state. To the outer world the object looks like a normal object with methods that can be called from outside. Implementation of such methods must have a certain synchronization mechanism with the encapsulated task in order to prevent object's state corruption.
|
||||
|
||||
A typical instance of an active object is an animation widget. The widget state changes with the time, while as an object it has all properties of a normal widget.
|
||||
|
||||
'''The task'''
|
||||
|
||||
Implement an active integrator object. The object has an input and output. The input can be set using the method ''Input''. The input is a function of time. The output can be queried using the method ''Output''. The object integrates its input over the time and the result becomes the object's output. So if the input is ''K''(''t'') and the output is ''S'', the object state ''S'' is changed to ''S'' + (''K''(''t''<sub>1</sub>) + ''K''(''t''<sub>0</sub>)) * (''t''<sub>1</sub> - ''t''<sub>0</sub>) / 2, i.e. it integrates ''K'' using the trapeze method. Initially ''K'' is constant 0 and ''S'' is 0.
|
||||
|
||||
In order to test the object:
|
||||
# set its input to sin (2π ''f t''), where the frequency ''f''=0.5Hz. The phase is irrelevant.
|
||||
# wait 2s
|
||||
# set the input to constant 0
|
||||
# wait 0.5s
|
||||
|
||||
Verify that now the object's output is approximately 0 (the sine has the period of 2s). The accuracy of the result will depend on the [[OS]] scheduler time slicing and the accuracy of the clock.
|
||||
|
||||
{{omit from|VBScript}}
|
||||
8
Task/Active-object/1META.yaml
Normal file
8
Task/Active-object/1META.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
category:
|
||||
- Object oriented
|
||||
note: Concurrency
|
||||
requires:
|
||||
- Concurrency
|
||||
- Objects
|
||||
- Mutable State
|
||||
65
Task/Active-object/Ada/active-object.ada
Normal file
65
Task/Active-object/Ada/active-object.ada
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
with Ada.Calendar; use Ada.Calendar;
|
||||
with Ada.Numerics; use Ada.Numerics;
|
||||
with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions;
|
||||
with Ada.Text_IO; use Ada.Text_IO;
|
||||
|
||||
procedure Test_Integrator is
|
||||
type Func is access function (T : Time) return Float;
|
||||
|
||||
function Zero (T : Time) return Float is
|
||||
begin
|
||||
return 0.0;
|
||||
end Zero;
|
||||
|
||||
Epoch : constant Time := Clock;
|
||||
|
||||
function Sine (T : Time) return Float is
|
||||
begin
|
||||
return Sin (Pi * Float (T - Epoch));
|
||||
end Sine;
|
||||
|
||||
task type Integrator is
|
||||
entry Input (Value : Func);
|
||||
entry Output (Value : out Float);
|
||||
entry Shut_Down;
|
||||
end Integrator;
|
||||
|
||||
task body Integrator is
|
||||
K : Func := Zero'Access;
|
||||
S : Float := 0.0;
|
||||
F0 : Float := 0.0;
|
||||
F1 : Float;
|
||||
T0 : Time := Clock;
|
||||
T1 : Time;
|
||||
begin
|
||||
loop
|
||||
select
|
||||
accept Input (Value : Func) do
|
||||
K := Value;
|
||||
end Input;
|
||||
or accept Output (Value : out Float) do
|
||||
Value := S;
|
||||
end Output;
|
||||
or accept Shut_Down;
|
||||
exit;
|
||||
else
|
||||
T1 := Clock;
|
||||
F1 := K (T1);
|
||||
S := S + 0.5 * (F1 + F0) * Float (T1 - T0);
|
||||
T0 := T1;
|
||||
F0 := F1;
|
||||
end select;
|
||||
end loop;
|
||||
end Integrator;
|
||||
|
||||
I : Integrator;
|
||||
S : Float;
|
||||
begin
|
||||
I.Input (Sine'Access);
|
||||
delay 2.0;
|
||||
I.Input (Zero'Access);
|
||||
delay 0.5;
|
||||
I.Output (S);
|
||||
Put_Line ("Integrated" & Float'Image (S) & "s");
|
||||
I.Shut_Down;
|
||||
end Test_Integrator;
|
||||
70
Task/Active-object/C/active-object.c
Normal file
70
Task/Active-object/C/active-object.c
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* no need to lock the object: at worst the readout would be 1 tick off,
|
||||
which is no worse than integrator's inate inaccuracy */
|
||||
typedef struct {
|
||||
double (*func)(double);
|
||||
struct timeval start;
|
||||
double v, last_v, last_t;
|
||||
pthread_t id;
|
||||
} integ_t, *integ;
|
||||
|
||||
void update(integ x)
|
||||
{
|
||||
struct timeval tv;
|
||||
double t, v, (*f)(double);
|
||||
|
||||
f = x->func;
|
||||
gettimeofday(&tv, 0);
|
||||
t = ((tv.tv_sec - x->start.tv_sec) * 1000000
|
||||
+ tv.tv_usec - x->start.tv_usec) * 1e-6;
|
||||
v = f ? f(t) : 0;
|
||||
x->v += (x->last_v + v) * (t - x->last_t) / 2;
|
||||
x->last_t = t;
|
||||
}
|
||||
|
||||
void* tick(void *a)
|
||||
{
|
||||
integ x = a;
|
||||
while (1) {
|
||||
usleep(100000); /* update every .1 sec */
|
||||
update(x);
|
||||
}
|
||||
}
|
||||
|
||||
void set_input(integ x, double (*func)(double))
|
||||
{
|
||||
update(x);
|
||||
x->func = func;
|
||||
x->last_t = 0;
|
||||
x->last_v = func ? func(0) : 0;
|
||||
}
|
||||
|
||||
integ new_integ(double (*func)(double))
|
||||
{
|
||||
integ x = malloc(sizeof(integ_t));
|
||||
x->v = x->last_v = 0;
|
||||
x->func = 0;
|
||||
gettimeofday(&x->start, 0);
|
||||
set_input(x, func);
|
||||
pthread_create(&x->id, 0, tick, x);
|
||||
return x;
|
||||
}
|
||||
|
||||
double sine(double t) { return sin(4 * atan2(1, 1) * t); }
|
||||
|
||||
int main()
|
||||
{
|
||||
integ x = new_integ(sine);
|
||||
sleep(2);
|
||||
set_input(x, 0);
|
||||
usleep(500000);
|
||||
printf("%g\n", x->v);
|
||||
|
||||
return 0;
|
||||
}
|
||||
36
Task/Active-object/Clojure/active-object.clj
Normal file
36
Task/Active-object/Clojure/active-object.clj
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
(ns active-object
|
||||
(:import (java.util Timer TimerTask)))
|
||||
|
||||
(defn input [integrator k]
|
||||
(send integrator assoc :k k))
|
||||
|
||||
(defn output [integrator]
|
||||
(:s @integrator))
|
||||
|
||||
(defn tick [integrator t1]
|
||||
(send integrator
|
||||
(fn [{:keys [k s t0] :as m}]
|
||||
(assoc m :s (+ s (/ (* (+ (k t1) (k t0)) (- t1 t0)) 2.0)) :t0 t1))))
|
||||
|
||||
(defn start-timer [integrator interval]
|
||||
(let [timer (Timer. true)
|
||||
start (System/currentTimeMillis)]
|
||||
(.scheduleAtFixedRate timer
|
||||
(proxy [TimerTask] []
|
||||
(run [] (tick integrator (double (/ (- (System/currentTimeMillis) start) 1000)))))
|
||||
(long 0)
|
||||
(long interval))
|
||||
#(.cancel timer)))
|
||||
|
||||
(defn test-integrator []
|
||||
(let [integrator (agent {:k (constantly 0.0) :s 0.0 :t0 0.0})
|
||||
stop-timer (start-timer integrator 10)]
|
||||
(input integrator #(Math/sin (* 2.0 Math/PI 0.5 %)))
|
||||
(Thread/sleep 2000)
|
||||
(input integrator (constantly 0.0))
|
||||
(Thread/sleep 500)
|
||||
(println (output integrator))
|
||||
(stop-timer)))
|
||||
|
||||
user> (test-integrator)
|
||||
1.414065859052494E-5
|
||||
80
Task/Active-object/Go/active-object.go
Normal file
80
Task/Active-object/Go/active-object.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// type for input function, k.
|
||||
// input is duration since an arbitrary start time t0.
|
||||
type tFunc func(time.Duration) float64
|
||||
|
||||
// active integrator object. state variables are not here, but in
|
||||
// function aif, started as a goroutine in the constructor.
|
||||
type aio struct {
|
||||
iCh chan tFunc // channel for setting input function
|
||||
oCh chan chan float64 // channel for requesting output
|
||||
}
|
||||
|
||||
// constructor
|
||||
func newAio() *aio {
|
||||
var a aio
|
||||
a.iCh = make(chan tFunc)
|
||||
a.oCh = make(chan chan float64)
|
||||
go aif(&a)
|
||||
return &a
|
||||
}
|
||||
|
||||
// input method required by task description. in practice, this method is
|
||||
// unnecessary; you would just put that single channel send statement in
|
||||
// your code wherever you wanted to set the input function.
|
||||
func (a aio) input(f tFunc) {
|
||||
a.iCh <- f
|
||||
}
|
||||
|
||||
// output method required by task description. in practice, this method too
|
||||
// would not likely be best. instead any client interested in the value would
|
||||
// likely make a return channel sCh once, and then reuse it as needed.
|
||||
func (a aio) output() float64 {
|
||||
sCh := make(chan float64)
|
||||
a.oCh <- sCh
|
||||
return <-sCh
|
||||
}
|
||||
|
||||
// integration function that returns constant 0
|
||||
func zeroFunc(time.Duration) float64 { return 0 }
|
||||
|
||||
// goroutine serializes access to integrated function k and state variable s
|
||||
func aif(a *aio) {
|
||||
var k tFunc = zeroFunc // integration function
|
||||
s := 0. // "object state" initialized to 0
|
||||
t0 := time.Now() // initial time
|
||||
k0 := k(0) // initial sample value
|
||||
t1 := t0 // t1, k1 used for trapezoid formula
|
||||
k1 := k0
|
||||
|
||||
tk := time.Tick(10 * time.Millisecond) // 10 ms -> 100 Hz
|
||||
for {
|
||||
select {
|
||||
case t2 := <-tk: // timer tick event
|
||||
k2 := k(t2.Sub(t0)) // new sample value
|
||||
s += (k1 + k2) * .5 * t2.Sub(t1).Seconds() // trapezoid formula
|
||||
t1, k1 = t2, k2 // save time and value
|
||||
case k = <-a.iCh: // input method event: function change
|
||||
case sCh := <-a.oCh: // output method event: sample object state
|
||||
sCh <- s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
a := newAio() // create object
|
||||
a.input(func(t time.Duration) float64 { // 1. set input to sin function
|
||||
return math.Sin(t.Seconds() * math.Pi)
|
||||
})
|
||||
time.Sleep(2 * time.Second) // 2. sleep 2 sec
|
||||
a.input(zeroFunc) // 3. set input to zero function
|
||||
time.Sleep(time.Second / 2) // 4. sleep .5 sec
|
||||
fmt.Println(a.output()) // output should be near zero
|
||||
}
|
||||
77
Task/Active-object/Haskell/active-object.hs
Normal file
77
Task/Active-object/Haskell/active-object.hs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
module Integrator (
|
||||
newIntegrator, input, output, stop,
|
||||
Time, timeInterval
|
||||
) where
|
||||
import Control.Concurrent (forkIO, threadDelay)
|
||||
import Control.Concurrent.MVar (MVar, newMVar, modifyMVar_, modifyMVar, readMVar)
|
||||
import Control.Exception (evaluate)
|
||||
import Data.Time (UTCTime)
|
||||
import Data.Time.Clock (getCurrentTime, diffUTCTime)
|
||||
|
||||
-- RC task
|
||||
main = do let f = 0.5 {- Hz -}
|
||||
t0 <- getCurrentTime
|
||||
i <- newIntegrator
|
||||
input i (\t -> sin(2*pi * f * timeInterval t0 t)) -- task step 1
|
||||
threadDelay 2000000 {- µs -} -- task step 2
|
||||
input i (const 0) -- task step 3
|
||||
threadDelay 500000 {- µs -} -- task step 4
|
||||
result <- output i
|
||||
stop i
|
||||
print result
|
||||
|
||||
---- Implementation ------------------------------------------------------
|
||||
|
||||
-- Utilities for working with the time type
|
||||
type Time = UTCTime
|
||||
type Func a = Time -> a
|
||||
timeInterval t0 t1 = realToFrac $ diffUTCTime t1 t0
|
||||
|
||||
-- Type signatures of the module's interface
|
||||
newIntegrator :: Fractional a => IO (Integrator a) -- Create an integrator
|
||||
input :: Integrator a -> Func a -> IO () -- Set the input function
|
||||
output :: Integrator a -> IO a -- Get the current value
|
||||
stop :: Integrator a -> IO () -- Stop integration, don't waste CPU
|
||||
|
||||
-- Data structures
|
||||
data Integrator a = Integrator (MVar (IntState a)) -- MVar is a thread-safe mutable cell
|
||||
deriving Eq
|
||||
data IntState a = IntState { func :: Func a, -- The current function
|
||||
run :: Bool, -- Whether to keep going
|
||||
value :: a, -- The current accumulated value
|
||||
time :: Time } -- The time of the previous update
|
||||
|
||||
newIntegrator = do
|
||||
now <- getCurrentTime
|
||||
state <- newMVar $ IntState { func = const 0,
|
||||
run = True,
|
||||
value = 0,
|
||||
time = now }
|
||||
thread <- forkIO (intThread state) -- The state variable is shared between the thread
|
||||
return (Integrator state) -- and the client interface object.
|
||||
|
||||
input (Integrator stv) f = modifyMVar_ stv (\st -> return st { func = f })
|
||||
output (Integrator stv) = fmap value $ readMVar stv
|
||||
stop (Integrator stv) = modifyMVar_ stv (\st -> return st { run = False })
|
||||
-- modifyMVar_ takes an MVar and replaces its contents according to the provided function.
|
||||
-- a { b = c } is record-update syntax: "the record a, except with field b changed to c"
|
||||
|
||||
-- Integration thread
|
||||
intThread :: Fractional a => MVar (IntState a) -> IO ()
|
||||
intThread stv = whileM $ modifyMVar stv updateAndCheckRun
|
||||
-- modifyMVar is like modifyMVar_ but the function returns a tuple of the new value
|
||||
-- and an arbitrary extra value, which in this case ends up telling whileM whether
|
||||
-- to keep looping.
|
||||
where updateAndCheckRun st = do
|
||||
now <- getCurrentTime
|
||||
let value' = integrate (func st) (value st) (time st) now
|
||||
evaluate value' -- avoid undesired laziness
|
||||
return (st { value = value', time = now }, -- updated state
|
||||
run st) -- whether to continue
|
||||
|
||||
integrate :: Fractional a => Func a -> a -> Time -> Time -> a
|
||||
integrate f value t0 t1 = value + (f t0 + f t1)/2 * dt
|
||||
where dt = timeInterval t0 t1
|
||||
|
||||
-- Execute 'action' until it returns false.
|
||||
whileM action = do b <- action; if b then whileM action else return ()
|
||||
26
Task/Active-object/JavaScript/active-object-1.js
Normal file
26
Task/Active-object/JavaScript/active-object-1.js
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
function Integrator(sampleIntervalMS) {
|
||||
var inputF = function () { return 0.0 };
|
||||
var sum = 0.0;
|
||||
|
||||
var t1 = new Date().getTime();
|
||||
var input1 = inputF(t1 / 1000);
|
||||
|
||||
function update() {
|
||||
var t2 = new Date().getTime();
|
||||
var input2 = inputF(t2 / 1000);
|
||||
var dt = (t2 - t1) / 1000;
|
||||
|
||||
sum += (input1 + input2) * dt / 2;
|
||||
|
||||
t1 = t2;
|
||||
input1 = input2;
|
||||
}
|
||||
|
||||
var updater = setInterval(update, sampleIntervalMS);
|
||||
|
||||
return ({
|
||||
input: function (newF) { inputF = newF },
|
||||
output: function () { return sum },
|
||||
shutdown: function () { clearInterval(updater) },
|
||||
});
|
||||
}
|
||||
20
Task/Active-object/JavaScript/active-object-2.js
Normal file
20
Task/Active-object/JavaScript/active-object-2.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<p><span id="a">Test running...</span> <code id="b">-</code></p>
|
||||
|
||||
<script type="text/javascript">
|
||||
var f = 0.5;
|
||||
|
||||
var i = new Integrator(1);
|
||||
var displayer = setInterval(function () { document.getElementById("b").firstChild.data = i.output() }, 100)
|
||||
|
||||
setTimeout(function () {
|
||||
i.input(function (t) { return Math.sin(2*Math.PI*f*t) }); // test step 1
|
||||
setTimeout(function () { // test step 2
|
||||
i.input(function (t) { return 0 }); // test step 3
|
||||
setTimeout(function () { // test step 3
|
||||
i.shutdown();
|
||||
clearInterval(displayer);
|
||||
document.getElementById("a").firstChild.data = "Done, should be about 0: "
|
||||
}, 500);
|
||||
}, 2000);
|
||||
}, 1)
|
||||
</script>
|
||||
69
Task/Active-object/Perl/active-object.pl
Normal file
69
Task/Active-object/Perl/active-object.pl
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use 5.10.0;
|
||||
|
||||
package Integrator;
|
||||
use threads;
|
||||
use threads::shared;
|
||||
|
||||
sub new {
|
||||
my $cls = shift;
|
||||
my $obj = bless { t => 0,
|
||||
sum => 0,
|
||||
ref $cls ? %$cls : (),
|
||||
stop => 0,
|
||||
tid => 0,
|
||||
func => shift,
|
||||
}, ref $cls || $cls;
|
||||
|
||||
share($obj->{sum});
|
||||
share($obj->{stop});
|
||||
|
||||
$obj->{tid} = async {
|
||||
my $upd = 0.1; # update every 0.1 second
|
||||
while (!$obj->{stop}) {
|
||||
{
|
||||
my $f = $obj->{func};
|
||||
my $t = $obj->{t};
|
||||
|
||||
$obj->{sum} += ($f->($t) + $f->($t + $upd))* $upd/ 2;
|
||||
$obj->{t} += $upd;
|
||||
}
|
||||
select(undef, undef, undef, $upd);
|
||||
}
|
||||
# say "stopping $obj";
|
||||
};
|
||||
$obj
|
||||
}
|
||||
|
||||
sub output { shift->{sum} }
|
||||
|
||||
sub delete {
|
||||
my $obj = shift;
|
||||
$obj->{stop} = 1;
|
||||
$obj->{tid}->join;
|
||||
}
|
||||
|
||||
sub setinput {
|
||||
# This is surprisingly difficult because of the perl sharing model.
|
||||
# Func refs can't be shared, thus can't be replaced by another thread.
|
||||
# Have to create a whole new object... there must be a better way.
|
||||
my $obj = shift;
|
||||
$obj->delete;
|
||||
$obj->new(shift);
|
||||
}
|
||||
|
||||
package main;
|
||||
|
||||
my $x = Integrator->new(sub { sin(atan2(1, 1) * 8 * .5 * shift) });
|
||||
|
||||
sleep(2);
|
||||
say "sin after 2 seconds: ", $x->output;
|
||||
|
||||
$x = $x->setinput(sub {0});
|
||||
|
||||
select(undef, undef, undef, .5);
|
||||
say "0 after .5 seconds: ", $x->output;
|
||||
|
||||
$x->delete;
|
||||
44
Task/Active-object/PicoLisp/active-object.l
Normal file
44
Task/Active-object/PicoLisp/active-object.l
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
(load "@lib/math.l")
|
||||
|
||||
(class +Active)
|
||||
# inp val sum usec
|
||||
|
||||
(dm T ()
|
||||
(unless (assoc -100 *Run) # Install timer task
|
||||
(task -100 100 # Update objects every 0.1 sec
|
||||
(mapc 'update> *Actives) ) )
|
||||
(=: inp '((U) 0)) # Set zero input function
|
||||
(=: val 0) # Initialize last value
|
||||
(=: sum 0) # Initialize sum
|
||||
(=: usec (usec)) # and time
|
||||
(push '*Actives This) ) # Install in notification list
|
||||
|
||||
(dm input> (Fun)
|
||||
(=: inp Fun) )
|
||||
|
||||
(dm update> ()
|
||||
(let (U (usec) V ((: inp) U)) # Get current time, calculate value
|
||||
(inc (:: sum)
|
||||
(*/
|
||||
(+ V (: val)) # (K(t[1]) + K(t[0])) *
|
||||
(- U (: usec)) # (t[1] - t[0]) /
|
||||
2.0 ) ) # 2.0
|
||||
(=: val V)
|
||||
(=: usec U) ) )
|
||||
|
||||
(dm output> ()
|
||||
(format (: sum) *Scl) ) # Get result
|
||||
|
||||
(dm stop> ()
|
||||
(unless (del This '*Actives) # Removing the last active object?
|
||||
(task -100) ) ) # Yes: Uninstall timer task
|
||||
|
||||
(de integrate () # Test it
|
||||
(let Obj (new '(+Active)) # Create an active object
|
||||
(input> Obj # Set input function
|
||||
'((U) (sin (*/ pi U 1.0))) ) # to sin(π * t)
|
||||
(wait 2000) # Wait 2 sec
|
||||
(input> Obj '((U) 0)) # Reset input function
|
||||
(wait 500) # Wait 0.5 sec
|
||||
(prinl "Output: " (output> Obj)) # Print return value
|
||||
(stop> Obj) ) ) # Stop active object
|
||||
38
Task/Active-object/Python/active-object.py
Normal file
38
Task/Active-object/Python/active-object.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
from time import time, sleep
|
||||
from threading import Thread
|
||||
|
||||
class Integrator(Thread):
|
||||
'continuously integrate a function `K`, at each `interval` seconds'
|
||||
def __init__(self, K=lambda t:0, interval=1e-4):
|
||||
Thread.__init__(self)
|
||||
self.interval = interval
|
||||
self.K = K
|
||||
self.S = 0.0
|
||||
self.__run = True
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
"entry point for the thread"
|
||||
interval = self.interval
|
||||
start = time()
|
||||
t0, k0 = 0, self.K(0)
|
||||
while self.__run:
|
||||
sleep(interval)
|
||||
t1 = time() - start
|
||||
k1 = self.K(t1)
|
||||
self.S += (k1 + k0)*(t1 - t0)/2.0
|
||||
t0, k0 = t1, k1
|
||||
|
||||
def join(self):
|
||||
self.__run = False
|
||||
Thread.join(self)
|
||||
|
||||
if __name__ == "__main__":
|
||||
from math import sin, pi
|
||||
|
||||
ai = Integrator(lambda t: sin(pi*t))
|
||||
sleep(2)
|
||||
print ai.S
|
||||
ai.K = lambda t: 0
|
||||
sleep(0.5)
|
||||
print ai.S
|
||||
30
Task/Active-object/Racket/active-object.rkt
Normal file
30
Task/Active-object/Racket/active-object.rkt
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#lang racket
|
||||
|
||||
(require (only-in racket/gui sleep/yield timer%))
|
||||
|
||||
(define active%
|
||||
(class object%
|
||||
(super-new)
|
||||
(init-field k) ; input function
|
||||
(field [s 0]) ; state
|
||||
(define t_0 0)
|
||||
|
||||
(define/public (input new-k) (set! k new-k))
|
||||
(define/public (output) s)
|
||||
|
||||
(define (callback)
|
||||
(define t_1 (/ (- (current-inexact-milliseconds) start) 1000))
|
||||
(set! s (+ s (* (+ (k t_0) (k t_1))
|
||||
(/ (- t_1 t_0) 2))))
|
||||
(set! t_0 t_1))
|
||||
|
||||
(define start (current-inexact-milliseconds))
|
||||
(new timer%
|
||||
[interval 1000]
|
||||
[notify-callback callback])))
|
||||
|
||||
(define active (new active% [k (λ (t) (sin (* 2 pi 0.5 t)))]))
|
||||
(sleep/yield 2)
|
||||
(send active input (λ _ 0))
|
||||
(sleep/yield 0.5)
|
||||
(displayln (send active output))
|
||||
48
Task/Active-object/Scala/active-object.scala
Normal file
48
Task/Active-object/Scala/active-object.scala
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
object ActiveObject {
|
||||
|
||||
class Integrator {
|
||||
|
||||
import java.util._
|
||||
import scala.actors.Actor._
|
||||
|
||||
case class Pulse(t: Double)
|
||||
case class Input(k: Double => Double)
|
||||
case object Output
|
||||
case object Bye
|
||||
|
||||
val timer = new Timer(true)
|
||||
var k: Double => Double = (_ => 0.0)
|
||||
var s: Double = 0.0
|
||||
var t0: Double = 0.0
|
||||
|
||||
val handler = actor {
|
||||
loop {
|
||||
react {
|
||||
case Pulse(t1) => s += (k(t1) + k(t0)) * (t1 - t0) / 2.0; t0 = t1
|
||||
case Input(k) => this.k = k
|
||||
case Output => reply(s)
|
||||
case Bye => timer.cancel; exit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timer.scheduleAtFixedRate(new TimerTask {
|
||||
val start = System.currentTimeMillis
|
||||
def run { handler ! Pulse((System.currentTimeMillis - start) / 1000.0) }
|
||||
}, 0, 10) // send Pulse every 10 ms
|
||||
|
||||
def input(k: Double => Double) = handler ! Input(k)
|
||||
def output = handler !? Output
|
||||
def bye = handler ! Bye
|
||||
}
|
||||
|
||||
def main(args: Array[String]) {
|
||||
val integrator = new Integrator
|
||||
integrator.input(t => Math.sin(2.0 * Math.Pi * 0.5 * t))
|
||||
Thread.sleep(2000)
|
||||
integrator.input(_ => 0.0)
|
||||
Thread.sleep(500)
|
||||
println(integrator.output)
|
||||
integrator.bye
|
||||
}
|
||||
}
|
||||
50
Task/Active-object/Tcl/active-object.tcl
Normal file
50
Task/Active-object/Tcl/active-object.tcl
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package require Tcl 8.6
|
||||
oo::class create integrator {
|
||||
variable e sum delay tBase t0 k0 aid
|
||||
constructor {{interval 1}} {
|
||||
set delay $interval
|
||||
set tBase [clock microseconds]
|
||||
set t0 0
|
||||
set e { 0.0 }
|
||||
set k0 0.0
|
||||
set sum 0.0
|
||||
set aid [after $delay [namespace code {my Step}]]
|
||||
}
|
||||
destructor {
|
||||
after cancel $aid
|
||||
}
|
||||
method input expression {
|
||||
set e $expression
|
||||
}
|
||||
method output {} {
|
||||
return $sum
|
||||
}
|
||||
method Eval t {
|
||||
expr $e
|
||||
}
|
||||
method Step {} {
|
||||
set aid [after $delay [namespace code {my Step}]]
|
||||
set t [expr {([clock microseconds] - $tBase) / 1e6}]
|
||||
set k1 [my Eval $t]
|
||||
set sum [expr {$sum + ($k1 + $k0) * ($t - $t0) / 2.}]
|
||||
set t0 $t
|
||||
set k0 $k1
|
||||
}
|
||||
}
|
||||
|
||||
set pi 3.14159265
|
||||
proc pause {time} {
|
||||
yield [after [expr {int($time * 1000)}] [info coroutine]]
|
||||
}
|
||||
proc task {script} {
|
||||
coroutine task_ apply [list {} "$script;set ::done ok"]
|
||||
vwait done
|
||||
}
|
||||
task {
|
||||
integrator create i
|
||||
i input {sin(2*$::pi * 0.5 * $t)}
|
||||
pause 2
|
||||
i input { 0.0 }
|
||||
pause 0.5
|
||||
puts [format %.15f [i output]]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue