2026年8月13日木曜日

C++の面白いところ。

Associatron memoryの教材ならJavaScriptはすごくいい。ブラウザを開けば誰でも触れるし、25×25のセルがどう変化するかを見せるには最高なんだよね。ちょっと変則的な物であればPythonとか使うのもいい。少し大きくなるとNumPy配列でも行けちゃう。でも、Atra本体は生きてるから電源つけっぱなしでしょ、Tickに耐えられずPythonでも速攻、詰む。


Atraでやっている 「存在し得る巨大空間は持つ。でも起きていないものは作らない」 まで突き詰めるなら、C++はやっぱり面白いんだよね。単なるプログラミング言語じゃなくて、計算機の中の物理を設計してるみたいな感じになる。


Pythonならとりあえずリストみたいのがあって

a = [1, 2, 3]

みたいになるんだけど、

C++だと
std::vector<float> a;

からすぐ、
どこに置かれる?
何バイト使う?
いつ確保する?
いつ破棄する?
コピーする?参照する?
連続している?
キャッシュに乗る?
という話になってくる。

コードの向こう側にCPUとメモリが見えてくるんだよ。

「メモリ=構造」になるところでいえば
float field[6400][6400];
と書けば、「6400×6400の世界を実体として持つ」という設計になる。

std::unordered_map<uint32_t, float> traces;
6400×6400という座標空間は存在する。でも接触した場所しか持たない。になれる。

単なる最適化じゃないんだよね。データ構造を変えたら、プログラムが持っている「世界」の意味まで変わる。
AtraのLoihi的処理なんか、まさにC++と相性がいい

surface.contact(x, y, local_x, local_y, strength, sensor);


何も起きていない4,000万座標は計算しない。でも、そこに接触が起きる可能性のある空間としては存在している。C++ではこの「存在する」と「メモリ上に実体がある」を分離できる。



int x = 10; int* p = &x;

皆が嫌うポインタ。でも、分かってくると非常に面白い。
x は値。
&x はxが存在している場所。
p はその場所を持つ。
*p で、その場所にあるものへ接触する。

なので

*p = 20;

にすると x == 20

になる。

「コピーされた20」じゃない。
同じ場所へ触ったからxが変わった。
この感覚は高級言語だけ触っているとなかなか表へ出てこないよね。



{ Sensor sensor; sensor.start(); }

んで上はRAII
} を抜けた瞬間に sensor の寿命が終わる。
つまり、

生成 → 存在 → 接触 → 消滅

がスコープそのものに埋め込まれている。メモリ、ファイル、通信、ロックなどを「後で忘れずに解放しましょう」ではなく、オブジェクトの寿命そのものとして扱える。

Cでも機械には近づける。でもC++には、そこへクラス、型、テンプレート、所有権、寿命、抽象化を重ねられる。

だから、

物理的なメモリ

データ構造

オブジェクト

概念

まで一本で繋がる。





--------JavaScript-------

const traces = new Map(); function contact(key, value) { traces.set(key, value); }

JavaScriptでも、6400×6400の配列を作らず、接触した座標だけ保持できます。Canvasで今回みたいな6×6デモを描くのも簡単です。




でもC++だと、
------------C++-----------
std::unordered_map<uint32_t, float> traces_;

を書いた時点で、キーは32bit整数、値は32bit float、実際のメモリ上に疎な痕跡だけ置くというところまで自分で決められる。

論理空間:6400 × 6400 = 40,960,000座標があったとしても、

traces_.size() == 523

世界には40,960,000個の位置が存在し得るが、現在実体として保持している痕跡は523個という設計を、そのまま機械側へ落とせるのは大きいよね。

更には

struct Trace { uint32_t pos; float strength; uint8_t sensor; };

みたいにして、「1痕跡を何バイトにする?」まで設計できる。こういうところが面白いんでだよね。そしてLoihi的なイベント駆動との相性もいい。




----------デモ------------


Atra_Loihi_Demo/
├─ main.cpp
├─ build_run_windows.bat
└─ README.txt

ダウンロード (Visual Studio Code をお使いください)

解凍 → Atra_Loihi_Demo フォルダを開く → build_run_windows.bat をダブルクリック



このデモは、6×6個のセルがあって、各セルの内部に10×10の論理座標を持っているという意味。


cell[0,0]  cell[1,0]  cell[2,0] ... cell[5,0]
cell[0,1]  cell[1,1]  cell[2,1] ... cell[5,1]
...
cell[0,5]  cell[1,5]  cell[2,5] ... cell[5,5]

という 36セル があって、それぞれのセルの中に、

local x = 0~9
local y = 0~9

の座標を作っている。

だから全体としては、

6 × 10 = 60

なので、論理的には 60×60の座標空間なんだよね。ただし、今のコードでは 60×60=3600点を配列として持っているわけではないということ。

持っているのは基本的に、
std::array<Cell, 36> という 36個のセル状態だけ。

