Showing posts with label scientific. Show all posts
Showing posts with label scientific. Show all posts

Friday, 27 September 2013

Roman-Arabic numeral converter

Today script is simple but efficient, is a Roman to Arabic (our common) numeral, it converts in both directions:

Roman 10
== "X"
>> Roman 115
== "CXV"
>> Roman 418
== "CDXVIII"
>> Roman "XIV"
== 14
>> Roman "XXIV"
== 24
>> Roman "IX"
== 9
>> Roman "LXXXI"
== 81
>> Roman "MCMLII"
== 1952
>> Roman "MMI"
== 2001
>> Roman "MMMCMXCIX"
== 3999
>> Roman 9
== "IX"
>> Roman 81
== "LXXXI"
>> Roman 1952
== "MCMLII"
>> Roman 2001
== "MMI"
>> Roman 3999
== "MMMCMXCIX"


Here is the source code:
REBOL [
    Title: "Roman"
    Date: 3-Jul-2002
    Name: 'Roman
    Version: 1.0.0
    File: %roman.r
    Author: "Andrew Martin"
    Purpose: "Converts a Roman numeral to Arabic and reverse!"
    eMail: Al.Bri@xtra.co.nz
    Web: http://valley.150m.com
    Acknowledgements: {Christian "CHE" Ensel}
]
Roman: function [
    {Converts a Roman numeral to Arabic and reverse!
    Returns 'none if it can't convert the number.}

    [catch]
    Number [string! integer!] {The Roman "MMMCMXCIX" or Arabic 3999 number to convert.}
    ][Roman-Arabic Result ][
    throw-on-error [
        Roman-Arabic: compose [
            M   1000
            CM   (-100 + 1000)
            D   500
            CD   (-100 + 500)
            C   100
            XC   (-10 + 100)
            L   50
            XL   (-10 + 50)
            X   10
            IX   (-1 + 10)
            V   5
            IV   (-1 + 5)
            I   1
            ]
        either string? Number [
            Result: 0
            if not parse/all Number [
                0 3 ["M" (Result: Result + Roman-Arabic/M)]
                opt [
                    "CM" (Result: Result + Roman-Arabic/CM)
                    | "D" (Result: Result + Roman-Arabic/D)
                    | "CD" (Result: Result + Roman-Arabic/CD)
                    ]
                0 3 ["C" (Result: Result + Roman-Arabic/C)]
                opt [
                    "XC" (Result: Result + Roman-Arabic/XC)
                    | "L" (Result: Result + Roman-Arabic/L)
                    | "XL" (Result: Result + Roman-Arabic/XL)
                    ]
                0 3 ["X" (Result: Result + Roman-Arabic/X)]
                opt [
                    "IX" (Result: Result + Roman-Arabic/IX)
                    | "V" (Result: Result + Roman-Arabic/V)
                    | "IV" (Result: Result + Roman-Arabic/IV)
                    ]
                0 3 ["I" (Result: Result + Roman-Arabic/I)]
                end
                ][Result: none ]
            ][
            if all [0 <= Number Number <= 3999] [
                Result: make string! 10
                foreach [Roman Arabic] Roman-Arabic [
                    while [Arabic <= Number][
                        append Result Roman
                        Number: Number - Arabic
                        ]
                    ]
                ]
            ]
        Result
        ]
    ]

Tuesday, 10 September 2013

Neural network

What is a neural network? You could read an answer on http://en.wikipedia.org/wiki/Neural_network, but in simple words is a software that produce an answer, but the calculus behind the result is very complex. or read and try the following script:



Here is the source code:

