Active object: Difference between revisions

Content added Content deleted
m (→‎{{header|Perl 6}}: avoid a race condition)
m (alphabetize)
Line 44: Line 44:
entry Output (Value : out Float);
entry Output (Value : out Float);
entry Shut_Down;
entry Shut_Down;
end Integrator;
end Integrator;A072954
task body Integrator is
task body Integrator is
Line 196: Line 196:
output
output
<pre>-9.99348e-05</pre>
<pre>-9.99348e-05</pre>
A072954

=={{header|C#}}==
=={{header|C#}}==
{{works with|C# 6}}
{{works with|C# 6}}
Line 1,260: Line 1,260:
v2 = it.runningsum
v2 = it.runningsum
println("After 2.5 seconds, integrator value was $v2")</lang>
println("After 2.5 seconds, integrator value was $v2")</lang>

=={{header|Lingo}}==
Parent script "Integrator":
<lang Lingo>property _sum
property _func
property _timeLast
property _valueLast
property _ms0
property _updateTimer

on new (me, func)
if voidP(func) then func = "0.0"
me._sum = 0.0
-- update frequency: 100/sec (arbitrary)
me._updateTimer = timeout().new("update", 10, #_update, me)
me.input(func)
return me
end

on stop (me)
me._updateTimer.period = 0 -- deactivates timer
end

-- func is a term (as string) that might contain "t" and is evaluated at runtime
on input (me, func)
me._func = func
me._ms0 = _system.milliseconds
me._timeLast = 0.0
t = 0.0
me._valueLast = value(me._func)
end

on output (me)
return me._sum
end

on _update (me)
now = _system.milliseconds - me._ms0
t = now/1000.0
val = value(me._func)
me._sum = me._sum + (me._valueLast+val)*(t - me._timeLast)/2
me._timeLast = t
me._valueLast = val
end</lang>

In some movie script:
<lang Lingo>global gIntegrator

-- entry point
on startMovie
gIntegrator = script("Integrator").new("sin(PI * t)")
timeout().new("timer", 2000, #step1)
end

on step1 (_, timer)
gIntegrator.input("0.0")
timer.timeoutHandler = #step2
timer.period = 500
end

on step2 (_, timer)
gIntegrator.stop()
put gIntegrator.output()
timer.forget()
end</lang>

{{out}}
<pre>-- 0.0004</pre>


=={{header|Kotlin}}==
=={{header|Kotlin}}==
Line 1,407: Line 1,339:
</pre>
</pre>


=={{header|Mathematica}}==
=={{header|Lingo}}==
Parent script "Integrator":
<lang Mathematica>Block[{start = SessionTime[], K, t0 = 0, t1, kt0, S = 0},
<lang Lingo>property _sum
K[t_] = Sin[2 Pi f t] /. f -> 0.5; kt0 = K[t0];
property _func
While[True, t1 = SessionTime[] - start;
property _timeLast
S += (kt0 + (kt0 = K[t1])) (t1 - t0)/2; t0 = t1;
property _valueLast
If[t1 > 2, K[t_] = 0; If[t1 > 2.5, Break[]]]]; S]</lang>
property _ms0
property _updateTimer


on new (me, func)
1.1309*10^-6
if voidP(func) then func = "0.0"
me._sum = 0.0
-- update frequency: 100/sec (arbitrary)
me._updateTimer = timeout().new("update", 10, #_update, me)
me.input(func)
return me
end


on stop (me)
Curiously, this value never changes; it is always exactly the same (at 1.1309E-6). Note that closer answers could be achieved by using Mathematica's better interpolation methods, but it would require collecting the data (in a list), which would have a speed penalty large enough to negate the improved estimation.
me._updateTimer.period = 0 -- deactivates timer
end


-- func is a term (as string) that might contain "t" and is evaluated at runtime
=={{header|Oz}}==
on input (me, func)
<lang oz>declare
me._func = func
fun {Const X}
me._ms0 = _system.milliseconds
fun {$ _} X end
me._timeLast = 0.0
end
t = 0.0
me._valueLast = value(me._func)
end


on output (me)
fun {Now}
return me._sum
{Int.toFloat {Property.get 'time.total'}} / 1000.0
end
end


on _update (me)
class Integrator from Time.repeat
now = _system.milliseconds - me._ms0
attr
k:{Const 0.0}
t = now/1000.0
s:0.0
val = value(me._func)
me._sum = me._sum + (me._valueLast+val)*(t - me._timeLast)/2
t1 k_t1
t2 k_t2
me._timeLast = t
me._valueLast = val
end</lang>
meth init(SampleIntervalMS)
t1 := {Now}
k_t1 := {@k @t1}
{self setRepAll(action:Update
delay:SampleIntervalMS)}
thread
{self go}
end
end


In some movie script:
meth input(K)
<lang Lingo>global gIntegrator
k := K
end


-- entry point
meth output($)
on startMovie
@s
gIntegrator = script("Integrator").new("sin(PI * t)")
end
timeout().new("timer", 2000, #step1)
end


on step1 (_, timer)
meth Update
gIntegrator.input("0.0")
t2 := {Now}
timer.timeoutHandler = #step2
k_t2 := {@k @t2}
timer.period = 500
s := @s + (@k_t1 + @k_t2) * (@t2 - @t1) / 2.0
end
t1 := @t2
k_t1 := @k_t2
end
end


on step2 (_, timer)
Pi = 3.14159265
F = 0.5
gIntegrator.stop()
put gIntegrator.output()
timer.forget()
end</lang>


{{out}}
I = {New Integrator init(10)}
<pre>-- 0.0004</pre>
in
{I input(fun {$ T}
{Sin 2.0 * Pi * F * T}
end)}


=={{header|Mathematica}}==
{Delay 2000} %% ms
<lang Mathematica>Block[{start = SessionTime[], K, t0 = 0, t1, kt0, S = 0},
K[t_] = Sin[2 Pi f t] /. f -> 0.5; kt0 = K[t0];
While[True, t1 = SessionTime[] - start;
S += (kt0 + (kt0 = K[t1])) (t1 - t0)/2; t0 = t1;
If[t1 > 2, K[t_] = 0; If[t1 > 2.5, Break[]]]]; S]</lang>


1.1309*10^-6
{I input({Const 0.0})}


Curiously, this value never changes; it is always exactly the same (at 1.1309E-6). Note that closer answers could be achieved by using Mathematica's better interpolation methods, but it would require collecting the data (in a list), which would have a speed penalty large enough to negate the improved estimation.
{Delay 500} %% ms

{Show {I output($)}}
{I stop}</lang>


=={{header|ooRexx}}==
=={{header|ooRexx}}==
Line 1,554: Line 1,492:


::routine sine
::routine sine
use arg t
use arg t=={{header|OxygenBasic}}==
Built from scratch. The ringmaster orchestrates all the active-objects, keeping a list of
return rxcalcsin(rxcalcpi() * t)
each individual and its method call.


With a high precision timer the result is around -.0002
::requires rxmath library
<lang oxygenbasic>
double MainTime


'===============
</lang>
class RingMaster
'===============
'
indexbase 1
sys List[512] 'limit of 512 objects per ringmaster
sys max,acts
'
method Register(sys meth,obj) as sys
sys i
for i=1 to max step 2
if list[i]=0 then exit for 'vacant slot
next
if i>=max then max+=2
List[i]<=meth,obj
return i 'token for deregistration etc
end method
'
method Deregister(sys *i)
if i then List[i]<=0,0 : i=0
end method
'
method Clear()
max=0
end method
'
method Act() 'called by the timer
sys i,q
for i=1 to max step 2
q=List[i]
if q then
call q List[i+1] 'anon object
end if
next
acts++
end method
'
end class


=={{header|Perl}}==
<lang perl>#!/usr/bin/perl


'=================
use strict;
class ActiveObject
use 5.10.0;
'=================
'
double s,freq,t1,t2,v1,v2
sys nfun,acts,RingToken
RingMaster *Master
'
method fun0() as double
end method
'
method fun1() as double
return sin(2*pi()*freq*MainTime)
end method
'
method func() as double
select case nfun
case 0 : return fun0()
case 1 : return fun1()
end select
'error?
end method
'
method TimeBasedDuties()
t1=t2
v1=v2
t2=MainTime
v2=func
s=s+(v2+v1)*(t2-t1)*0.5 'add slice to integral
acts++
end method
'
method RegisterWith(RingMaster*r)
@Master=@r
if @Master then
RingToken=Master.register @TimeBasedDuties,@this
end if
end method
'
method Deregister()
if @Master then
Master.Deregister RingToken 'this is set to null
end if
end method
'
method Output() as double
return s
end method
'
method Input(double fr=0,fun=0)
if fr then freq=fr
nfun=fun
end method


method ClearIntegral()
package Integrator;
s=0
use threads;
end method
use threads::shared;
'
end class


sub new {
my $cls = shift;
my $obj = bless { t => 0,
sum => 0,
ref $cls ? %$cls : (),
stop => 0,
tid => 0,
func => shift,
}, ref $cls || $cls;


'SETUP TIMING SYSTEM
share($obj->{sum});
'===================
share($obj->{stop});


extern library "kernel32.dll"
$obj->{tid} = async {
declare QueryPerformanceCounter (quad*c)
my $upd = 0.1; # update every 0.1 second
declare QueryPerformanceFrequency(quad*f)
while (!$obj->{stop}) {
declare Sleep(sys milliseconds)
{
end extern
my $f = $obj->{func};
'
my $t = $obj->{t};
quad scount,tcount,freq
QueryPerformanceFrequency freq
double tscale=1/freq
double t1,t2
QueryPerformanceCounter scount


macro PrecisionTime(time)
$obj->{sum} += ($f->($t) + $f->($t + $upd))* $upd/ 2;
QueryPerformanceCounter tcount
$obj->{t} += $upd;
time=(tcount-scount)*tscale
}
end macro
select(undef, undef, undef, $upd);
}
# say "stopping $obj";
};
$obj
}


sub output { shift->{sum} }


'====
sub delete {
'TEST
my $obj = shift;
'====
$obj->{stop} = 1;
$obj->{tid}->join;
}


double integral
sub setinput {
double tevent1,tevent2
# This is surprisingly difficult because of the perl sharing model.
RingMaster Rudolpho
# Func refs can't be shared, thus can't be replaced by another thread.
ActiveObject A
# Have to create a whole new object... there must be a better way.
'
my $obj = shift;
A.RegisterWith Rudolpho
$obj->delete;
A.input (fr=0.5, fun=1) 'start with the freqency function (1)
$obj->new(shift);
'
}
'SET EVENT TIMES
'===============


tEvent1=2.0 'seconds
package main;
tEvent2=2.5 'seconds
'
PrecisionTime t1 'mark initial time
MainTime=t1
'
'
'EVENT LOOP
'==========
'
do
PrecisionTime t2
MainTime=t2
if t2-t1>=0.020 'seconds interval
Rudolpho.Act 'service all active objects
t1=t2
end if
'
if tEvent1>=0 and MainTime>=tEvent1
A.input (fun=0) 'switch to null function (0)
tEvent1=-1 'disable this event from happening again
end if
if MainTime>=tEvent2
integral=A.output()
exit do 'end of session
end if
'
sleep 5 'hand control to OS for a while
end doA072954


print str(integral,4)
my $x = Integrator->new(sub { sin(atan2(1, 1) * 8 * .5 * shift) });


Rudolpho.clear</lang>
sleep(2);
return rxcalcsin(rxcalcpi() * t)
say "sin after 2 seconds: ", $x->output;


::requires rxmath library
$x = $x->setinput(sub {0});


</lang>
select(undef, undef, undef, .5);
say "0 after .5 seconds: ", $x->output;

$x->delete;</lang>

=={{header|Perl 6}}==
{{works with|Rakudo|2018.12}}
There is some jitter in the timer, but it is typically accurate to within a few thousandths of a second.

<lang perl6>class Integrator {
has $.f is rw = sub ($t) { 0 };
has $.now is rw;
has $.value is rw = 0;
has $.integrator is rw;

method init() {
self.value = &(self.f)(0);
self.integrator = Thread.new(
:code({
loop {
my $t1 = now;
self.value += (&(self.f)(self.now) + &(self.f)($t1)) * ($t1 - self.now) / 2;
self.now = $t1;
sleep .001;
}
}),
:app_lifetime(True)
).run
}

method Input (&f-of-t) {
self.f = &f-of-t;
self.init;
self.now = now;
}

method Output { self.value }
}

my $a = Integrator.new;

$a.Input( sub ($t) { sin(2 * π * .5 * $t) } );

say "Initial value: ", $a.Output;

sleep 2;

say "After 2 seconds: ", $a.Output;

$a.Input( sub ($t) { 0 } );

sleep .5;

say "f(0): ", $a.Output;</lang>

{{out|Typical output}}
<pre>Initial value: 0
After 2 seconds: -0.0005555887464620366
f(0): 0</pre>


=={{header|OxygenBasic}}==
=={{header|OxygenBasic}}==
Line 1,860: Line 1,849:
'
'
sleep 5 'hand control to OS for a while
sleep 5 'hand control to OS for a while
end do
end doA072954


print str(integral,4)
print str(integral,4)


Rudolpho.clear</lang>
Rudolpho.clear</lang>

=={{header|Oz}}==
<lang oz>declare
fun {Const X}
fun {$ _} X end
end

fun {Now}
{Int.toFloat {Property.get 'time.total'}} / 1000.0
end

class Integrator from Time.repeat
attr
k:{Const 0.0}
s:0.0
t1 k_t1
t2 k_t2
meth init(SampleIntervalMS)
t1 := {Now}
k_t1 := {@k @t1}
{self setRepAll(action:Update
delay:SampleIntervalMS)}
thread
{self go}
end
end

meth input(K)
k := K
end

meth output($)
@s
end

meth Update
t2 := {Now}
k_t2 := {@k @t2}
s := @s + (@k_t1 + @k_t2) * (@t2 - @t1) / 2.0
t1 := @t2
k_t1 := @k_t2
end
end

Pi = 3.14159265
F = 0.5

I = {New Integrator init(10)}
in
{I input(fun {$ T}
{Sin 2.0 * Pi * F * T}
end)}

{Delay 2000} %% ms

{I input({Const 0.0})}

{Delay 500} %% ms

{Show {I output($)}}
{I stop}</lang>

=={{header|Perl}}==
<lang perl>#!/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;</lang>

=={{header|Perl 6}}==
{{works with|Rakudo|2018.12}}
There is some jitter in the timer, but it is typically accurate to within a few thousandths of a second.

<lang perl6>class Integrator {
has $.f is rw = sub ($t) { 0 };
has $.now is rw;
has $.value is rw = 0;
has $.integrator is rw;

method init() {
self.value = &(self.f)(0);
self.integrator = Thread.new(
:code({
loop {
my $t1 = now;
self.value += (&(self.f)(self.now) + &(self.f)($t1)) * ($t1 - self.now) / 2;
self.now = $t1;
sleep .001;
}
}),
:app_lifetime(True)
).run
}

method Input (&f-of-t) {
self.f = &f-of-t;
self.init;
self.now = now;
}

method Output { self.value }
}

my $a = Integrator.new;

$a.Input( sub ($t) { sin(2 * π * .5 * $t) } );

say "Initial value: ", $a.Output;

sleep 2;

say "After 2 seconds: ", $a.Output;

$a.Input( sub ($t) { 0 } );

sleep .5;

say "f(0): ", $a.Output;</lang>

{{out|Typical output}}
<pre>Initial value: 0
After 2 seconds: -0.0005555887464620366
f(0): 0</pre>


=={{header|PicoLisp}}==
=={{header|PicoLisp}}==