X は 2D の点のセットで、凸包は X のすべての点を含む多角形を定義する最小の点セットであるとします。これらの点がボード上に留められたくぎであると考えた場合、くぎを紐で作った輪で囲み、たるみがなくなるまで紐を張ると、凸包ができます。この場合、凸包は紐に接しているくぎです。
以下は、20 点の凸包の例です。
凸包を計算する 1 つの方法として、QuickHull アルゴリズムを使用できます。凸包上の 2 点 (たとえば、x 軸上の最小位置と最大位置の点) を結ぶ線を引いて、残りの点を 2 つのグループに分けます。2 つのグループの凸包が求められれば、それらを結合して全体の凸包を形成することができます。線の片側にある点のなかから、線から最も遠い位置にある点を求めます。この点は凸包上にも存在します。この点と線の 2 つの端点を使用して、さらに 2 本の線を定義します。これらの線は再帰的に処理できます。これまでに作成した凸包の外側に点が 1 つだけまたは 1 つも存在しない線が見つかった場合、その線の両端と 1 つの外点 (存在する場合) が凸包内にあると言えます。
このアルゴリズムは、再帰的なステップを並列で実行することで、並列化できます。以下のコードを使用すると、タスクプログラミングモデルを使用して QuickHull アルゴリズムとパラレル QuickHull を実装できます。
QuickHull := module()
逐次アルゴリズムを並列アルゴリズムに変換するのに必要な追加コードはわずかです。これは、タスクプログラミングモデルでは、スレッドプログラミングの紛らわしくて乱雑な、バグが発生しやすいさまざまな側面が考慮されているためです。
いくつかの点を作成して QuickHull アルゴリズムを試してみましょう。
![points := table(); while numelems(points) < 1000 do p := [RandomTools:-Generate(float(range = -1 .. 1)), RandomTools:-Generate(float(range = -1 .. 1))]; if p[1]*p[1]+p[2]*p[2] < 1 then points[numelems(points)] := p end if end do; points := [entries(points, 'nolist')]; t := time[real](); QuickHull(points, plot); tSeq := time[real]()-t](/support/helpjp/helpview.aspx?si=2552/file01552/math78.png)
同じ点セットについて並列アルゴリズムを試してみます。
![t := time[real](); QuickHull(points, plot, parallel); tPara := time[real]()-t](/support/helpjp/helpview.aspx?si=2552/file01552/math110.png)
前述したように、QuickHull アルゴリズムに少しの修正を加えるだけで、かなりの高速化を実現できます。