REBOL [
Title: "Simple Backprop Neural Net"
Date: 18-Sep-2003
File: %bp.r
Author: "Karl Lewin and Francois Jouen for graphical implementation"
Purpose: {
This is pretty much a straight translation from python
to REBOL of Neil Schemenauer's bpnn.py
There are probably some places where it could be changed
to be more REBOL friendly but I'm not fluent enough to
know for sure.
}
History: "18-Sep-2003 - Initial Translation from bpnn.py"
"18-Jun-2005 - Graphical Version"
]
; calculate a random number where: a <= rand < b
rand: func [a b] [(b - a) * ((random 10000) / 10000) + a]
; Make a matrix
makeMatrix: func [I J /fill f] [
if not fill [f: 0.0]
array/initial reduce [I J] f
]
NN: func [p_ni [integer!] p_nh [integer!] p_no [integer!]] [
make object! [
; number of input, hidden, and output nodes
ni: p_ni + 1
nh: p_nh
no: p_no
; activations for nodes
ai: array/initial ni 1.0
ah: array/initial nh 1.0
ao: array/initial no 1.0
; create weights
wi: makeMatrix ni nh
wo: makeMatrix nh no
; set them to random values
foreach elo wi [loop length? elo [elo: change/part elo rand -2 2 1]]
foreach elo wo [loop length? elo [elo: change/part elo rand -2 2 1]]
; last change in weights for momentum
ci: makeMatrix ni nh
co: makeMatrix nh no
update: func [inputs /local i j sum] [
; input activations
repeat i (self/ni - 1) [poke self/ai i inputs/:i]
; hidden activations
repeat j self/nh [
sum: 0
repeat i self/ni [sum: sum + (self/ai/:i * self/wi/:i/:j)]
poke self/ah j 1 / (1 + (EXP - sum))
]
; output activations
repeat j self/no [
sum: 0
repeat i self/nh [sum: sum + (self/ah/:i * self/wo/:i/:j)]
poke self/ao j 1 / (1 + (EXP - sum))
]
self/ao
]
backprop: func [targets N M /local i j k sum chnge o_deltas h_deltas ao error] [
; calculate error terms for output
o_deltas: array/initial self/no 0
repeat k self/no [
ao: self/ao/:k
poke o_deltas k ao * (1 - ao) * (targets/:k - ao)
]
; calculate error terms for hidden
h_deltas: array/initial self/nh 0
repeat j self/nh [
sum: 0.0
repeat k self/no [sum: sum + (o_deltas/:k * self/wo/:j/:k)]
poke h_deltas j (self/ah/:j * (1 - self/ah/:j) * sum)
]
; update output weights
repeat j self/nh [
repeat k self/no [
chnge: o_deltas/:k * self/ah/:j
poke self/wo/:j k (self/wo/:j/:k + (N * chnge) + (M * self/co/:j/:k))
poke self/co/:j k chnge
]
]
; update hidden weights
repeat i self/ni [
repeat j self/nh [
chnge: h_deltas/:j * self/ai/:i
poke self/wi/:i j (self/wi/:i/:j + (N * chnge) + (M * self/ci/:i/:j))
poke self/ci/:i j chnge
]
]
; calculate error
error: 0
repeat k self/no [error: error + (lr * ((targets/:k - self/ao/:k) ** 2))]
error
]
test: func [patterns /local p] [
clear tt/text
append tt/text join rule/text newline
foreach p patterns [rs: self/update(p/1) append tt/text mold p
append tt/text newline
append tt/text rejoin [p/1 "-->" round first rs]
append tt/text newline
show tt
]
]
train: func [patterns iterations /local i error] [
repeat i iterations [
error: 0
foreach p patterns [
self/update p/1
error: error + self/backprop p/2 lr mf ; 0.5 = learning rate, 0.1 = momentum factor
]
if (i // 100) = 0 [result/text: join i [ ": error: " error] show result
show_training error]
]
result/text: "Training done" show [result visu]
]
]
]
Set_Pattern: does [
switch rule/text [
"XOR" [ change second first pat 0 change second second pat 1 change second third pat 1 change second fourth pat 0]
"AND" [change second first pat 0 change second second pat 0 change second third pat 0 change second fourth pat 1]
"OR" [change second first pat 0 change second second pat 1 change second third pat 1 change second fourth pat 1]
]
]
Fix_pattern: does [
pat: [
[[0 0] [0]]
[[0 1] [1]]
[[1 0] [1]]
[[1 1] [0]]
]
a: NN 2 3 1 ; 2 input, 3 hidden, 1 output
]
Fix_Pattern
lr: 0.5
mf: 0.1
;0.5 = learning rate, 0.1 = momentum factor

x: 0
col: red
n: 2000
Clear_Screen: does [
clear tt/text
x: 0
plot: copy [pen col spline]
append clear visu/effect reduce ['grid 100x20 blue 'draw plot]
show [visu tt]
]
show_training: func [val] [
tmp: n / 100
either x = 0 [pas: 1]
[pas: round (600 / tmp)]
x: x + pas
y: 170 - (val * 150)
append plot to-pair compose [(x) (y)]
show visu
]
ParaWin: Layout [
origin 0x0
space 5x5
across
at 5x5 Text 150 left "Sample" nt: field 50 to-string n [if error? try [n: to-integer nt/text] [n: 2000]]
at 5x30 text 150 "Learning rate" lrf: field 50 to-string lr [if error? try [lr: to-decimal lrf/text] [lr: 0.5]]
at 5x55 text 150 "Momentum Factor" mff: field 50 to-string mf [if error? try [mf: to-decimal mff/text] [mf: 0.1]]
at 5x80 text 150 "Learning rule" rule: choice silver 50 "XOR" "AND" "OR" [Set_Pattern Fix_pattern]
at 90x110 btn "Close" [unview/only Parawin]
]
win: layout [
origin 0x0
space 2x5
across
at 0x5
btn "Train Network" [clear result/text clear_screen
a/train pat n
a/test pat
]
result: info 280
btn "Reset Learning" [Fix_pattern clear_screen]
btn "Neural Net Configuration" [view/new center-face ParaWin]
at 602x5 btn 100 "Quit" [Quit]
at 0x30 visu: box 600x200 green frame blue
tt: info 100x200
]
view center-face win

Friday, 30 August 2013

The world's smallest spreadsheet program

