Merge branch 'master' of git://factorcode.org/git/factor
commit
1b8c9f757d
|
|
@ -53,11 +53,11 @@ $nl
|
||||||
" to be accessed remotely. " { $link publish } " returns an id which a remote node "
|
" to be accessed remotely. " { $link publish } " returns an id which a remote node "
|
||||||
"needs to know to access the channel."
|
"needs to know to access the channel."
|
||||||
$nl
|
$nl
|
||||||
{ $snippet "channel [ from . ] spawn drop dup publish" }
|
{ $snippet "<channel> dup [ from . flush ] curry \"test\" spawn drop publish" }
|
||||||
$nl
|
$nl
|
||||||
"Given the id from the snippet above, a remote node can put items in the channel."
|
"Given the id from the snippet above, a remote node can put items in the channel (where 123456 is the id):"
|
||||||
$nl
|
$nl
|
||||||
{ $snippet "\"myhost.com\" 9001 <node> \"ID123456\" <remote-channel>\n\"hello\" over to" }
|
{ $snippet "\"myhost.com\" 9001 <node> 123456 <remote-channel>\n\"hello\" over to" }
|
||||||
;
|
;
|
||||||
|
|
||||||
ABOUT: { "remote-channels" "remote-channels" }
|
ABOUT: { "remote-channels" "remote-channels" }
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
!
|
!
|
||||||
! Remote Channels
|
! Remote Channels
|
||||||
USING: kernel init namespaces make assocs arrays random
|
USING: kernel init namespaces assocs arrays random
|
||||||
sequences channels match concurrency.messaging
|
sequences channels match concurrency.messaging
|
||||||
concurrency.distributed threads accessors ;
|
concurrency.distributed threads accessors ;
|
||||||
IN: channels.remote
|
IN: channels.remote
|
||||||
|
|
@ -27,39 +27,44 @@ PRIVATE>
|
||||||
MATCH-VARS: ?from ?tag ?id ?value ;
|
MATCH-VARS: ?from ?tag ?id ?value ;
|
||||||
|
|
||||||
SYMBOL: no-channel
|
SYMBOL: no-channel
|
||||||
|
TUPLE: to-message id value ;
|
||||||
|
TUPLE: from-message id ;
|
||||||
|
|
||||||
: channel-process ( -- )
|
: channel-thread ( -- )
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
{ { to ?id ?value }
|
{ T{ to-message f ?id ?value }
|
||||||
[ ?value ?id get-channel dup [ to f ] [ 2drop no-channel ] if ] }
|
[ ?value ?id get-channel dup [ to f ] [ 2drop no-channel ] if ] }
|
||||||
{ { from ?id }
|
{ T{ from-message f ?id }
|
||||||
[ ?id get-channel [ from ] [ no-channel ] if* ] }
|
[ ?id get-channel [ from ] [ no-channel ] if* ] }
|
||||||
} match-cond
|
} match-cond
|
||||||
] handle-synchronous ;
|
] handle-synchronous ;
|
||||||
|
|
||||||
PRIVATE>
|
|
||||||
|
|
||||||
: start-channel-node ( -- )
|
: start-channel-node ( -- )
|
||||||
"remote-channels" get-process [
|
"remote-channels" get-remote-thread [
|
||||||
"remote-channels"
|
[ channel-thread t ] "Remote channels" spawn-server
|
||||||
[ channel-process t ] "Remote channels" spawn-server
|
"remote-channels" register-remote-thread
|
||||||
register-process
|
|
||||||
] unless ;
|
] unless ;
|
||||||
|
|
||||||
|
PRIVATE>
|
||||||
|
|
||||||
TUPLE: remote-channel node id ;
|
TUPLE: remote-channel node id ;
|
||||||
|
|
||||||
C: <remote-channel> remote-channel
|
C: <remote-channel> remote-channel
|
||||||
|
|
||||||
|
<PRIVATE
|
||||||
|
|
||||||
|
: send-message ( message remote-channel -- value )
|
||||||
|
node>> "remote-channels" <remote-thread>
|
||||||
|
send-synchronous dup no-channel = [ no-channel throw ] when* ;
|
||||||
|
|
||||||
|
PRIVATE>
|
||||||
|
|
||||||
M: remote-channel to ( value remote-channel -- )
|
M: remote-channel to ( value remote-channel -- )
|
||||||
[ [ \ to , id>> , , ] { } make ] keep
|
[ id>> swap to-message boa ] keep send-message drop ;
|
||||||
node>> "remote-channels" <remote-process>
|
|
||||||
send-synchronous no-channel = [ no-channel throw ] when ;
|
|
||||||
|
|
||||||
M: remote-channel from ( remote-channel -- value )
|
M: remote-channel from ( remote-channel -- value )
|
||||||
[ [ \ from , id>> , ] { } make ] keep
|
[ id>> from-message boa ] keep send-message ;
|
||||||
node>> "remote-channels" <remote-process>
|
|
||||||
send-synchronous dup no-channel = [ no-channel throw ] when* ;
|
|
||||||
|
|
||||||
[
|
[
|
||||||
H{ } clone \ remote-channels set-global
|
H{ } clone \ remote-channels set-global
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,54 @@ HELP: start-node
|
||||||
{ $values { "port" "a port number between 0 and 65535" } }
|
{ $values { "port" "a port number between 0 and 65535" } }
|
||||||
{ $description "Starts a node server for receiving messages from remote Factor instances." } ;
|
{ $description "Starts a node server for receiving messages from remote Factor instances." } ;
|
||||||
|
|
||||||
|
ARTICLE: "concurrency.distributed.example" "Distributed Concurrency Example"
|
||||||
|
"For a Factor instance to be able to send and receive distributed "
|
||||||
|
"concurrency messages it must first have " { $link start-node } " called."
|
||||||
|
$nl
|
||||||
|
"In one factor instance call " { $link start-node } " with the port 9000, "
|
||||||
|
"and in another with the port 9001."
|
||||||
|
$nl
|
||||||
|
"In this example the Factor instance associated with port 9000 will run "
|
||||||
|
"a thread that sits receiving messages and printing the received message "
|
||||||
|
"in the listener. The code to start the thread is: "
|
||||||
|
{ $examples
|
||||||
|
{ $unchecked-example
|
||||||
|
": log-message ( -- ) receive . flush log-message ;"
|
||||||
|
"[ log-message ] \"logger\" spawn dup name>> register-remote-thread"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"This spawns a thread waits for the messages. It registers that thread as a "
|
||||||
|
"able to be accessed remotely using " { $link register-remote-thread } "."
|
||||||
|
$nl
|
||||||
|
"The second Factor instance, the one associated with port 9001, can send "
|
||||||
|
"messages to the 'logger' thread by name:"
|
||||||
|
{ $examples
|
||||||
|
{ $unchecked-example
|
||||||
|
"USING: io.sockets concurrency.messaging concurrency.distributed ;"
|
||||||
|
"\"hello\" \"127.0.0.1\" 9000 <inet4> \"logger\" <remote-thread> send"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"The " { $link send } " word is used to send messages to other threads. If an "
|
||||||
|
"instance of " { $link remote-thread } " is provided instead of a thread then "
|
||||||
|
"the message is marshalled to the named thread on the given machine using the "
|
||||||
|
{ $vocab-link "serialize" } " vocabulary."
|
||||||
|
$nl
|
||||||
|
"Running this code should show the message \"hello\" in the first Factor "
|
||||||
|
"instance."
|
||||||
|
$nl
|
||||||
|
"It is also possible to use " { $link send-synchronous } " to receive a "
|
||||||
|
"response to a distributed message. When an instance of " { $link thread } " "
|
||||||
|
"is marshalled it is converted into an instance of " { $link remote-thread }
|
||||||
|
". The receiver of this can use it as the target of a " { $link send }
|
||||||
|
" or " { $link reply } " call." ;
|
||||||
|
|
||||||
ARTICLE: "concurrency.distributed" "Distributed message passing"
|
ARTICLE: "concurrency.distributed" "Distributed message passing"
|
||||||
"The " { $vocab-link "concurrency.distributed" } " implements transparent distributed message passing, inspired by Erlang and Termite."
|
"The " { $vocab-link "concurrency.distributed" } " implements transparent distributed message passing, inspired by Erlang and Termite."
|
||||||
{ $subsections start-node }
|
{ $subsections start-node }
|
||||||
"Instances of " { $link thread } " can be sent to remote processes, at which point they are converted to objects holding the thread ID and the current node's host name:"
|
"Instances of " { $link thread } " can be sent to remote threads, at which point they are converted to objects holding the thread ID and the current node's host name:"
|
||||||
{ $subsections remote-process }
|
{ $subsections remote-thread }
|
||||||
"The " { $vocab-link "serialize" } " vocabulary is used to convert Factor objects to byte arrays for transfer over a socket." ;
|
"The " { $vocab-link "serialize" } " vocabulary is used to convert Factor objects to byte arrays for transfer over a socket."
|
||||||
|
{ $subsections "concurrency.distributed.example" } ;
|
||||||
|
|
||||||
|
|
||||||
ABOUT: "concurrency.distributed"
|
ABOUT: "concurrency.distributed"
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,14 @@ IN: concurrency.distributed.tests
|
||||||
[ ] [
|
[ ] [
|
||||||
[
|
[
|
||||||
receive first2 [ 3 + ] dip send
|
receive first2 [ 3 + ] dip send
|
||||||
"thread-a" unregister-process
|
"thread-a" unregister-remote-thread
|
||||||
] "Thread A" spawn
|
] "Thread A" spawn
|
||||||
"thread-a" swap register-process
|
"thread-a" register-remote-thread
|
||||||
] unit-test
|
] unit-test
|
||||||
|
|
||||||
[ 8 ] [
|
[ 8 ] [
|
||||||
5 self 2array
|
5 self 2array
|
||||||
"thread-a" test-node <remote-process> send
|
test-node "thread-a" <remote-thread> send
|
||||||
|
|
||||||
receive
|
receive
|
||||||
] unit-test
|
] unit-test
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,32 @@
|
||||||
! Copyright (C) 2005 Chris Double. All Rights Reserved.
|
! Copyright (C) 2005 Chris Double. All Rights Reserved.
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: serialize sequences concurrency.messaging threads io
|
USING: serialize sequences concurrency.messaging threads io
|
||||||
io.servers.connection io.encodings.binary
|
io.servers.connection io.encodings.binary assocs init
|
||||||
arrays namespaces kernel accessors ;
|
arrays namespaces kernel accessors ;
|
||||||
FROM: io.sockets => host-name <inet> with-client ;
|
FROM: io.sockets => host-name <inet> with-client ;
|
||||||
IN: concurrency.distributed
|
IN: concurrency.distributed
|
||||||
|
|
||||||
|
<PRIVATE
|
||||||
|
|
||||||
|
: registered-remote-threads ( -- hash )
|
||||||
|
\ registered-remote-threads get-global ;
|
||||||
|
|
||||||
|
PRIVATE>
|
||||||
|
|
||||||
|
: register-remote-thread ( thread name -- )
|
||||||
|
registered-remote-threads set-at ;
|
||||||
|
|
||||||
|
: unregister-remote-thread ( name -- )
|
||||||
|
registered-remote-threads delete-at ;
|
||||||
|
|
||||||
|
: get-remote-thread ( name -- thread )
|
||||||
|
dup registered-remote-threads at [ ] [ thread ] ?if ;
|
||||||
|
|
||||||
SYMBOL: local-node
|
SYMBOL: local-node
|
||||||
|
|
||||||
: handle-node-client ( -- )
|
: handle-node-client ( -- )
|
||||||
deserialize
|
deserialize
|
||||||
[ first2 get-process send ] [ stop-this-server ] if* ;
|
[ first2 get-remote-thread send ] [ stop-this-server ] if* ;
|
||||||
|
|
||||||
: <node-server> ( addrspec -- threaded-server )
|
: <node-server> ( addrspec -- threaded-server )
|
||||||
binary <threaded-server>
|
binary <threaded-server>
|
||||||
|
|
@ -24,20 +40,26 @@ SYMBOL: local-node
|
||||||
: start-node ( port -- )
|
: start-node ( port -- )
|
||||||
host-name over <inet> (start-node) ;
|
host-name over <inet> (start-node) ;
|
||||||
|
|
||||||
TUPLE: remote-process id node ;
|
TUPLE: remote-thread node id ;
|
||||||
|
|
||||||
C: <remote-process> remote-process
|
C: <remote-thread> remote-thread
|
||||||
|
|
||||||
: send-remote-message ( message node -- )
|
: send-remote-message ( message node -- )
|
||||||
binary [ serialize ] with-client ;
|
binary [ serialize ] with-client ;
|
||||||
|
|
||||||
M: remote-process send ( message thread -- )
|
M: remote-thread send ( message thread -- )
|
||||||
[ id>> 2array ] [ node>> ] bi
|
[ id>> 2array ] [ node>> ] bi
|
||||||
send-remote-message ;
|
send-remote-message ;
|
||||||
|
|
||||||
M: thread (serialize) ( obj -- )
|
M: thread (serialize) ( obj -- )
|
||||||
id>> local-node get-global <remote-process>
|
id>> [ local-node get-global ] dip <remote-thread>
|
||||||
(serialize) ;
|
(serialize) ;
|
||||||
|
|
||||||
: stop-node ( node -- )
|
: stop-node ( node -- )
|
||||||
f swap send-remote-message ;
|
f swap send-remote-message ;
|
||||||
|
|
||||||
|
[
|
||||||
|
H{ } clone \ registered-remote-threads set-global
|
||||||
|
] "remote-thread-registry" add-init-hook
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
! Copyright (C) 2006 Chris Double.
|
! Copyright (C) 2006 Chris Double.
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: help.syntax help.markup concurrency.messaging.private
|
USING: help.syntax help.markup
|
||||||
threads kernel arrays quotations strings ;
|
threads kernel arrays quotations strings ;
|
||||||
IN: concurrency.messaging
|
IN: concurrency.messaging
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,21 +68,3 @@ M: cannot-send-synchronous-to-self summary
|
||||||
receive [
|
receive [
|
||||||
data>> swap call
|
data>> swap call
|
||||||
] keep reply-synchronous ; inline
|
] keep reply-synchronous ; inline
|
||||||
|
|
||||||
<PRIVATE
|
|
||||||
|
|
||||||
: registered-processes ( -- hash )
|
|
||||||
\ registered-processes get-global ;
|
|
||||||
|
|
||||||
PRIVATE>
|
|
||||||
|
|
||||||
: register-process ( name process -- )
|
|
||||||
swap registered-processes set-at ;
|
|
||||||
|
|
||||||
: unregister-process ( name -- )
|
|
||||||
registered-processes delete-at ;
|
|
||||||
|
|
||||||
: get-process ( name -- process )
|
|
||||||
dup registered-processes at [ ] [ thread ] ?if ;
|
|
||||||
|
|
||||||
\ registered-processes [ H{ } clone ] initialize
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ SYMBOL: vocab-articles
|
||||||
: contains-funky-elements? ( element -- ? )
|
: contains-funky-elements? ( element -- ? )
|
||||||
{
|
{
|
||||||
$shuffle
|
$shuffle
|
||||||
|
$complex-shuffle
|
||||||
$values-x/y
|
$values-x/y
|
||||||
$predicate
|
$predicate
|
||||||
$class-description
|
$class-description
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,8 @@ ARTICLE: "power-functions" "Powers and logarithms"
|
||||||
{ $subsections log1+ log10 }
|
{ $subsections log1+ log10 }
|
||||||
"Raising a number to a power:"
|
"Raising a number to a power:"
|
||||||
{ $subsections ^ 10^ }
|
{ $subsections ^ 10^ }
|
||||||
|
"Finding the root of a number:"
|
||||||
|
{ $subsections nth-root }
|
||||||
"Converting between rectangular and polar form:"
|
"Converting between rectangular and polar form:"
|
||||||
{ $subsections
|
{ $subsections
|
||||||
abs
|
abs
|
||||||
|
|
@ -259,6 +261,10 @@ HELP: ^
|
||||||
{ $description "Raises " { $snippet "x" } " to the power of " { $snippet "y" } ". If " { $snippet "y" } " is an integer the answer is computed exactly, otherwise a floating point approximation is used." }
|
{ $description "Raises " { $snippet "x" } " to the power of " { $snippet "y" } ". If " { $snippet "y" } " is an integer the answer is computed exactly, otherwise a floating point approximation is used." }
|
||||||
{ $errors "Throws an error if " { $snippet "x" } " and " { $snippet "y" } " are both integer 0." } ;
|
{ $errors "Throws an error if " { $snippet "x" } " and " { $snippet "y" } " are both integer 0." } ;
|
||||||
|
|
||||||
|
HELP: nth-root
|
||||||
|
{ $values { "n" integer } { "x" number } { "y" number } }
|
||||||
|
{ $description "Calculates the nth root of a number, such that " { $snippet "y^n=x" } "." } ;
|
||||||
|
|
||||||
HELP: 10^
|
HELP: 10^
|
||||||
{ $values { "x" number } { "y" number } }
|
{ $values { "x" number } { "y" number } }
|
||||||
{ $description "Raises " { $snippet "x" } " to the power of 10. If " { $snippet "x" } " is an integer the answer is computed exactly, otherwise a floating point approximation is used." } ;
|
{ $description "Raises " { $snippet "x" } " to the power of 10. If " { $snippet "x" } " is an integer the answer is computed exactly, otherwise a floating point approximation is used." } ;
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,8 @@ PRIVATE>
|
||||||
[ ^complex ]
|
[ ^complex ]
|
||||||
} cond ; inline
|
} cond ; inline
|
||||||
|
|
||||||
|
: nth-root ( n x -- y ) swap recip ^ ; inline
|
||||||
|
|
||||||
: gcd ( x y -- a d )
|
: gcd ( x y -- a d )
|
||||||
[ 0 1 ] 2dip (gcd) dup 0 < [ neg ] when ; foldable
|
[ 0 1 ] 2dip (gcd) dup 0 < [ neg ] when ; foldable
|
||||||
|
|
||||||
|
|
@ -304,4 +306,3 @@ M: real atan >float atan ; inline
|
||||||
[ [ / floor ] [ * ] bi ] unless-zero ;
|
[ [ / floor ] [ * ] bi ] unless-zero ;
|
||||||
|
|
||||||
: lerp ( a b t -- a_t ) [ over - ] dip * + ; inline
|
: lerp ( a b t -- a_t ) [ over - ] dip * + ; inline
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,56 +1,67 @@
|
||||||
USING: help.markup help.syntax debugger ;
|
USING: assocs debugger hashtables help.markup help.syntax
|
||||||
|
quotations sequences math ;
|
||||||
IN: math.statistics
|
IN: math.statistics
|
||||||
|
|
||||||
HELP: geometric-mean
|
HELP: geometric-mean
|
||||||
{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
|
{ $values { "seq" sequence } { "x" "a non-negative real number"} }
|
||||||
{ $description "Computes the geometric mean of all elements in " { $snippet "seq" } ". The geometric mean measures the central tendency of a data set that minimizes the effects of extreme values." }
|
{ $description "Computes the geometric mean of all elements in " { $snippet "seq" } ". The geometric mean measures the central tendency of a data set and minimizes the effects of extreme values." }
|
||||||
{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } geometric-mean ." "1.81712059283214" } }
|
{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } geometric-mean ." "1.81712059283214" } }
|
||||||
{ $errors "Throws a " { $link signal-error. } " (square-root of 0) if the sequence is empty." } ;
|
{ $errors "Throws a " { $link signal-error. } " (square-root of 0) if the sequence is empty." } ;
|
||||||
|
|
||||||
HELP: harmonic-mean
|
HELP: harmonic-mean
|
||||||
{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
|
{ $values { "seq" sequence } { "x" "a non-negative real number"} }
|
||||||
{ $description "Computes the harmonic mean of the elements in " { $snippet "seq" } ". The harmonic mean is appropriate when the average of rates is desired." }
|
{ $description "Computes the harmonic mean of the elements in " { $snippet "seq" } ". The harmonic mean is appropriate when the average of rates is desired." }
|
||||||
{ $notes "Positive reals only." }
|
{ $notes "Positive reals only." }
|
||||||
{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } harmonic-mean ." "6/11" } }
|
{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } harmonic-mean ." "6/11" } }
|
||||||
{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
|
{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
|
||||||
|
|
||||||
HELP: mean
|
HELP: mean
|
||||||
{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
|
{ $values { "seq" sequence } { "x" "a non-negative real number"} }
|
||||||
{ $description "Computes the arithmetic mean of all elements in " { $snippet "seq" } "." }
|
{ $description "Computes the arithmetic mean of the elements in " { $snippet "seq" } "." }
|
||||||
{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } mean ." "2" } }
|
{ $examples { $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } mean ." "2" } }
|
||||||
{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
|
{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
|
||||||
|
|
||||||
HELP: median
|
HELP: median
|
||||||
{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
|
{ $values { "seq" sequence } { "x" "a non-negative real number"} }
|
||||||
{ $description "Computes the median of " { $snippet "seq" } " by sorting the sequence from lowest value to highest and outputting the middle one. If there is an even number of elements in the sequence, the median is not unique, so the mean of the two middle values is outputted." }
|
{ $description "Computes the median of " { $snippet "seq" } " by finding the middle element of the sequence using " { $link kth-smallest } ". If there is an even number of elements in the sequence, the median is not unique, so the mean of the two middle values is output." }
|
||||||
{ $examples
|
{ $examples
|
||||||
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } median ." "2" }
|
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } median ." "2" }
|
||||||
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } median ." "2+1/2" } }
|
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } median ." "2+1/2" } }
|
||||||
{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
|
{ $errors "Throws a " { $link signal-error. } " (divide by zero) if the sequence is empty." } ;
|
||||||
|
|
||||||
HELP: range
|
HELP: range
|
||||||
{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
|
{ $values { "seq" sequence } { "x" "a non-negative real number"} }
|
||||||
{ $description "Computes the distance of the maximum and minimum values in " { $snippet "seq" } "." }
|
{ $description "Computes the difference of the maximum and minimum values in " { $snippet "seq" } "." }
|
||||||
{ $examples
|
{ $examples
|
||||||
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } range ." "2" }
|
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } range ." "2" }
|
||||||
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } range ." "3" } } ;
|
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } range ." "3" } } ;
|
||||||
|
|
||||||
|
HELP: minmax
|
||||||
|
{ $values { "seq" sequence } { "min" real } { "max" real } }
|
||||||
|
{ $description "Finds the minimum and maximum elements of " { $snippet "seq" } " in one pass." }
|
||||||
|
{ $examples
|
||||||
|
{ $example "USING: arrays math.statistics prettyprint ;"
|
||||||
|
"{ 1 2 3 } minmax 2array ."
|
||||||
|
"{ 1 3 }"
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
HELP: std
|
HELP: std
|
||||||
{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
|
{ $values { "seq" sequence } { "x" "a non-negative real number"} }
|
||||||
{ $description "Computes the standard deviation of " { $snippet "seq" } ", which is the square root of the variance. It measures how widely spread the values in a sequence are about the mean." }
|
{ $description "Computes the standard deviation of " { $snippet "seq" } ", which is the square root of the variance. It measures how widely spread the values in a sequence are about the mean." }
|
||||||
{ $examples
|
{ $examples
|
||||||
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } std ." "1.0" }
|
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } std ." "1.0" }
|
||||||
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } std ." "1.290994448735806" } } ;
|
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } std ." "1.290994448735806" } } ;
|
||||||
|
|
||||||
HELP: ste
|
HELP: ste
|
||||||
{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
|
{ $values { "seq" sequence } { "x" "a non-negative real number"} }
|
||||||
{ $description "Computes the standard error of the mean for " { $snippet "seq" } ". It's defined as the standard deviation divided by the square root of the length of the sequence, and measures uncertainty associated with the estimate of the mean." }
|
{ $description "Computes the standard error of the mean for " { $snippet "seq" } ". It's defined as the standard deviation divided by the square root of the length of the sequence, and measures uncertainty associated with the estimate of the mean." }
|
||||||
{ $examples
|
{ $examples
|
||||||
{ $example "USING: math.statistics prettyprint ;" "{ -2 2 } ste ." "2.0" }
|
{ $example "USING: math.statistics prettyprint ;" "{ -2 2 } ste ." "2.0" }
|
||||||
{ $example "USING: math.statistics prettyprint ;" "{ -2 2 2 } ste ." "1.333333333333333" } } ;
|
{ $example "USING: math.statistics prettyprint ;" "{ -2 2 2 } ste ." "1.333333333333333" } } ;
|
||||||
|
|
||||||
HELP: var
|
HELP: var
|
||||||
{ $values { "seq" "a sequence of numbers" } { "x" "a non-negative real number"} }
|
{ $values { "seq" sequence } { "x" "a non-negative real number"} }
|
||||||
{ $description "Computes the variance of " { $snippet "seq" } ". It's a measurement of the spread of values in a sequence. The larger the variance, the larger the distance of values from the mean." }
|
{ $description "Computes the variance of " { $snippet "seq" } ". It's a measurement of the spread of values in a sequence. The larger the variance, the larger the distance of values from the mean." }
|
||||||
{ $notes "If the number of elements in " { $snippet "seq" } " is 1 or less, it outputs 0." }
|
{ $notes "If the number of elements in " { $snippet "seq" } " is 1 or less, it outputs 0." }
|
||||||
{ $examples
|
{ $examples
|
||||||
|
|
@ -58,3 +69,104 @@ HELP: var
|
||||||
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } var ." "1" }
|
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 } var ." "1" }
|
||||||
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } var ." "1+2/3" } } ;
|
{ $example "USING: math.statistics prettyprint ;" "{ 1 2 3 4 } var ." "1+2/3" } } ;
|
||||||
|
|
||||||
|
|
||||||
|
HELP: histogram
|
||||||
|
{ $values
|
||||||
|
{ "seq" sequence }
|
||||||
|
{ "hashtable" hashtable }
|
||||||
|
}
|
||||||
|
{ $examples
|
||||||
|
{ $example "! Count the number of times an element appears in a sequence."
|
||||||
|
"USING: prettyprint math.statistics ;"
|
||||||
|
"\"aaabc\" histogram ."
|
||||||
|
"H{ { 97 3 } { 98 1 } { 99 1 } }"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ $description "Returns a hashtable where the keys are the elements of the sequence and the values are the number of times they appeared in that sequence." } ;
|
||||||
|
|
||||||
|
HELP: histogram*
|
||||||
|
{ $values
|
||||||
|
{ "hashtable" hashtable } { "seq" sequence }
|
||||||
|
{ "hashtable" hashtable }
|
||||||
|
}
|
||||||
|
{ $examples
|
||||||
|
{ $example "! Count the number of times the elements of two sequences appear."
|
||||||
|
"USING: prettyprint math.statistics ;"
|
||||||
|
"\"aaabc\" histogram \"aaaaaabc\" histogram* ."
|
||||||
|
"H{ { 97 9 } { 98 2 } { 99 2 } }"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ $description "Takes an existing hashtable and uses " { $link histogram } " to continue counting the number of occurences of each element." } ;
|
||||||
|
|
||||||
|
HELP: sequence>assoc
|
||||||
|
{ $values
|
||||||
|
{ "seq" sequence } { "quot" quotation } { "exemplar" "an exemplar assoc" }
|
||||||
|
{ "assoc" assoc }
|
||||||
|
}
|
||||||
|
{ $examples
|
||||||
|
{ $example "! Iterate over a sequence and increment the count at each element"
|
||||||
|
"USING: assocs prettyprint math.statistics ;"
|
||||||
|
"\"aaabc\" [ inc-at ] H{ } sequence>assoc ."
|
||||||
|
"H{ { 97 3 } { 98 1 } { 99 1 } }"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ $description "Iterates over a sequence, allowing elements of the sequence to be added to a newly created " { $snippet "assoc" } " according to the passed quotation." } ;
|
||||||
|
|
||||||
|
HELP: sequence>assoc*
|
||||||
|
{ $values
|
||||||
|
{ "assoc" assoc } { "seq" sequence } { "quot" quotation }
|
||||||
|
{ "assoc" assoc }
|
||||||
|
}
|
||||||
|
{ $examples
|
||||||
|
{ $example "! Iterate over a sequence and add the counts to an existing assoc"
|
||||||
|
"USING: assocs prettyprint math.statistics kernel ;"
|
||||||
|
"H{ { 97 2 } { 98 1 } } clone \"aaabc\" [ inc-at ] sequence>assoc* ."
|
||||||
|
"H{ { 97 5 } { 98 2 } { 99 1 } }"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ $description "Iterates over a sequence, allowing elements of the sequence to be added to an existing " { $snippet "assoc" } " according to the passed quotation." } ;
|
||||||
|
|
||||||
|
HELP: sequence>hashtable
|
||||||
|
{ $values
|
||||||
|
{ "seq" sequence } { "quot" quotation }
|
||||||
|
{ "hashtable" hashtable }
|
||||||
|
}
|
||||||
|
{ $examples
|
||||||
|
{ $example "! Count the number of times an element occurs in a sequence"
|
||||||
|
"USING: assocs prettyprint math.statistics ;"
|
||||||
|
"\"aaabc\" [ inc-at ] sequence>hashtable ."
|
||||||
|
"H{ { 97 3 } { 98 1 } { 99 1 } }"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ $description "Iterates over a sequence, allowing elements of the sequence to be added to a hashtable according to the passed quotation." } ;
|
||||||
|
|
||||||
|
ARTICLE: "histogram" "Computing histograms"
|
||||||
|
"Counting elements in a sequence:"
|
||||||
|
{ $subsections
|
||||||
|
histogram
|
||||||
|
histogram*
|
||||||
|
}
|
||||||
|
"Combinators for implementing histogram:"
|
||||||
|
{ $subsections
|
||||||
|
sequence>assoc
|
||||||
|
sequence>assoc*
|
||||||
|
sequence>hashtable
|
||||||
|
} ;
|
||||||
|
|
||||||
|
ARTICLE: "math.statistics" "Statistics"
|
||||||
|
"Computing the mean:"
|
||||||
|
{ $subsections mean geometric-mean harmonic-mean }
|
||||||
|
"Computing the median:"
|
||||||
|
{ $subsections median lower-median upper-median medians }
|
||||||
|
"Computing the mode:"
|
||||||
|
{ $subsections mode }
|
||||||
|
"Computing the standard deviation, standard error, and variance:"
|
||||||
|
{ $subsections std ste var }
|
||||||
|
"Computing the range and minimum and maximum elements:"
|
||||||
|
{ $subsections range minmax }
|
||||||
|
"Computing the kth smallest element:"
|
||||||
|
{ $subsections kth-smallest }
|
||||||
|
"Counting the frequency of occurrence of elements:"
|
||||||
|
{ $subsection "histogram" } ;
|
||||||
|
|
||||||
|
ABOUT: "math.statistics"
|
||||||
|
|
|
||||||
|
|
@ -43,3 +43,13 @@ IN: math.statistics.tests
|
||||||
[ 0 ] [ { 1 } var ] unit-test
|
[ 0 ] [ { 1 } var ] unit-test
|
||||||
[ 0.0 ] [ { 1 } std ] unit-test
|
[ 0.0 ] [ { 1 } std ] unit-test
|
||||||
[ 0.0 ] [ { 1 } ste ] unit-test
|
[ 0.0 ] [ { 1 } ste ] unit-test
|
||||||
|
|
||||||
|
[
|
||||||
|
H{
|
||||||
|
{ 97 2 }
|
||||||
|
{ 98 2 }
|
||||||
|
{ 99 2 }
|
||||||
|
}
|
||||||
|
] [
|
||||||
|
"aabbcc" histogram
|
||||||
|
] unit-test
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
! Copyright (C) 2008 Doug Coleman, Michael Judge.
|
! Copyright (C) 2008 Doug Coleman, Michael Judge.
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
! See http://factorcode.org/license.txt for BSD license.
|
||||||
USING: arrays combinators kernel math math.analysis
|
USING: arrays combinators kernel math math.functions
|
||||||
math.functions math.order sequences sorting locals
|
math.order sequences sorting locals sequences.private
|
||||||
sequences.private assocs fry ;
|
assocs fry ;
|
||||||
IN: math.statistics
|
IN: math.statistics
|
||||||
|
|
||||||
: mean ( seq -- x )
|
: mean ( seq -- x )
|
||||||
|
|
@ -33,7 +33,7 @@ IN: math.statistics
|
||||||
[ i seq nth-unsafe x < ] [ i 1 + i! ] while
|
[ i seq nth-unsafe x < ] [ i 1 + i! ] while
|
||||||
[ x j seq nth-unsafe < ] [ j 1 - j! ] while
|
[ x j seq nth-unsafe < ] [ j 1 - j! ] while
|
||||||
i j <= [
|
i j <= [
|
||||||
i j seq exchange
|
i j seq exchange-unsafe
|
||||||
i 1 + i!
|
i 1 + i!
|
||||||
j 1 - j!
|
j 1 - j!
|
||||||
] when
|
] when
|
||||||
|
|
@ -45,7 +45,8 @@ IN: math.statistics
|
||||||
k seq nth ; inline
|
k seq nth ; inline
|
||||||
|
|
||||||
: lower-median ( seq -- elt )
|
: lower-median ( seq -- elt )
|
||||||
dup dup length odd? [ midpoint@ ] [ midpoint@ 1 - ] if kth-smallest ;
|
[ ] [ ] [ length odd? ] tri
|
||||||
|
[ midpoint@ ] [ midpoint@ 1 - ] if kth-smallest ;
|
||||||
|
|
||||||
: upper-median ( seq -- elt )
|
: upper-median ( seq -- elt )
|
||||||
dup midpoint@ kth-smallest ;
|
dup midpoint@ kth-smallest ;
|
||||||
|
|
@ -54,13 +55,35 @@ IN: math.statistics
|
||||||
[ lower-median ] [ upper-median ] bi ;
|
[ lower-median ] [ upper-median ] bi ;
|
||||||
|
|
||||||
: median ( seq -- x )
|
: median ( seq -- x )
|
||||||
dup length odd? [ lower-median ] [ medians + 2 / ] if ;
|
[ ] [ length odd? ] bi [ lower-median ] [ medians + 2 / ] if ;
|
||||||
|
|
||||||
: frequency ( seq -- hashtable )
|
<PRIVATE
|
||||||
H{ } clone [ '[ _ inc-at ] each ] keep ;
|
|
||||||
|
: (sequence>assoc) ( seq quot assoc -- assoc )
|
||||||
|
[ swap curry each ] keep ; inline
|
||||||
|
|
||||||
|
PRIVATE>
|
||||||
|
|
||||||
|
: sequence>assoc* ( assoc seq quot: ( obj assoc -- ) -- assoc )
|
||||||
|
rot (sequence>assoc) ; inline
|
||||||
|
|
||||||
|
: sequence>assoc ( seq quot: ( obj assoc -- ) exemplar -- assoc )
|
||||||
|
clone (sequence>assoc) ; inline
|
||||||
|
|
||||||
|
: sequence>hashtable ( seq quot: ( obj hashtable -- ) -- hashtable )
|
||||||
|
H{ } sequence>assoc ; inline
|
||||||
|
|
||||||
|
: histogram* ( hashtable seq -- hashtable )
|
||||||
|
[ inc-at ] sequence>assoc* ;
|
||||||
|
|
||||||
|
: histogram ( seq -- hashtable )
|
||||||
|
[ inc-at ] sequence>hashtable ;
|
||||||
|
|
||||||
|
: collect-values ( seq quot: ( obj hashtable -- ) -- hash )
|
||||||
|
'[ [ dup @ ] dip push-at ] sequence>hashtable ; inline
|
||||||
|
|
||||||
: mode ( seq -- x )
|
: mode ( seq -- x )
|
||||||
frequency >alist
|
histogram >alist
|
||||||
[ ] [ [ [ second ] bi@ > ] 2keep ? ] map-reduce first ;
|
[ ] [ [ [ second ] bi@ > ] 2keep ? ] map-reduce first ;
|
||||||
|
|
||||||
: minmax ( seq -- min max )
|
: minmax ( seq -- min max )
|
||||||
|
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
IN: histogram
|
|
||||||
USING: help.markup help.syntax sequences hashtables quotations assocs ;
|
|
||||||
|
|
||||||
HELP: histogram
|
|
||||||
{ $values
|
|
||||||
{ "seq" sequence }
|
|
||||||
{ "hashtable" hashtable }
|
|
||||||
}
|
|
||||||
{ $examples
|
|
||||||
{ $example "! Count the number of times an element appears in a sequence."
|
|
||||||
"USING: prettyprint histogram ;"
|
|
||||||
"\"aaabc\" histogram ."
|
|
||||||
"H{ { 97 3 } { 98 1 } { 99 1 } }"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ $description "Returns a hashtable where the keys are the elements of the sequence and the values are the number of times they appeared in that sequence." } ;
|
|
||||||
|
|
||||||
HELP: histogram*
|
|
||||||
{ $values
|
|
||||||
{ "hashtable" hashtable } { "seq" sequence }
|
|
||||||
{ "hashtable" hashtable }
|
|
||||||
}
|
|
||||||
{ $examples
|
|
||||||
{ $example "! Count the number of times the elements of two sequences appear."
|
|
||||||
"USING: prettyprint histogram ;"
|
|
||||||
"\"aaabc\" histogram \"aaaaaabc\" histogram* ."
|
|
||||||
"H{ { 97 9 } { 98 2 } { 99 2 } }"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ $description "Takes an existing hashtable and uses " { $link histogram } " to continue counting the number of occurences of each element." } ;
|
|
||||||
|
|
||||||
HELP: sequence>assoc
|
|
||||||
{ $values
|
|
||||||
{ "seq" sequence } { "quot" quotation } { "exemplar" "an exemplar assoc" }
|
|
||||||
{ "assoc" assoc }
|
|
||||||
}
|
|
||||||
{ $examples
|
|
||||||
{ $example "! Iterate over a sequence and increment the count at each element"
|
|
||||||
"USING: assocs prettyprint histogram ;"
|
|
||||||
"\"aaabc\" [ inc-at ] H{ } sequence>assoc ."
|
|
||||||
"H{ { 97 3 } { 98 1 } { 99 1 } }"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ $description "Iterates over a sequence, allowing elements of the sequence to be added to a newly created " { $snippet "assoc" } " according to the passed quotation." } ;
|
|
||||||
|
|
||||||
HELP: sequence>assoc*
|
|
||||||
{ $values
|
|
||||||
{ "assoc" assoc } { "seq" sequence } { "quot" quotation }
|
|
||||||
{ "assoc" assoc }
|
|
||||||
}
|
|
||||||
{ $examples
|
|
||||||
{ $example "! Iterate over a sequence and add the counts to an existing assoc"
|
|
||||||
"USING: assocs prettyprint histogram kernel ;"
|
|
||||||
"H{ { 97 2 } { 98 1 } } clone \"aaabc\" [ inc-at ] sequence>assoc* ."
|
|
||||||
"H{ { 97 5 } { 98 2 } { 99 1 } }"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ $description "Iterates over a sequence, allowing elements of the sequence to be added to an existing " { $snippet "assoc" } " according to the passed quotation." } ;
|
|
||||||
|
|
||||||
HELP: sequence>hashtable
|
|
||||||
{ $values
|
|
||||||
{ "seq" sequence } { "quot" quotation }
|
|
||||||
{ "hashtable" hashtable }
|
|
||||||
}
|
|
||||||
{ $examples
|
|
||||||
{ $example "! Count the number of times an element occurs in a sequence"
|
|
||||||
"USING: assocs prettyprint histogram ;"
|
|
||||||
"\"aaabc\" [ inc-at ] sequence>hashtable ."
|
|
||||||
"H{ { 97 3 } { 98 1 } { 99 1 } }"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{ $description "Iterates over a sequence, allowing elements of the sequence to be added to a hashtable according to the passed quotation." } ;
|
|
||||||
|
|
||||||
ARTICLE: "histogram" "Computing histograms"
|
|
||||||
"Counting elements in a sequence:"
|
|
||||||
{ $subsections
|
|
||||||
histogram
|
|
||||||
histogram*
|
|
||||||
}
|
|
||||||
"Combinators for implementing histogram:"
|
|
||||||
{ $subsections
|
|
||||||
sequence>assoc
|
|
||||||
sequence>assoc*
|
|
||||||
sequence>hashtable
|
|
||||||
} ;
|
|
||||||
|
|
||||||
ABOUT: "histogram"
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
IN: histogram.tests
|
|
||||||
USING: help.markup help.syntax tools.test histogram ;
|
|
||||||
|
|
||||||
[
|
|
||||||
H{
|
|
||||||
{ 97 2 }
|
|
||||||
{ 98 2 }
|
|
||||||
{ 99 2 }
|
|
||||||
}
|
|
||||||
] [
|
|
||||||
"aabbcc" histogram
|
|
||||||
] unit-test
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
! Copyright (C) 2009 Doug Coleman.
|
|
||||||
! See http://factorcode.org/license.txt for BSD license.
|
|
||||||
USING: kernel sequences assocs fry ;
|
|
||||||
IN: histogram
|
|
||||||
|
|
||||||
<PRIVATE
|
|
||||||
|
|
||||||
: (sequence>assoc) ( seq quot assoc -- assoc )
|
|
||||||
[ swap curry each ] keep ; inline
|
|
||||||
|
|
||||||
PRIVATE>
|
|
||||||
|
|
||||||
: sequence>assoc* ( assoc seq quot: ( obj assoc -- ) -- assoc )
|
|
||||||
rot (sequence>assoc) ; inline
|
|
||||||
|
|
||||||
: sequence>assoc ( seq quot: ( obj assoc -- ) exemplar -- assoc )
|
|
||||||
clone (sequence>assoc) ; inline
|
|
||||||
|
|
||||||
: sequence>hashtable ( seq quot: ( obj hashtable -- ) -- hashtable )
|
|
||||||
H{ } sequence>assoc ; inline
|
|
||||||
|
|
||||||
: histogram* ( hashtable seq -- hashtable )
|
|
||||||
[ inc-at ] sequence>assoc* ;
|
|
||||||
|
|
||||||
: histogram ( seq -- hashtable )
|
|
||||||
[ inc-at ] sequence>hashtable ;
|
|
||||||
|
|
||||||
: collect-values ( seq quot: ( obj hashtable -- ) -- hash )
|
|
||||||
'[ [ dup @ ] dip push-at ] sequence>hashtable ; inline
|
|
||||||
|
|
@ -9,10 +9,6 @@ HELP: gammaln
|
||||||
{ $values { "x" number } { "gamma[x]" number } }
|
{ $values { "x" number } { "gamma[x]" number } }
|
||||||
{ $description "An alternative to " { $link gamma } " when gamma(x)'s range varies too widely." } ;
|
{ $description "An alternative to " { $link gamma } " when gamma(x)'s range varies too widely." } ;
|
||||||
|
|
||||||
HELP: nth-root
|
|
||||||
{ $values { "n" integer } { "x" number } { "y" number } }
|
|
||||||
{ $description "Calculates the nth root of a number, such that " { $snippet "y^n=x" } "." } ;
|
|
||||||
|
|
||||||
HELP: exp-int
|
HELP: exp-int
|
||||||
{ $values { "x" number } { "y" number } }
|
{ $values { "x" number } { "y" number } }
|
||||||
{ $description "Exponential integral function." }
|
{ $description "Exponential integral function." }
|
||||||
|
|
|
||||||
|
|
@ -56,9 +56,6 @@ PRIVATE>
|
||||||
[ abs gammaln-lanczos6 ] keep dup 0 > [ drop ] [ gamma-neg ] if
|
[ abs gammaln-lanczos6 ] keep dup 0 > [ drop ] [ gamma-neg ] if
|
||||||
] if ;
|
] if ;
|
||||||
|
|
||||||
: nth-root ( n x -- y )
|
|
||||||
swap recip ^ ;
|
|
||||||
|
|
||||||
! Forth Scientific Library Algorithm #1
|
! Forth Scientific Library Algorithm #1
|
||||||
!
|
!
|
||||||
! Evaluates the Real Exponential Integral,
|
! Evaluates the Real Exponential Integral,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue