1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
|
(*
I 配列のデータ並列処理.(構文にwhere句が無い場合)
_foreach <id> in <arrayExp>
with <pat>
do <iteratorExp>
while <predExp>
end
与えられた <arrayExp> の配列の各要素のインデックス
を <id> に束縛し,データ並列で <iteratorExp> の値を計算し,
配列を関数的に更新する.<iteratorExp>計算の際,配列の値と
新しく計算された値を参照することが可能.この目的のために,
<iteratorExp> 式では,型
{value:int -> 'a, newValue:int -> 'a, size:int}
型の値に束縛されたパターン <pat> が参照できる.
すべてのインデックスに対するデータ並列計算が終了すると,
各インデックスに対して<predExp>式が評価され,要素がひとつでも
trueを返せば,<iteratorExp>の計算が繰り替えされる.
各要素の型は以下の通り.
<arrayExp> : 'a array
<id> : int
<pat> : {value:int -> 'a, newValue:int -> 'a, size:int}
<iteratorExp> : 'a - > 'a (この中で,<pat>が束縛される)
<predExp> : 'a - > bool (この中で,<pat>が束縛される)
各配列要素の現在の値をXiとし,新しい値をnewXiとすると,この
構文は,
newXi = <iteratorExp> (X1,..., Xn, newXj,..., newXk)
の計算を
<predExp>(X1,..., Xn, newX1,..., newXn)
がすべてfalseになるまで繰り返す構文である.ここで,newXj,..., newXk
は,newXiの計算に依存しない要素の計算.
*)
(* 配列要素へのデータ並列マップ
mapArray : ['a. ('a -> 'a) -> 'a array -> 'a array]
*)
fun mapArray f A =
_foreach id in A with {value, newValue, size}
do f (value id) while false
end
(* ガウスサイデル法
Gauss_Sidel : real -> real array array * real array -> real array
*)
fun Gauss_Sidel epsilon (a, b) =
let
val size = Array.length a
val x = Array.array(size, 0.0)
fun A (i,j) = Array.sub(Array.sub(a,i), j)
fun Ai i = Array.sub(a,i)
fun B i = Array.sub(b,i)
fun sumAX x newx i =
let
fun X j = if j < i then newx j else x j
fun each j R =
if j >= size then R
else if j = i then each (j+1) R
else each (j+1) (A(i,j) * X(j) + R)
in
each 0 0.0
end
in
_foreach i in x with {value=X, newValue=newX, size}
do (B(i) - sumAX X newX i) / A(i,i)
while Real.abs(newX(i) - X(i)) > epsilon
end
end
(*
I 再帰的データのデータ並列処理.(構文にwhere句がある場合)
_foreach <id> in <dataExp>
where <setupExp>
with <pat>
do <iteratorExp>
while <predExp>
end
1.初期化処理
ユーザが指定した<setupExp>を使い,与えられた <dataExp> データ
の各ノード(リストのnilやツリーのemptyも一ノード)を,
名前(抽象データ型indexの値)から,indexを子ノードとして含む値
へのマップ(配列)に変換する.インデックス値を名前Xiとする方程式
Xi = C(Xj,...,Xk)
がつくられる.<setupExp>は,この変換のために,
default : 'para,
initialize : ('para -> index) -> 'seq -> index.
finalize : (index -> 'para) -> index -> 'seq,
size : int
の各値(関数)を指定する.initializeは,変換後のノード値にインデクス
を割りてる 関数を受け取り,データを再帰的にたどって,再帰的データの
各ノードを変換する関数.返り値のindexは,再帰構造をたもつために使用される.
たとえば,リスト型
datatype 'a list = nil | :: of 'a * 'a list
を
*)
datatype 'a LIST = NIL | CONS of 'a * index
(*
に型に変換したい場合,以下の関数
initialize : ['a. ('a LIST -> index) -> 'a list -> index]
*)
fun initialize toLIST l =
case l of
nil => toLIST NIL
| h :: tail =>
let
val TAIL = initialize toLIST tail
in
toLIST (CONS(h, TAIL))
end
(*
をinitializeのフィールドに指定すればよい.この初期化のより,
例えば,リスト型の値 1::2::3::nilは
X1 = CONS(1, X2)
X2 = CONS(2, X3)
X3 = CONS(3, X4)
X4 = NIL
の方程式の表現に変換される.
finalizeは,indexを用いた方程式表現を,indexを展開し,もとの
データに変換すための関数である.例えば上記リストの場合,
ユーザは,以下の関数をfinilieのフィールドに指定すればよい.
finalize : ['a. (index -> 'a LIST) -> index -> 'a list]
*)
fun finalize toData i =
case toData i of
NIL => nil
| CONS(head, tail) => head :: (finalize toData tail)
(*
sizeは,再帰的データの要素数を返す関数である.ただし,リストの
nilやツリーのemptyも1と数える.リストの場合は,以下のような
定義である.
size : 'a list -> int
*)
fun size nil = 1
| size (h::t) = 1 + size t
(*
ユーザは,これら関数を用いて,<setUp>式を以下のように定義する
*)
val param =
{
default = NIL,
finalize = finalize,
initialize = initialize,
size = size
}
: {default: 'a LIST,
finalize: (index -> 'a LIST) -> index -> 'a list,
initialize: ('a LIST -> index) -> 'a list -> index,
size: 'a list -> int};
(*
2.データ並列計算.
各ノードに関して,名前を <id> に束縛し,対応する値を <iteratorExp>
によって新しい値にデータ並列で更新する.配列同様,<iteratorExp>計算の際,
配列の値と新しく計算された値を参照することが可能.
この目的のために,<iteratorExp> 式では,型
{value:index -> 'para, newValue:index -> 'para, size:int}
型の値に束縛されたパターン <pat> が参照できる.
すべてのインデックスに対するデータ並列計算が終了すると,
各インデックスに対して<predExp>式が評価され,要素がひとつでも
trueを返せば,<iteratorExp>の計算が繰り替えされる.
これは,データを表す方程式を並列変換する計算である.
たとえば,1::2::3::nil を 2::3::4::nilに変換する
計算は
X1 = CONS(1, X2)
X2 = CONS(2, X3)
X3 = CONS(3, X4)
X4 = NIL
を
X1 = CONS(2, X2)
X2 = CONS(3, X3)
X3 = CONS(4, X4)
X4 = NIL
に変換する計算であり,各ノードは,head + 1を実行すればよい.
この計算は,
*)
_foreach id in [1,2,3] where param
with {value, ...}
do case (value id) of
NIL => NIL
| CONS(i, TAIL) => CONS (i + 1, TAIL)
while false
end;
(* 勿論,高階のマップ関数
parallemMap : ['a. ('a -> 'a) -> 'a list -> 'a list]
も,単に関数抽象するだけで,定義できる.*)
fun parallemMap f L =
_foreach id in L where param
with {value, ...}
do case (value id) of
NIL => NIL
| CONS(head, TAIL) => CONS (f head, TAIL)
while false
end;
(* 変数Xiを参照し,さらに,繰り返し判定で新しい値を参照すれば,
データ並列scanなどの関数も宣言的に定義可能.そのために,
中間データ構造とparamを以下のように定義する.
*)
datatype 'a parList
= NIL
| CELL of {head : 'a, cham: index, tail: index}
fun initialize toLIST l =
case l of
nil => toLIST NIL
| h :: tail =>
let
val TAIL = initialize toLIST tail
in
toLIST (CELL {head = h, cham=TAIL, tail=TAIL})
end
fun finalize toData i =
case toData i of
NIL => nil
| CELL{head, tail,...} => head :: (finalize toData tail)
val param = {default = NIL,finalize = finalize,
initialize = initialize,
size = size}
(* この chamフィールド,データ並列計算で知られるpointer jumping
を行うための"cham pointer"の表現である.この関数は,リスト要素んp
O(log n)回のデータ並列ステップでscamを計算する関数である.
*)
fun sufixsum L =
_foreach id in L where param
with {value, newValue, ...}
do case (value id) of
NIL => NIL
| CELL {head =i, tail, cham} =>
(case value cham of
CELL {head, tail=_, cham} =>
CELL {head = i + head, cham = cham, tail = tail}
| NIL => CELL {head =i, cham = cham, tail = tail}
)
while case (newValue id) of
CELL {head =i, cham, tail} =>
(case newValue cham of NIL => false | _ => true)
| _ => false
end
|