Mr. Carl Sassenrath is always a genius in coding, look this spreadsheet program:




the source code is only 70 lines!!!! He probably wrote it in 2 minutes...

Here is the source:

REBOL [
    Title: "Rebocalc"
    Date: 19-Jun-2001
    Version: 1.0.0
    File: %rebocalc.r
    Author: "Carl Sassenrath"
    Purpose: {The world's smallest spreadsheet program, but very powerful.}
    Email: carl@rebol.com
]
csize: 100x20
max-x: 8
max-y: 16
pane: []
xy: csize / 2 + 1 * 1x0
yx: csize + 1 * 0x1
layout [
    cell:   field csize edge none [enter face   compute   face/para/scroll: 0x0]
    label: text csize white black bold center
]
;--Headings:
char: #"A"
repeat x max-x [
    append pane make label [offset: xy text: char]
    set in last pane 'offset xy
    xy: csize + 1 * 1x0 + xy
    char: char + 1
]
repeat y max-y [
    append pane make label [offset: yx text: y size: csize * 1x2 / 2]
    yx: csize + 1 * 0x1 + yx
]
xy: csize * 1x2 / 2 + 1
;--Cells:
cells: tail pane
repeat y max-y [
    char: #"A"
    repeat x max-x [
        v: to-word join char y
        set v none
        char: char + 1
        append pane make cell [offset: xy text: none var: v formula: none]
        xy: csize + 1 * 1x0 + xy
    ]
    xy: csize * 1x2 / 2 + 1 + (xy * 0x1)
]
enter: func [face /local data] [
    if empty? face/text [exit]
    set face/var face/text
    data: either face/text/1 = #"=" [next face/text][face/text]
    if error? try [data: load data] [exit]
    if find [integer! decimal! money! time! date! tuple! pair!] type?/word :data [set face/var data exit]
    if face/text/1 = #"=" [face/formula: :data]   ; string case falls thru
]
compute: has [blk] [
    unfocus
    foreach cell cells [
        if cell/formula [ ;probe cell/var
            if error? cell/text: try [do cell/formula] [cell/text: "ERROR!"]
            set cell/var cell/text
            show cell
        ]
    ]
]
lo: layout [
    bx: box second span? pane
    pad 55x0
    text as-is trim/auto {
        Cells can be numbers, times, money, tuples, pairs, etc.
        If a cell is not a scalar value, then it is treated as a string.
        Start formulas with the = character.   Any REBOL expression is valid.
        Remember to put spaces between each item in a formula.   Use ( ) where needed.
        Refer to cells as A1 D8 E10.   Example: =A1 + B1 * length? B8
        Example: in A1 type REBOL, in B1 type =length? a1, in C1 type =reverse copy a1
        Then: in D1 =checksum A1.   Now, change A1 to "Amazing!"
        In A2 type 1 + 2 (no =), in B2 type =A2.   Now change A2 to 3 * 4.
        Try: =(now/time) or =request-date or =checksum read rejoin [http://www. A1 ".com"]
        Computation moves from top to bottom. It is non-iterative.
    }

]
bx/pane: pane
view lo

Friday, 2 August 2013

Periodic Table

The script showed today produce a periodic table, you can click on an element to see properties and electrons disposition. It's amazing!


Here is the source:
REBOL [
    Title: "periodic table"
    File: %periodictable.r
    Author: "Brian Tiffin"
    Date: 14-Jan-2007
    Version: 0.9.4
    Purpose: {Display a periodic table of the elements as REBOL buttons}
    History: [
            0.9.4 28-Jul-2007 btiffin "Added close button, experiment with plugin header field"
        0.9.3 14-Jan-2007 btiffin "Idea for a draw effect generator from the orbits block..."
        0.9.2 13-Jan-2007 btiffin "first addition - added seperate color for lanthanides and actinides, professionalized 'help about' title"
        0.9.1 13-Jan-2007 btiffin "first correction - comment on elements missed weight and orbits"
        0.9.0 13-Jan-2007 btiffin "First cut - mistakes non-zero probable"
    ]
        license: GPL
]
; Define states as text color
gas: :white
liquid: :blue
solid: :black
; Define chemical series as button color
nonmetal: :green
alkali-metal: :blue
alkaline-earth-metal: :red
transition-metal: :yellow
metalloid: :magenta
halogen: :orange
poor-metal: sky
noble: :gold
lanthanide: :pink
actinide: :papaya
; Define the elements; Number, Symbol, Name, Group and period, chemical series, state at 0 celcius 1 atmosphere weight orbits
;     Group and period are a pair, with the pop-outs set to row (period) 9 and 10.   Groups run 1 to 18.
elements: [
    1 H Hydrogen 1x1 nonmetal gas 1.00794 [1]
    2 He Helium 18x1 noble gas 4.002602 [2]
    3 Li Lithium 1x2 alkali-metal solid 6.941 [2 1]
    4 Be Beryllium 2x2 alkaline-earth-metal solid 9.01218 [2 2]
    5 B Boron 13x2 metalloid solid 10.811 [2 3]
    6 C Carbon 14x2 nonmetal solid 12.011 [2 4]
    7 N Nitrogen 15x2 nonmetal gas 14.00674 [2 5]
    8 O Oxygen 16x2 nonmetal gas 15.9994 [2 6]
    9 F Fluorine 17x2 halogen gas 18.998403 [2 7]
    10 Ne Neon 18x2 noble gas 20.1797 [2 8]
    11 Na Sodium 1x3 alkali-metal solid 22.989768 [2 8 1]
    12 Mg Magnesium 2x3 alkaline-earth-metal solid 24.305 [2 8 2]
    13 Al Aluminum 13x3 poor-metal solid 26.981539 [2 8 3]
    14 Si Silicon 14x3 metalloid solid 28.0855 [2 8 4]
    15 P Phosphorus 15x3 nonmetal solid 30.973762 [2 8 5]
    16 S Sulphur 16x3 nonmetal solid 32.066 [2 8 6]
    17 Cl Chlorine 17x3 halogen gas 35.4527 [2 8 7]
    18 Ar Argon 18x3 noble gas 39.948 [2 8 8]
    19 K Potassium 1x4 alkali-metal solid 39.0983 [2 8 8 1]
    20 Ca Calcium 2x4 alkaline-earth-metal solid 40.078 [2 8 8 2]
    21 Sc Scandium 3x4 transition-metal solid 44.95591 [2 8 9 2]
    22 Ti Titanium 4x4 transition-metal solid 47.88 [2 8 10 2]
    23 V Vanadium 5x4 transition-metal solid 50.9415 [2 8 11 2]
    24 Cr Chromium 6x4 transition-metal solid 51.9961 [2 8 13 1]
    25 Mn Manganese 7x4 transition-metal solid 54.93805 [2 8 13 2]
    26 Fe Iron 8x4 transition-metal solid 55.847 [2 8 14 2]
    27 Co Cobalt 9x4 transition-metal solid 58.9332 [2 8 15 2]
    28 Ni Nickel 10x4 transition-metal solid 58.6934 [2 8 16 2]
    29 Cu Copper 11x4 transition-metal solid 63.546 [2 8 18 1]
    30 Zn Zinc 12x4 transition-metal solid 65.39 [2 8 18 2]
    31 Ga Gallium 13x4 poor-metal solid 69.723 [2 8 18 3]
    32 Ge Germanium 14x4 metalloid solid 72.61 [2 8 18 4]
    33 As Arsenic 15x4 metalloid solid 74.92159 [2 8 18 5]
    34 Se Selenium 16x4 nonmetal solid 78.96 [2 8 18 6]
    35 Br Bromine 17x4 halogen liquid 79.904 [2 8 18 7]
    36 Kr Krypton 18x4 noble gas 83.8 [2 8 18 8]
    37 Rb Rubidium 1x5 alkali-metal solid 85.4678 [2 8 18 8 1]
    38 Sr Strontium 2x5 alkaline-earth-metal solid 87.62 [2 8 18 8 2]
    39 Y Yttrium 3x5 transition-metal solid 88.90585 [2 8 18 9 2]
    40 Zr Zirconium 4x5 transition-metal solid 91.224 [2 8 18 10 2]
    41 Nb Niobium 5x5 transition-metal solid 92.90638 [2 8 18 12 1]
    42 Mo Molybdenum 6x5 transition-metal solid 95.94 [2 8 18 13 1]
    43 Tc Technetium 7x5 transition-metal solid 97.9072 [2 8 18 13 2]
    44 Ru Ruthenium 8x5 transition-metal solid 101.07 [2 8 18 15 1]
    45 Rh Rhodium 9x5 transition-metal solid 102.9055 [2 8 18 16 1]
    46 Pd Palladium 10x5 transition-metal solid 106.42 [2 8 18 18 0]
    47 Ag Silver 11x5 transition-metal solid 107.8682 [2 8 18 18 1]
    48 Cd Cadmium 12x5 transition-metal solid 112.411 [2 8 18 18 2]
    49 In Indium 13x5 poor-metal solid 114.818 [2 8 18 18 3]
    50 Sn Tin 14x5 poor-metal solid 118.71 [2 8 18 18 4]
    51 Sb Antimony 15x5 metalloid solid 121.760 [2 8 18 18 5]
    52 Te Tellurium 16x5 metalloid solid 127.6 [2 8 18 18 6]
    53 I Iodine 17x5 halogen solid 126.90447 [2 8 18 18 7]
    54 Xe Xenon 18x5 noble gas 131.29 [2 8 18 18 8]
    55 Cs Cesium 1x6 alkali-metal solid 132,90543 [2 8 18 18 8 1]
    56 Ba Barium 2x6 alkaline-earth-metal solid 137.327 [2 8 18 18 8 2]
    57 La Lanthanum 3x9 lanthanide solid 138.9055 [2 8 18 18 9 2]
    58 Ce Cerium 4x9 lanthanide solid 140.115 [2 8 18 20 8 2]
    59 Pr Praseodymium 5x9 lanthanide solid 140.90765 [2 8 18 21 8 2]
    60 Nd Noedymium 6x9 lanthanide solid 144.24   [2 8 18 22 8 2]
    61 Pm Promethium 7x9 lanthanide solid 144.9127 [2 8 18 23 8 2]
    62 Sm Samarium 8x9 lanthanide solid 150.36 [2 8 18 24 8 2]
    63 Eu Europium 9x9 lanthanide solid 151.965 [2 8 18 25 8 2]
    64 Gd Gadolinium 10x9 lanthanide solid 157.25 [2 8 18 25 9 2]
    65 Tb Terbium 11x9 lanthanide solid 158.92534 [2 8 18 27 8 2]
    66 Dy Dysprosium 12x9 lanthanide solid 162.50 [2 8 18 28 8 2]
    67 Ho Holmium 13x9 lanthanide solid 164.93032 [2 8 18 29 8 2]
    68 Er Erbium 14x9 lanthanide solid 167.26 [2 8 18 30 8 2]
    69 Tm Thulium 15x9 lanthanide solid 168.93421 [2 8 18 31 8 2]
    70 Yb Ytterbium 16x9 lanthanide solid 173.04 [2 8 18 32 8 2]
    71 Lu Lutetium   17x9 lanthanide solid 174.967 [2 8 18 32 9 2]
    72 Hf Hafnium 4x6 transition-metal solid 178.49 [2 8 18 32 10 2]
    73 Ta Tantalum 5x6 transition-metal solid 180.9479 [2 8 18 32 11 2]
    74 W Tungsten 6x6 transition-metal solid 183.84 [2 8 18 32 12 2]
    75 Re Rhenium 7x6 transition-metal solid 186.207 [2 8 18 32 13 2]
    76 Os Osmium 8x6 transition-metal solid 190.23 [2 8 18 32 14 2]
    77 Ir Iridium 9x6 transition-metal solid 192.22 [2 8 18 32 15 2]
    78 Pt Platinum 10x6 transition-metal solid 195.08 [2 8 18 32 17 1]
    79 Au Gold 11x6 transition-metal solid 196.96654 [2 8 18 32 18 1]
    80 Hg Mercury 12x6 transition-metal liquid 200.59 [2 8 18 32 18 2]
    81 Tl Thallium 13x6 poor-metal solid 204.3833 [2 8 18 32 18 3]
    82 Pb Lead 14x6 poor-metal solid 207.2 [2 8 18 32 18 4]
    83 Bi Bismuth 15x6 poor-metal solid 208.98037 [2 8 18 32 18 5]
    84 Po Polonium 16x6 metalloid solid 208.9824 [2 8 18 32 18 6]
    85 At Astatine 17x6 halogen solid 209.9871 [2 8 18 32 18 7]
    86 Rn Radon 18x6 noble gas 222.0176 [2 8 18 32 18 8]
    87 Fr Francium 1x7 alkali-metal solid 223.0197 [2 8 18 32 18 8 1]
    88 Ra Radium 2x7 alkaline-earth-metal solid 226.0254 [2 8 18 32 18 8 2]
    89 Ac Actinium 3x10 actinide solid 227.0278 [2 8 18 32 18 9 2]
    90 Th Thorium 4x10 actinide solid 232.0381 [2 8 18 32 18 10 2]
    91 Pa Protactinium 5x10 actinide solid 231.03588 [2 8 18 32 20 9 2]
    92 U Uranium 6x10 actinide solid 238.0289 [2 8 18 32 21 9 2]
    93 Np Neptunium 7x10 actinide solid 237.048 [2 8 18 32 22 9 2]
    94 Pu Plutonium 8x10 actinide solid 244.0642 [2 8 18 32 24 8 2]
    95 Am Americium 9x10 actinide solid 243.0614 [2 8 18 32 25 8 2]
    96 Cm Curium 10x10 actinide solid 247.0703 [2 8 18 32 25 9 2]
    97 Bk Berkelium 11x10 actinide solid 247.0703 [2 8 18 32 26 9 2]
    98 Cf Californium 12x10 actinide solid 251.0796 [2 8 18 32 28 8 2]
    99 Es Einsteinium 13x10 actinide solid 252.083 [2 8 18 32 29 8 2]
    100 Fm Fermium 14x10 actinide solid 257.0951 [2 8 18 32 30 8 2]
    101 Md Mendelevium 15x10 actinide solid 258.1 [2 8 18 32 31 8 2]
    102 No Nobelium 16x10 actinide solid 259.1009 [2 8 18 32 32 8 2]
    103 Lr Lawrencium 17x10 actinide solid 262.11 [2 8 18 32 32 9 2]
    104 Rf Rutherfordium 4x7 transition-metal solid 261 [2 8 18 32 32 10 2]
    105 Db Dubnium 5x7 transition-metal solid 262 [2 8 18 32 32 11 2]
    106 Sg Seaborgium 6x7 transition-metal solid 266 [2 8 18 32 32 12 2]
    107 Bh Bohrium 7x7 transition-metal solid 264 [2 8 18 32 32 13 2]
    108 Hs Hassium 8x7 transition-metal solid 269 [2 8 18 32 32 14 2]
    109 Mt Meitnerium 9x7 transition-metal solid 268 [2 8 18 32 32 15 2]
    110 Ds Darmstadmium 10x7 transition-metal solid 269 [2 8 18 32 32 17 1]
    111 Rg Roentgenium 11x7 transition-metal solid 272 [2 8 18 32 32 18 1]
    112 Uub Ununbium 12x7 transition-metal liquid 277 [2 8 18 32 32 18 2]
    113 Uut Ununtrium 13x7 poor-metal solid n/a [2 8 18 32 32 18 3]
    114 Uuq Ununquadium 14x7 poor-metal solid 289   [2 8 18 32 32 18 4]
    115 Uup Ununpentium 15x7 poor-metal solid n/a [2 8 18 32 32 18 5]
    116 Uuh Ununhexium 16x7 poor-metal solid n/a [2 8 18 32 32 18 6]
    117 Uus Ununseptium 17x7 halogen solid n/a [2 8 18 32 32 18 7]
    118 Uuo Ununoctium 18x7 noble gas n/a [2 8 18 32 32 18 8]
]
; Define draw effect generator...assume going in a box 160 by 160
spins: func ["Generate draw effect circles from element orbits" orbits [block!] /local d o r x y] [
    d: copy []
    ; background
    append d [draw [fill-pen ivory   pen black   circle 80x80 80]]
    ; nucleus
    append d compose/deep [draw [fill-pen black   pen none circle 80x80 (add 2 length? orbits)   fill-pen none]]
    ; orbital rings
    for i 1 7 1 [
        append d compose/deep [draw [fill-pen none   pen black   circle 80x80 (add multiply i 10 10)]]
    ]
    ; electrons
    o: 0
    foreach e orbits [
        o: o + 1
        loop e [
            append d compose/deep [
                draw [
                    fill-pen silver pen black
                    (r: add add multiply o 10 random 5 2)
                    (x: multiply either random true [1][-1] random r)
                    (y: multiply either random true [1][-1] square-root subtract power r 2 power x 2)
                    circle (as-pair   add 80 x   add 80 y) 3
                ]
            ]
        ]
    ]
    d
]
; Build up layout
; Start with the lines that pop out the lanthanide and actinide series
;   then put up a title and the clicked info area
;   then place the generated orbit image holder
pte: [
    backdrop effect [draw [pen black line 86x126 94x189 line 86x164 93x228]]
    at 100x0
    title "Periodic Table of the Elements" [
        inform/title center-face layout compose [
            across
            image logo.gif
            vh1 (to-string system/script/header/file)
            text (to-string system/script/header/version)
            text (to-string system/script/header/date)
            text (to-string system/script/header/author)
            return
            area 484x110 para [wrap?: true] (remold [new-line/all/skip system/script/header/history true 4])
            return
            text "Chemical Series"
            return
            btn 115x22 nonmetal to-string 'nonmetal
            btn 115x22 noble to-string 'noble
            btn 115x22 alkali-metal to-string 'alkali-metal
            btn 115x22 alkaline-earth-metal to-string 'alkaline-earth-metal
            return
            btn 115x22 metalloid to-string 'metalloid
            btn 115x22 halogen to-string 'halogen
            btn 115x22 transition-metal to-string 'transition-metal
            btn 115x22 poor-metal to-string 'poor-metal
            return
            pad 123
            btn 115x22 lanthanide to-string 'lanthanide
            btn 115x22 actinide to-string 'actinide
            return
            text "State (zero degrees Celsius one atmosphere)"
            return
            btn 115x22 nonmetal "Gas" font [size: 10 color: gas]
            btn 115x22 halogen "Liquid" font [size: 10 color: liquid]
            btn 115x22 transition-metal "Solid" font [size: 10 color: solid]
            return
            bar 484
            return
            text "Help from http://en.wikipedia.org/wiki/Periodic_table, google, textbooks and gperiodic"
            return
            pad 226
            btn "Ok"
        ] "Help About...click anywhere to close"
    ]
    at 100x40
    clicked: info white 265x40 font [style: 'bold]  
    at 559x15
    img: box 161x161 effect []
        at 588x200
        logo: image logo.gif
]
; build the buttons, positioned by group and period, pop out the lanthanide/actinide block by adding some pixels
; clicking a button fills in clicked area and the img effect block
foreach [el sym name pos series state weight orbits] elements [
    blurb: reform [el sym name series state newline   weight "[" orbits "]"]
    append pte reduce [
        'at as-pair add either greater? pos/y 8 [7][0] multiply pos/x 29 multiply pos/y 21
        'btn 29x22 to-string sym series 'font compose [color: (state)] compose/deep [set-face clicked (blurb)   img/effect: [(spins orbits)]   show img]
    ]
]
append pte [at 29x199 btn "Quit" [quit]]
; and view it
view layout pte

Thursday, 11 July 2013

Mathematical Expression Dialect Parser

The following script permits you to evaluate correctly math expressions.

For example rebol way to evaluate is wrong in this case (the correct result is 50):

>> 5 + 5 * 3 ** 2
== 900.0

Rebol evaluates without sign precedence.
Fortunately using parse-expression function, any expression is correctly evaluated:

>> parse-expression "5+5*3**2"
== [add 5.0 multiply 5.0 power 3.0 2.0]
>> do parse-expression "5+5*3**2"
== 50.0


You can use the following therms:
  • **
  • abs()
  • arcos() or acos()
  • arcsin() or asin()
  • arctan() or atan()
  • cos()
  • exp()
  • log() or log10()
  • log2()
  • ln()
  • sin()
  • sqrt()
  • tan()
Here is the source:
REBOL [
    File: %parse-expression.r
    Date: 21-Mar-2011
    Title: "Mathematical Expression Dialect Parser"
    Author: "Francois Vanzeveren"
    Purpose: {Converts a mathematical expression into a block of rebol code that can be evaluated.}
    Version: 0.9.6
    History: [
        0.9.6 21-Mar-2011 "Francois Vanzeveren"
            {- The caret character (^^) can now be used for exponentiation
            - Minor improvement to ease the use of the library}
        0.9.5 16-Mar-2011 "Francois Vanzeveren"
            {- BUG FIX: The evaluation of an expression containing trigonometric functions
                caused an error.
            - BUG FIX: The exponentiation of built-in functions (e.g. "log(2)**2")caused an error.
            - New built-in functions: log2()}
        0.9.4 15-Mar-2011 "Francois Vanzeveren"
            {- BUG FIX: + - * / and // are now left-associative! Thanks to Ladislav from REBOL3
                on altme for reporting this bug!}
        0.9.3 14-Mar-2011 "Francois Vanzeveren"
            {- BUG FIX: signed numbers and signed (sub-)expressions are now properly handled.
                e.g. "+(1+x)/-(1-x)" returns [divide add 1.0 x negate subtract 1.0 x]}
        0.9.2 14-Mar-2011 "Francois Vanzeveren"
            {-IMPROVEMENT: much more readable and elegant recursive implementation.
            - BUG FIX: precedence between '**' and '*' fixed, e.g 2**3*6 will now return
                [multiply power 2 3 6] instead of [power 2 multiply 3 6]}
        0.9.1 13-Mar-2011 "Francois Vanzeveren"
            {New functions implemented:
                abs(), arcos(), acos(), arcsin(), asin(), arctan(), atan(), cos(), exp(),
                log(), ln(), sin(), sqrt(), tan()}
        0.9.0 13-Mar-2011 "Francois Vanzeveren"
            "First public release. Future versions will provide additional functions."
    ]
    TO-DO: {
        Version 1.0.0
            - expression syntax error handling to return usefull messages to the user when
            she/he makes syntax errors in the expression.
    }
    license: 'lgpl
]
parse-expression: func [
    p_expression [string!] "The expression to parse."
    /local eq retval parent-depth str tmp char
] [
    eq: trim/all lowercase copy p_expression
   
    if empty? eq [return copy []]
   
    retval: copy []
   
    ; Avons-nous à faire à un nombre?
    if tmp: attempt [to-decimal eq] [
        append retval tmp
        return retval
    ]
   
    parent-depth: 0
    str: copy ""
    char: copy ""
   
    ; We first search for operators of first precedence (+ and -)
    parse/all eq [
        any [
            "+" (
                either any [greater? parent-depth 0 empty? char found? find "+-*/(" char]
                [append str "+"]
                [
                    insert retval 'add                   ; by using 'insert...
                    append retval parse-expression str   ; and 'append, we preserve the left-associativity of the addition
                    str: copy ""
                ]
                char: copy "+"
            ) |
            "-" (
                either any [greater? parent-depth 0 empty? char found? find "+-*/(" char]
                [append str "-"]
                [
                    insert retval 'subtract             ; by using 'insert
                    append retval parse-expression str   ; and 'append, we preserve the left-associativity of the subtraction
                    str: copy ""
                ]
                char: copy "-"
            ) |
            "(" (
                append str "("
                parent-depth: add parent-depth 1
                char: copy "("
            ) |
            ")" (
                append str ")"
                parent-depth: subtract parent-depth 1
                char: copy ")"
            ) |
            copy char skip (append str char)
        ]
    ]
   
    if not empty? retval [
        append retval parse-expression str
        return retval
    ]
   
    ; We did not find operator of first precedence (+ and -)
    ; We look now for second precedence (* and /).
    parent-depth: 0
    str: copy ""
    parse/all eq [
        any [
            "**" (append str "**" char: copy "*") |
            "*" (
                either zero? parent-depth [
                    insert retval 'multiply             ; by using 'insert...
                    append retval parse-expression str   ; and 'append, we preserve the left-associativity of the multiplication
                    str: copy ""
                ] [append str "*"]
                char: copy "*"
            ) |
            "//" (
                either zero? parent-depth [
                    insert retval 'remainder             ; by using 'insert...
                    append retval parse-expression str   ; and 'append, we preserve the left-associativity of the remainder
                    str: copy ""
                ] [append str "//"]
                char: copy "/"
            ) |
            "/" (
                either zero? parent-depth [
                    insert retval 'divide               ; by using 'insert...
                    append retval parse-expression str   ; and 'append, we preserve the left-associativity of the division
                    str: copy ""
                ] [append str "/"]
                char: copy "/"
            ) |
            "(" (
                append str "("
                parent-depth: add parent-depth 1
                char: copy "("
            ) |
            ")" (
                append str ")"
                parent-depth: subtract parent-depth 1
                char: copy ")"
            ) |
            copy char skip (append str char)
        ]
    ]
   
    if not empty? retval [
        append retval parse-expression str
        return retval
    ]
   
    ; Toujours rien? Il s'agit alors:
    ; * soit d'un exposant
    ; * soit d'un opérateur unitaire
    ; * soit d'une expression entièrement comprise entre parenthèse
    ; * soit d'une inconnue
   
    ; Exposant
    parent-depth: 0
    str: copy ""
    parse/all eq [
        any [
            "**" (
                either zero? parent-depth [
                    append retval 'power
                    append retval parse-expression str
                    str: copy ""
                ] [append str "**"]
            ) |
            "^^" (
                either zero? parent-depth [
                    append retval 'power
                    append retval parse-expression str
                    str: copy ""
                ] [append str "^^"]
            ) |
            "(" (
                append str "("
                parent-depth: add parent-depth 1
            ) |
            ")" (
                append str ")"
                parent-depth: subtract parent-depth 1
            ) | copy char skip (append str char)
        ]
    ]
    if not empty? retval [
        append retval parse-expression str
        return retval
    ]
   
    ; opérateur unitaire
    parent-depth: 0
    str: copy ""
    parse/all eq [
        "+" copy str to end (
            append retval parse-expression str
            return retval
        ) |
        "-" copy str to end (
            append retval 'negate
            append retval parse-expression str
            return retval
        ) |
        "abs(" copy str to end (
            remove back tail str
            append retval 'abs
            append retval parse-expression str
            return retval
        ) |
        "arccos(" copy str to end (
            remove back tail str
            append/only retval 'arccosine/radians
            append retval parse-expression str
            return retval
        ) |
        "acos(" copy str to end (
            remove back tail str
            append/only retval 'arccosine/radians
            append retval parse-expression str
            return retval
        ) |
        "arcsin(" copy str to end (
            remove back tail str
            append/only retval 'arcsine/radians
            append retval parse-expression str
            return retval
        ) |
        "asin(" copy str to end (
            remove back tail str
            append/only retval 'arcsine/radians
            append retval parse-expression str
            return retval
        ) |
        "arctan(" copy str to end (
            remove back tail str
            append/only retval 'arctangent/radians
            append retval parse-expression str
            return retval
        ) |
        "atan(" copy str to end (
            remove back tail str
            append/only retval 'arctangent/radians
            append retval parse-expression str
            return retval
        ) |
        "cos(" copy str to end (
            remove back tail str
            append/only retval 'cosine/radians
            append retval parse-expression str
            return retval
        ) |
        "exp(" copy str to end (
            remove back tail str
            append retval 'exp
            append retval parse-expression str
            return retval
        ) |
        "log2(" copy str to end (
            remove back tail str
            append retval 'log-2
            append retval parse-expression str
            return retval
        ) |
        "log10(" copy str to end (
            remove back tail str
            append retval 'log-10
            append retval parse-expression str
            return retval
        ) |
        "log(" copy str to end (
            remove back tail str
            append retval 'log-10
            append retval parse-expression str
            return retval
        ) |
        "ln(" copy str to end (
            remove back tail str
            append retval 'log-e
            append retval parse-expression str
            return retval
        ) |
        "sin(" copy str to end (
            remove back tail str
            append/only retval 'sine/radians
            append retval parse-expression str
            return retval
        ) |
        "sqrt(" copy str to end (
            remove back tail str
            append retval 'square-root
            append retval parse-expression str
            return retval
        ) |
        "tan(" copy str to end (
            remove back tail str
            append/only retval 'tangent/radians
            append retval parse-expression str
            return retval
        )
    ]
   
    ; Expression complètement comprise entre parenthèses.
    if equal? #"(" first eq [
        remove head eq ; on supprimer la parenthèse ouvrante
        remove back tail eq ; on supprimer la parenthèse fermante
        append retval parse-expression eq
        return retval
    ]
   
    ; il ne reste plus que l'hypothèse d'une inconnue
    append retval to-word eq
    return retval
]