# Directional Constraint Locking ## 方向約束鎖定演算法 — 概念文件 **版本:** v0.6 **日期:** 2026-03-30 **狀態:** 概念驗證階段(Prototype 完成) --- ## 一、概念摘要 Directional Constraint Locking(DCL)是一種**以空間移動行為驅動的多維篩選演算法**。 使用者不是事先設定篩選條件,而是透過在一個二維畫布上的**移動方向**來累積約束條件。每一次往某個方向移動,就鎖定一個新的維度值;鎖定的條件持續累積,最終形成一個由移動軌跡定義的多維交集查詢。 核心精神:**「你走到哪,條件就鎖到哪」** --- ## 二、形式化定義 ### 2.1 基本符號 | 符號 | 定義 | |------|------| | `C` | 所有卡片的集合,|C| = n | | `D` | { ↖ ↑ ↗ ← → ↙ ↓ ↘ },共 8 個方向 | | `N` | 類別數量(可設定,N ≥ 8,預設為 8) | | `A(c, d)` | 卡片 c 在方向 d 上的屬性值,A : C × D → {1…N} | | `L` | 目前鎖定的條件集合,L ⊆ D × {1…N} | | `Q` | 鎖定順序佇列(FIFO),記錄方向被鎖定的先後 | | `cₜ` | 當前卡片 | **選取約束(核心規則):** 對每張卡片 c,`A(c, ·)` 從 {1…N} 中**選取 8 個相異的值**(部分排列 P(N,8))。 即同一張卡片的 8 個方向各持有不同的值,不重複。 當 N = 8 時,等同完整雙射(排列);當 N > 8 時,值從更大的集合中抽取。 ### 2.2 候選池函數 ``` P(L, cₜ) = { c ∈ C | c ≠ cₜ ∧ ∀(d, v) ∈ L : A(c, d) = v } ``` 所有符合當前鎖定條件、且不是當前卡片的集合。 ### 2.3 導航函數 nav(d) ``` 1. 若 d ∉ L,鎖定當前值: L ← L ∪ {(d, A(cₜ, d))} Q.enqueue(d) 2. 計算候選池: P ← P(L, cₜ) 3. 若 P = ∅,執行 FIFO 解鎖直到 P ≠ ∅: while P = ∅ ∧ Q ≠ ∅ : d' ← Q.dequeue() L ← L \ {(d', ·)} P ← P(L, cₜ) 4. 隨機取下一張: cₜ ← P[ random(0, |P|-1) ] ``` ### 2.4 演算法性質 - **條件單調遞增**:|L| 只增不減,除非發生 FIFO 解鎖 - **最大鎖定數**:|L| ≤ 8(方向數量上限) - **無死路保證**:只要 |C| > 1,P(∅, cₜ) ≠ ∅ 永遠成立,FIFO 解鎖保證能找到候選 - **隨機導航**:同一條件 L 下持續導航,從候選池中隨機挑選,不保證遍歷所有候選 - **選取約束**:A(c, ·) 從 {1…N} 中選取 8 個相異值 ⟹ 同一張卡不可能在兩個方向有相同的值 --- ## 三、基本規則(直觀說明) ### 3.1 方向與維度的對應 畫布共有 8 個移動方向,每個方向對應一個固定的資料維度: ``` [U] | [LU] \ | / [RU] \ | / \ | / \ | / [L] --------- o --------- [R] / | \ / | \ / | \ [LD] / | \ [RD] | [D] ``` 每張卡片在 8 個方向各持有一個從 {1…N} 中選出的相異數值(N 可設定,預設為 8),且 8 個值互不重複。 ### 3.2 鎖定機制 - 使用者**第一次**往某個方向移動時,該方向的維度值被鎖定 - 鎖定的值來自**出發那張卡片**在該方向上的數值 - 之後每一步都必須符合所有已鎖定的條件 - 鎖定條件**只增不減**,最多同時鎖定 8 個維度 ### 3.3 條件累積範例 ``` 起點:卡片 A { 右:8, 上:7, 右上:6, 左:3, 下:4, 左上:2, 右下:5, 左下:1 } 第 1 步:往右 → 鎖定 右=8 查詢:右=8 的卡片群,進入其中一張(卡片 B) 第 2 步:往上 → 追加鎖定 上=7(注意:這是卡片 B 的上方值) 查詢:右=8 AND 上=7 的卡片群 第 3 步:往右上 → 追加鎖定 右上=(卡片 B 的右上值) 查詢:右=8 AND 上=7 AND 右上=? 的卡片群 ...依此類推,最多 8 個條件同時鎖定 ``` ### 3.4 隨機探索 每個符合條件的卡片群形成一個**候選池(Candidate Pool)**。 在同一個方向持續移動,會從池子裡隨機挑選一張,永遠不會走到死路。 ``` 右=8 的卡片池:{A, C, F, H} → 每次隨機挑一張 ``` ### 3.5 FIFO 解鎖 當多個條件的交集為空時,**最早鎖定的條件優先釋放**,直到找到有效的候選集為止。釋放順序嚴格遵循鎖定的先後次序(先進先出)。 --- ## 四、資料結構 ### 4.1 卡片節點 每張卡片是一個節點,包含 8 個從 {1…N} 中選出的相異方向數值(不重複): ```json { "id": "photo_001", "src": "...", "attrs": { "right": 8, "left": 3, "up": 7, "down": 4, "right_up": 6, "left_up": 2, "right_down": 5, "left_down": 1 } } ``` ### 4.2 導航狀態 使用者當前的移動狀態,記錄鎖定條件與順序: ```json { "current": "photo_001", "lockMap": { "right": 8, "up": 7 }, "lockOrder": ["right", "up"], "history": ["photo_003", "photo_007", "photo_001"] } ``` --- ## 五、與既有概念的比較 | 概念 | 相似之處 | 不同之處 | |------|----------|----------| | Faceted Search | 多條件篩選 | 條件是預設的,不是行為觸發的 | | Graph Traversal | 在節點間移動 | 沒有方向維度語意 | | Constraint Satisfaction | 累積約束找解 | 不是空間導航行為 | | Latent Space Navigation | 語意空間漫遊 | 需要 AI 模型,不透明 | | **DCL(本演算法)** | — | 行為即篩選,移動即定義條件,透明可控 | --- ## 六、潛在應用場景 - **穿搭探索 App**:8 個方向代表版型、色調、風格、場合等維度 - **音樂探索**:節奏、情緒、樂器、年代等維度 - **選品工具**:材質、價格區間、風格、品牌調性等 - **靈感牆**:讓使用者在視覺風格空間裡自由漂流 - **任何需要多維探索但不想讓用戶面對複雜篩選介面的場景** --- ## 七、擴展方向 ### 7.1 有序維度:時間軸與強度軸 基礎版 DCL 的 8 個方向是**對等的** — 每個方向都是離散標籤的精確匹配。但在實際應用中,某些維度天然具有**順序性**: - **時間軸**:將某個方向(例如 ↓)定義為時間維度,值代表時間區段(1=最舊, 8=最新) - **強度軸**:將某個方向(例如 →)定義為強度維度,值代表程度(1=最弱, 8=最強) **與現有設計的衝突:** 目前鎖定 `↓=3` 代表精確匹配「等於 3」。但對時間或強度維度,使用者的直覺是**方向性**的 — 「往下 = 更舊」、「往右 = 更強」。這需要引入新的匹配模式: ``` 精確匹配(現有):A(c, d) = v 方向匹配(擴展):A(c, d) >= v 或 A(c, d) <= v ``` 這意味著部分方向可以被標記為「有序維度」,導航時不鎖定精確值,而是鎖定一個**下界或上界**。往同方向持續移動會逐步收緊界限(例如 `>=3` → `>=4` → `>=5`),產生「越走越深入」的漸進體驗。 **設計考量:** - 有序維度不再適用選取約束(多張卡片可以在同方向有相同含義的值區間) - 候選池大小衰減速度較慢(`>=3` 命中較多卡片,而 `=3` 只命中一小部分) - 建議最多 2 個有序維度,其餘保持精確匹配,避免篩選力度過弱 ### 7.2 同方向漸進細化(Sub-step Refinement) 目前的行為:鎖定 `→=8` 後再往右走,只是在同一個候選池裡循環,**沒有「更深入」的感覺**。 擴展提案:每次在已鎖定方向上重複移動時,約束值遞增一個子步長: ``` 第 1 次往右:鎖定 → = 8.0 第 2 次往右:收緊 → = 8.1(候選池縮小) 第 3 次往右:收緊 → = 8.2(候選池更小) ... ``` **核心效果:** 把原本「在循環池中輪轉」的行為,變成「在同一維度上逐步收斂」。使用者會感受到「越走越精確」,而非「繞圈」。 **實作影響:** - 值域從離散整數 {1…N} 擴展為連續值或更細的離散刻度(如 {1.0, 1.1, ..., N.9}) - 選取約束需要放寬:不再是嚴格的相異整數,而是每張卡片在每個方向上持有一個浮點數 - 匹配邏輯改為區間比較:`|A(c, d) - v| <= tolerance`,容差隨子步長遞減 - 子步長的增量和容差需要仔細調校,以平衡「收斂速度」和「候選池大小」 **與有序維度的關係:** 漸進細化和有序維度可以組合使用。有序維度控制「方向」(更強/更新),漸進細化控制「精度」(更準確)。兩者共同構成一個從粗到細的探索體驗。 ### 7.3 插件架構 DCL 引擎支援可選的**插件系統**,允許按需掛載擴充功能,而不修改核心演算法。 **設計哲學:** - 核心引擎(`DCL.create()`)保持精簡純粹 — 不內建任何可選功能 - 擴充透過全域註冊、逐引擎掛載:`DCL.use(engine, 'pluginName')` - 插件可以包裝既有方法(如 `navigate`)或新增方法(如 `undo`) **內建插件 — `memory`:** 第一個內建插件提供導航回退功能。關鍵行為: - 每次 `navigate()` 時,當前卡片被推入內部堆疊 - `undo()` 從堆疊彈出,回到前一張卡片 - **鎖定狀態不變** — 回退不會撤銷約束條件 - 候選池根據當前(未改變的)鎖定狀態重新計算 - `reset()` 會同時清空記憶堆疊 這是一個刻意的設計選擇:回退的意思是「在當前約束下回到前一張卡片」,而非「撤銷整個導航步驟」。使用者累積的約束軌跡永遠被保留。 **未來可能的插件**包括:防重複(避免重訪近期卡片)、分析(追蹤導航模式)、路徑記錄(持久化完整導航歷史)等。 --- ## 九、待釐清的設計問題 - [x] 條件耗盡時的釋放順序 → 確認採用 **FIFO(先進先出)** - [ ] 8 個方向的維度語意由誰定義?產品方固定?還是隨內容動態生成? - [ ] 數值是從 {1…N} 中選出的離散整數,是否可支援區間模糊匹配(例如 ±1)? - [ ] 卡片池夠大時,AI 如何自動給每個方向打分(CLIP embedding)? - [ ] 有序維度的匹配模式如何與 FIFO 解鎖互動?方向匹配的解鎖是否應回退到前一個界限而非完全移除? - [ ] 漸進細化的子步長增量(0.1?動態?)和容差衰減曲線如何設計? --- ## 十、下一步 1. **~~Prototype 實作~~** ✓ 完成(100 張卡片、FIFO 解鎖、循環導航) 2. **驗證核心體驗**:移動的感覺是否符合直覺? 3. **真實內容替換**:用穿搭照片 + 手動打分取代佔位卡片 4. **AI 打分整合**:接入 CLIP embedding 自動產生方向數值 5. **命名與定位**:這個演算法是否值得獨立包裝成產品或開源工具? 6. **有序維度 PoC**:在 prototype 中實驗時間軸或強度軸 7. **漸進細化 PoC**:實作同方向重複移動的子步長收斂 --- ## 十一、版本歷史 | 版本 | 日期 | 說明 | |------|------|------| | v0.1 | 2026-03-25 | 初稿,概念與基本規則 | | v0.2 | 2026-03-25 | 加入形式化數學定義、確認 FIFO 解鎖、排列約束、Prototype 完成 | | v0.3 | 2026-03-25 | 新增擴展方向:有序維度(時間軸/強度軸)、同方向漸進細化 | | v0.4 | 2026-03-26 | 新增插件架構與內建記憶(undo)插件 | | v0.5 | 2026-03-30 | 候選池選取改為隨機;起始卡片隨機化(可自訂 startIndex);seed 預設改為 Date.now() | | v0.6 | 2026-03-30 | peek/peekAll 冪等性保證;undo/redo 方向僅顯示箭頭,不顯示分類 |