vvvvでのループ処理について考える

Pocket

これはvvvv Advent Calendar 201624日目の記事です。


はじめに

vvvvにはforやforeachといったループ(繰り返し/再帰)処理の構文がありません。
よくProcessingのコードをvvvvに書き換えるなんてことをやりますが、
forなどでループ処理がされている部分でよく悩みます。

似た挙動をするノードにFrameDelayがありますが、これは1フレーム前の値を持ってくるというものなので
プログラマが望むループ処理には使用できないでしょう。
もう1つ残念なことにvvvvはサブパッチを再帰的に使用(入れ子)できません。
(https://vvvv.org/documentation/subpatches の Recursion についての記述)
なのでこの方法でループ処理を実現することも不可能です。

VLってやつが仲間になりたそうにこちらを見ていますが、
今のところ自分のスタンスはプラグイン(C#)派です。
というかVLについてはドキュメントがまだ揃っていない(?)ようで詳細な使い方がよくわかりません。
また (将来的に改善されるのでしょうが)ノードにいちいちConfigure(型の定義など)を行ったり、
エラーの原因が分かりにくいなど、
なんだか好きになれる自信がありません、笑
(誰か僕をVL派に懐柔してください。)

そこで今回はvvvvオンリーでのループ処理について考えてみたいと思います。
ループ処理が必要となる目的をいくつか挙げ、それをvvvvで実装してみます。

もっといいやり方がある! というご意見などあれば大変ありがたいです。

配列のすべての要素に変更を加える

JavaScriptだとこう書くようなもの。

var arr = [1, 3, 5, 7, 9, 11];
for (var i=0; i<arr.length; i++) {
  arr[i] += 3;
}

vvvvだとこう。わざわざ載せるのも馬鹿らしいほど簡単になります、笑

合計を計算する

var arr = [1, 3, 5, 7, 9, 11];
var sum = 0;
for (var i=0; i<arr.length; i++) {
  sum += arr[i];
}

これは「+ Add (Value Spectral)」ノードを使えば簡単にできます。
vvvvではSlice単位ではなくSpread単位で何かをしてくれるノードには
Spectralというカテゴリが付いているようです。
(何でSpectralって言うんでしょうか?)

最大値/最小値を取得する

var arr = [1, 3, 5, 7, 9, 11];
var min = arr[0];
var max = arr[0];
for (var i=0; i<arr.length; i++) {
  if (arr[i] < min) {
    min = arr[i];
  }

  if (max < arr[i]) {
    max = arr[i];
  }
}

これもSpectral系のノードにあります。

微分/積分

Spectralカテゴリではないですが、Spectral的な何かに使えそうなノードとして、
「Differential(微分)」、「Integral(積分)」ノードがあります。
頭の片隅に入れておくといいかも。
使い方は各ヘルプパッチを参考にしてください。

条件に一致する値(とそのインデックス)だけ取得する

var arr = [1, 3, 5, 7, 9, 11];
var result = new Array();
for (var i=0; i<arr.length; i++) {
  if (arr[i] < 5) {
    result.push(arr[i]);
  }
}

Selectノードが役に立ちます。

ある条件でループ処理を抜ける(break)/スキップする(continue)

以下はcontinueの例。

var arr = [1, 3, 5, 7, 9, 11];
var result = new Array();
for (var i=0; i<arr.length; i++) {
  result.push(arr[i]);
  
  if (arr[i] < 5) {
    continue;
  }

  result[i] *= 3;
}

// result
// [1, 3, 15, 21, 27, 33]

vvvvではこうなります。左側と右側で2案。

左側の案はわかりやすいけど、3を掛けなくてもいいスライスに対しても掛けてしまっています。
右側は3を掛ける必要のあるスライスだけを分離して3を掛けた後に、もとのスプレッドに戻しています。
左側の案だと無駄な計算増えるかなぁと思って右側の案を書いてみましたが、
Selectは意外と重い模様…。Oh…。
(Debug Timing ONにした状態、数字は処理時間。)

多重配列

var arr = [[1, 3], [3, 5], [5, 20], [7, 3], [9, 14], [11, 13]];
var result = new Array();
for (var i=0; i<arr.length; i++) {
  var r = new Array();
  for (var j=0; j<arr[i].length; j++) {
    r[j] = arr[i][j] * 3;
  }
  result.push(r);
}
// result
// [[3,9],[9,15],[15,60],[21,9],[27,42],[33,39]]

これ系をわかりやすく書くのはvvvvは得意そうです。
多重度が増えてもVector SizeやスプレッドのBinと呼ばれる部分をいじれば対応できることが多いです。たぶん。

n-1回目の結果をn回目で使用する処理

たとえばこんな…

var arr = [3, 1, 5, 11, 9, 7];
var result = new Array();
for (var i=0; i<arr.length; i++) {
    if (i==0) {
        result.push(arr[i]);
    } else {
        var pre = result[i-1];
        if (pre < 25) {
            result.push(arr[i] * 10);
        } else {
            result.push(arr[i] * 5);
        }
    }
}
// result
// [3, 10, 50, 55, 45, 35]

難問です。

書く必要もないくらい愚直な案は、ループの回数だけノードを増やす、です笑

しかしこれは作業量も多いし、ループ回数が可変な場合は対応できません。

……
いろいろ試行錯誤しましたが、vvvvではこの様な処理は出来ないという結論に達しました。

アルゴリズム自体をvvvvで書けるように変更するか、
それも難しい場合はプラグイン(C#)orVLを使わなければなりません。

最終手段

前述の通り、vvvvでは書けないアルゴリズムの場合はプラグイン(C#)orVLを使います。
あとComputeShaderを使うこともできるかもしれません(まだやったことないので出来なかったらすみません。)

vvvvはとても簡単にプラグインとして処理を拡張できる仕組みが備わっているので、
使えるようになっておくといざと言う時かなり役立ちます。

プラグインの作り方やVLについてはまた別の機会に。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*