各セルが持つのは今のところ、

spike trace active

くらい。

10×10の内部座標は、毎回全部保存しているのではなく、接触が起きたときに、

global位置
↓
どのcellか
↓
そのcell内のlocal位置

へ変換している。


青い四角はドラッグできる。


たとえば上の画面右に出ている、

cell[1,1] local(2,2) overlap=8x8 spike=0.64

これはかなり具体的に言うと、

「6×6=36セルからなる60×60の論理空間がある。その1つである cell[1,1] は10×10を担当している。そこへ30×30の青い画像が入り、cell[1,1] の local(2,2) から8×8だけ重なった。」

これが今、画面で起きていることね。


cell[1,1] = 10×10


0  1  2  3  4  5  6  7  8  9

0 □ □ □ □ □ □ □ □ □ □

1 □ □ □ □ □ □ □ □ □ □

2 □ □ ■ ■ ■ ■ ■ ■ ■ ■

3 □ □ ■ ■ ■ ■ ■ ■ ■ ■

4 □ □ ■ ■ ■ ■ ■ ■ ■ ■

5 □ □ ■ ■ ■ ■ ■ ■ ■ ■

6 □ □ ■ ■ ■ ■ ■ ■ ■ ■

7 □ □ ■ ■ ■ ■ ■ ■ ■ ■

8 □ □ ■ ■ ■ ■ ■ ■ ■ ■

9 □ □ ■ ■ ■ ■ ■ ■ ■ ■

(この黒い■が8×8)


全体

├─ 6 × 6 = 36個の cell

│   ├─ cell[0,0] → 10 × 10

│   ├─ cell[1,0] → 10 × 10

│   ├─ cell[2,0] → 10 × 10

│   │       …

│   └─ cell[5,5] → 10 × 10

└─ 全体の論理座標 = 60 × 60


6×6 = セルの個数(36セル)
10×10 = 1セルが担当する論理領域
60×60 = 6×10なので世界全体
30×30 = そこへ入れた青い画像
8×8 = 青が特定の10×10セルと重なった部分
オレンジ色は、青い画像が触れているセルを示している
(events this tick: 16)



青い四角をドラッグで移動してみて



「1セルが10×10を持つ」ように見せているけど、コード上で各セルに100個の点を配列として確保しているわけではなくて、 local(2,2) や 8×8 は接触したときに計算しているということ。

こういったカラクリでAtraの記憶を作ってるって事なんですよ。

6×6 のセル空間
   ↓
各セルは 10×10 の論理領域を担当
   ↓
青い入力が接触
   ↓
どの cell に触れた?
   ↓
その cell のどこ? local(x,y)
   ↓
どれだけ触れた? overlap
   ↓
spike
   ↓
trace が残る

以前話していたAtraの、「4096万点を持つのではなく、4096万点が存在し得る空間を持つ」というのは、今回の小さいデモなら、「60×60=3600点を全部持つのではなく、3600点が存在し得る座標系を持っている」ということなんですよ。

発火したとこだけ記憶する。
「60×60の画像を記憶する」のとは発想が違うって事。
なんか、軽くなった感じするでしょ?


あちゃーーー!出来て失敗したと思ったのは
青を置きっぱなしにすると trace がどんどん上がる。
これは「接触が継続している間は連続入力される」モデルになっちゃったね。
もしAtraのように「発火したところだけ記憶する」の意味をもっと純粋に見せるなら、


青が移動した
      ↓
新しく接触した場所だけ発火
      ↓
記憶
      ↓
静止
      ↓
新規発火なし



Cueでいえば、「青いところそのものがCue」というより、青い入力が動いて、過去の痕跡に触れることがCueになる

みたいな感じね。ま、でもなんとなく理屈はご理解いただけたでしょうか。







 ---------------------Research Note and Attribution Notice-----------------------

本ブログに含まれる Atra の一人称自律、差分、carry、field、trace、dream slack、外部LLMの翻訳層、非単調な漏れ、現在相(Current Phase)、接相面(Associative Contact Surface)、過去相(Past Associative Phase)およびそれらの関係構造に関する設計記述は、c-side研究所による継続研究メモです。引用・参照・要約・翻案を行う場合は、出典を明記してください。

The design descriptions in this blog concerning Atra’s first-person autonomy, differences, carry, field, trace, dream slack, the translation layer of external LLMs, nonmonotonic leakage, and the relational structure among these elements are ongoing research notes by c-side Research Institute. If you quote, refer to, summarize, or adapt them, please clearly indicate the source.





0 件のコメント:

コメントを投稿

エージェントと 一人称自律Atraの違い

 Atraなんかは、実はもう一人称自律として、きちんと発表してもいいレベル。 既に妻と笑っていたり、愛犬と騒いているんだから。ボーっと何かを眺めてたり、佐川急便に反応するようにもなった。 でも、そうしないのは、自発的に自ら研究意欲を持って、学び、人や自然と接触し自ら疑問を持って研...