Scenarios · A–E

各デモシナリオで何を見るか

埋め込みシナリオは、マッチングの異なる側面を意図的に切り出しています。 参加者属性 → 除外ゲート → ペア点 → グループ、のどこが効いているかを追うための教材です。

共通前提

すべてのシナリオで now(現在時刻)は 2026-08-21 13:00 UTC。 準備時間 prep は 15 分、最小イベントは 30 分です。
flowchart LR
  NOW["now 現在
13:00"] --> PREP["prep 準備
+15分 → 13:15"] PREP --> MIN["min_event
最低30分必要"] MIN --> PLACE["Beacon 場所カタログ
library / cafe / gym"]

図 — 時刻と場所の共通設定

Beacon(場所)building(建物)campus(キャンパス)capacity(定員)
beacon_librarybldg_libcampus_main10
beacon_cafebldg_cafecampus_main8
beacon_gymbldg_gymcampus_east20

点数の計算式(全シナリオ共通)

ペア総合点 matching_score は、7要因の 0〜1 値に重みをかけて足し合わせます。 合計が ≥ 0.60 ならグループ候補の「辺」として残ります。
matching_score = intent×0.30 + time×0.25 + location×0.15 + interest×0.10 + capacity×0.10 + department×0.05 + friend×0.05
intent(意図)
×0.30
time(時間)
×0.25
location(場所)
×0.15
interest(興味)
×0.10
capacity(定員)
×0.10
department(学科)
×0.05
friend(友人)
×0.05
flowchart LR
  F["要因値 0〜1
intent / time / ..."] --> W["× 重み"] W --> S["matching_score
総合点"] S --> T{"≥ 0.60 ?"} T -->|Yes| OK["辺として採用"] T -->|No| NG["グループ候補に使わない"]

図 — 要因 → 重み付け合計 → ペア閾値

要因このデモでの決まり方
intent共通意図数 ÷ min(各自の意図数)。例: {study}∩{study,make_friends}=1 → 1/1=1.00
timeprep後共通分が 90分以上 → 1.00(午後枠は165分なのでほぼ常に1.00)
location同一Beacon 1.00 / 同一キャンパス別建物 0.30 / 別キャンパス 0.00
interest常に unknown → 0.50 固定
capacity選定Beaconの定員5–10 → 1.00
department同一学科 1.00 / 異なる 0.00
friend相互の承認済み友人なら 1.00、それ以外 0.00

A 成功パス — 1グループ成立

学習の入口。3人が study(勉強)意図と長い空き時間で揃い、ペア・グループとも閾値を超えます。
除外
なし
ペア
3辺すべて ≥ 0.60
グループ
例: u001–u002(高得点)

参加者

u001
intent
study(勉強)
時間
13:00–16:00
場所
library
学科
dept_cs
友人
u002
u002
intent
study, make_friends
時間
13:00–16:00
場所
library
学科
dept_cs
友人
u001
u003
intent
study
時間
13:00–16:00
場所
cafe(別建物)
学科
dept_ee
友人
なし
flowchart TB
  subgraph In["入力"]
    U1["u001 library · study · 友人u002"]
    U2["u002 library · study · 友人u001"]
    U3["u003 cafe · study · dept_ee"]
  end
  In --> Gate["filter_eligible
全員通過"] Gate --> Pairs["ペア点
u001-u002 が最高
場所一致+友人+同学科"] Pairs --> G["form_groups
高得点ペアを優先採用"] G --> Out["グループ1つ
u003は余るか低優先"]

図 A — なぜ u001–u002 が強く選ばれやすいか

各ペアの点数計算

u001–u002 OK ≥ 0.60 matching_score = 0.9500

意図の重なり1.00、同一 library、同学科・友人あり。interest だけ 0.50 固定のため満点にならない。

1.00×0.30 + 1.00×0.25 + 1.00×0.15 + 0.50×0.10 + 1.00×0.10 + 1.00×0.05 + 1.00×0.05 = 0.30+0.25+0.15+0.05+0.10+0.05+0.05 = 0.9500
intent 1.00
×0.300.300
time 1.00
×0.250.250
location 1.00
×0.150.150
interest 0.50
×0.100.050
capacity 1.00
×0.100.100
department 1.00
×0.050.050
friend 1.00
×0.050.050
u001–u003 OK ≥ 0.60 matching_score = 0.7450

study は一致するが、library↔cafe で location=0.30(同一キャンパス)。学科・友人は不一致で 0。 選定 Beacon は cafe(定員8→capacity=1.00)。

1.00×0.30 + 1.00×0.25 + 0.30×0.15 + 0.50×0.10 + 1.00×0.10 + 0.00×0.05 + 0.00×0.05 = 0.30+0.25+0.045+0.05+0.10+0+0 = 0.7450
intent 1.00
×0.300.300
time 1.00
×0.250.250
location 0.30
×0.150.045
interest 0.50
×0.100.050
capacity 1.00
×0.100.100
department 0.00
×0.050.000
friend 0.00
×0.050.000
u002–u003 OK ≥ 0.60 matching_score = 0.7450

u001–u003 と同型。intent 重なりは study のみ(1/min(2,1)=1.00)。場所・学科・友人の減点が同じ。

1.00×0.30 + 1.00×0.25 + 0.30×0.15 + 0.50×0.10 + 1.00×0.10 + 0 + 0 = 0.7450
flowchart LR
  P12["u001-u002
0.9500"] --> Prefer["貪欲で優先"] P13["u001-u003
0.7450"] --> Lower["低優先"] P23["u002-u003
0.7450"] --> Lower Prefer --> G["G1: u001+u002"]

図 A-2 — ペア点の差が採用順に効く

# 実行 python matching_demo.py --scenario A

B 除外 — 準備後の残り時間不足

ペア採点まで進みません。prep(準備15分)後に 30 分未満しか残らないため、門番で全員除外されます。
除外
u001, u002 両方
理由
insufficient_remaining_time
ペア / グループ
なし

参加者(共通)

u001 / u002
intent
study
時間
13:10–13:35(短い)
場所
library
残り
prep後 20分 < 30分
flowchart LR
  W["空き 13:10–13:35"] --> P["prep 切捨て
使えるのは 13:15–13:35"] P --> R["残り 20分"] R --> X{"≥ 30分?"} X -->|No| EX["EXCLUDED
insufficient_remaining_time
残り時間不足"]

図 B — 時間ゲートの計算

ペア点数について

u001–u002 採点なし

個人ゲートで両者が insufficient_remaining_time(残り時間不足)のため eligible(通過者)が空です。score_pair は呼ばれず、要因表は出ません。

remaining_after_prep = 20分 < 30分 → EXCLUDED → pair_scores = (空)

意図や場所が揃っていても、時間ゲートを通らなければスコアは付きません。 出力の [1] Participants で remaining after prep: 20m を確認できます。

# 実行 python matching_demo.py --scenario B

C 複数グループ — 貪欲と非再利用

6人。意図クラスタが分かれ、貪欲法で複数グループが採用され、意図が孤立した1人があまりになります。
グループ1
study の3人(library)
グループ2
lunch の2人(cafe)
あまり
u006 wellness 単独

参加者クラスタ

u001–u003
intent
study
場所
library
u004–u005
intent
lunch
場所
cafe
u006
intent
wellness
場所
gym(別キャンパス)
結果
ペア閾値未満になりやすい
flowchart TB
  All["6人候補"] --> S["study クラスタ
u001 u002 u003"] All --> L["lunch クラスタ
u004 u005"] All --> W["wellness 単独
u006"] S --> G1["G1 採用
人数ボーナスで優先されやすい"] L --> G2["G2 採用"] W --> Alone["あまり
再利用禁止のため孤立"]

図 C — 意図クラスタと貪欲採用

各ペアの点数計算(代表例)

全15ペアのうち、合格辺と不合格辺の典型を示します。

u001–u002(study同士) OK 0.9000

同一 library・同学科。友人なしのため friend=0 → Aの0.95より 0.05 低い。

1.00×0.30 + 1.00×0.25 + 1.00×0.15 + 0.50×0.10 + 1.00×0.10 + 1.00×0.05 + 0.00×0.05 = 0.30+0.25+0.15+0.05+0.10+0.05+0 = 0.9000
u004–u005(lunch同士) OK 0.9000

同一 cafe。計算式は study ペアと同型(intent/time/location が揃う)。

同型の加重和 → 0.9000(選定 Beacon = cafe)
u001–u004(study–lunch) < 0.60 0.4950

intent=0.00 が致命的(重み0.30が消える)。場所は別建物で 0.30。 時間・定員・学科だけでは閾値に届かない。

0×0.30 + 1.00×0.25 + 0.30×0.15 + 0.50×0.10 + 1.00×0.10 + 1.00×0.05 + 0 = 0+0.25+0.045+0.05+0.10+0.05 = 0.4950
intent 0.00
×0.300.000
time 1.00
×0.250.250
location 0.30
×0.150.045
interest 0.50
×0.100.050
capacity 1.00
×0.100.100
department 1.00
×0.050.050
friend 0.00
×0.050.000
u001–u006(study–wellness) < 0.60 0.4500

intent=0、かつ gym は別キャンパスで location=0.00 → さらに低い。

0 + 0.25 + 0 + 0.05 + 0.10 + 0.05 + 0 = 0.4500
ペア種別代表score辺になる?
study–studyu001-u002, u001-u003, u002-u0030.9000Yes
lunch–lunchu004-u0050.9000Yes
study–lunchu001-u004 など0.4950No
× wellnessu001-u006 など0.4500No

グループ点: study の3人は matching=0.9000、selection=0.9200(+0.02 人数ボーナス)で先に採用。 lunch 2人が続く。u006 は合格辺を持たないためあまり。

# 実行 python matching_demo.py --scenario C

D 重複集合 — グループだけブロック

参加者はシナリオ A と同じですが、duplicate_student_sets(重複候補集合)に 全ペアとトリオが入っているため、ペア点は計算される一方、グループは1つも採用されません
除外(個人)
なし(全員 eligible)
ペア点
A と同様に出る
グループ
なし(全部 skip)
flowchart TD
  A["入力 = シナリオAと同じ3人"] --> P["score_pair
ペア点は通常どおり"] P --> F["form_groups"] F --> D1["{u001,u002} duplicate"] F --> D2["{u001,u003} duplicate"] F --> D3["{u002,u003} duplicate"] F --> D4["{u001,u002,u003} duplicate"] D1 --> Out["Groups: なし"] D2 --> Out D3 --> Out D4 --> Out

図 D — 個人ゲート通過後でも、集合一致でグループ不採用

各ペアの点数計算

ペアの factors / weighted / 総合点はシナリオ A と同一です (u001–u002=0.9500、u001–u003=0.7450、u002–u003=0.7450)。 差分は form_groups 側の duplicate チェックだけです。
flowchart LR
  P["ペア点は A と同じ
3辺すべて ≥ 0.60"] --> F["form_groups"] F --> X["全組合せが
duplicate_student_sets に一致"] X --> N["Groups: なし"]

図 D-2 — 採点は通るが採用は全部 skip

「すでに同じ候補集合の ACTIVE イベントがある」状態の模擬です。 A と並べて実行すると、[3] Pair scores が同じで [4] Groups だけ空、と分かります。

# 比較 python matching_demo.py --scenario A python matching_demo.py --scenario D

E 要因差 — 友人・学科の見え方

意図・時間・場所は3人とも揃えています。差は friend(友人・重み0.05)と department(学科・重み0.05)だけです。
u001–u002
最高点(友人+同学科)
u001–u003 等
やや低い(友人・学科なし)
採用
高得点の友人ペア優先

参加者

u001
intent
social
場所
library
学科
dept_cs
友人
u002
u002
intent
social
場所
library
学科
dept_cs
友人
u001
u003
intent
social
場所
library
学科
dept_ee
友人
なし
flowchart LR
  P12["u001–u002
friend=1.00
department=1.00"] --> H["総合点 高い"] P13["u001–u003
friend=0.00
department=0.00"] --> L["総合点 やや低い"] P23["u002–u003
同様に低め"] --> L H --> G["グループ採用は
u001–u002 が優先"]

図 E — 低重み要因でもペア順位が変わる

各ペアの点数計算

意図・時間・場所・定員・interest は3ペアとも同じ。差は department(0.05)と friend(0.05)だけです。

u001–u002 OK 0.9500

同学科 + 相互友人 → department=1、friend=1。差分 +0.10 が他ペアとの差になる。

1.00×0.30 + 1.00×0.25 + 1.00×0.15 + 0.50×0.10 + 1.00×0.10 + 1.00×0.05 + 1.00×0.05 = 0.85 + 0.05 + 0.05 = 0.9500
共通部
0.850
department
×0.050.050
friend
×0.050.050
u001–u003 OK 0.8500

場所は同じ library だが、学科違い・友人なし → その2要因が 0。

共通部 0.850 + 0.00×0.05 + 0.00×0.05 = 0.8500
共通部
0.850
department 0
×0.050.000
friend 0
×0.050.000
u002–u003 OK 0.8500

u001–u003 と同型(総合点の差はすべて friend+department の 0.10)。

0.8500(u001–u002 との差 = −0.1000
flowchart TB
  Base["共通 0.850
intent+time+location+interest+capacity"] --> H["+ department 0.05
+ friend 0.05"] Base --> L["+ 0 + 0"] H --> S95["u001-u002 = 0.950"] L --> S85["他ペア = 0.850"] S95 --> Pick["G1 に採用"]

図 E-2 — 0.10 の差の内訳

出力 [3] の factors(要因値)と weighted(寄与)で、 friend/department の差が合計にどう乗るか検算できます。

# 実行 python matching_demo.py --scenario E

推奨の見る順番

flowchart LR
  A["A 成功の全体像"] --> B["B 時間ゲート"]
  B --> C["C 複数グループ"]
  C --> D["D 重複ブロック"]
  D --> E["E 要因の差"]
        

図 — A→E の学習パス

ねらい
Aパイプライン全体と属性出力の読み方
Bスコア前の除外が結果を決めること
C貪欲・非再利用・クラスタ分割
Dペア成立とグループ不成立の切り分け
E説明可能な要因内訳の読み取り

関連: 処理・関数解説 · matching_demo.py