Skip to content

Fun10165/ortools_planner

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OR-Tools Planner — Stage 0

基础可行性排程,使用 Google OR-Tools CP-SAT。

准备

  • 依赖已在 pyproject.toml 声明。使用 uv 运行:
uv run ortools-planner --help

Web UI

The project includes a modern Vue 3 + TypeScript frontend for parameter tuning and weekly schedule visualization.

Development Mode

  1. Start the backend:
uv run python -m ortools_planner.webui_app
  1. In another terminal, start the frontend dev server:
cd frontend
npm install
npm run dev

The frontend will be available at http://localhost:5173 with hot-reload. API calls are proxied to the backend at http://localhost:8001.

Production Build

To build the frontend for production:

cd frontend
npm install
npm run build

The build output will be in frontend/dist/ and will be automatically served by FastAPI when available. Access the app at http://localhost:8001/.

Features

  • Parameter Controls: Adjust solver configuration, energy budgets, rewards, and penalties via interactive sliders
  • Task Type Defaults: Set default parameters for different task types (work, meal, sleep, etc.)
  • Weekly Visualization: View a 7-day timeline with scheduled tasks color-coded by type
  • Real-time Progress: WebSocket updates for running plans
  • Run History: Browse and inspect previous planning runs

可选:在项目根目录创建 .env 用于后续阶段的环境变量管理;本阶段不必需。

输入格式(CSV)

列:id,name,duration_minutes,deadline_minute(optional),fixed_start_minute(optional)

示例(无标题解释以避免“模拟数据”代码):请提供你自己的真实任务文件。

运行示例

uv run ortools-planner \
  --tasks /path/to/tasks.csv \
  --horizon-minutes 1440 \
  --start-minute 0 \
  --verbose

输出将按开始时间排序,包含每个任务的 startend(绝对分钟)。

说明

  • 阶段零仅实现硬约束:无重叠、截止时间、固定开始。目标为最小化 makespan
  • 如出现不可行,程序会输出诊断信息,优先检查:
    • duration_minutes 是否大于规划窗口。
    • 固定开始时间是否越界。
    • 截止时间是否早于持续时间可完成。

阶段一(奖励与能量预算)

  • 输入 CSV 需要新增列:reward,energy_cost_per_minute
  • 目标:在满足硬约束前提下,最大化 总奖励 - 能量超标惩罚
  • 能量建模(阶段一最简版):
    • 能量使用 = energy_cost_per_minute * duration_minutes 的线性和。
    • 能量预算使用 --energy-budget 限制总和,超出部分以 --overuse-penalty 加权惩罚。
    • 任务为可选,求解器可在预算受限时倾向选择高奖励/低能耗任务。
    • 注意:Total Energy Used 不包含“疲劳惩罚”,疲劳惩罚作为独立项 Fatigue Penalty 报告并进入目标函数。

运行示例:

uv run ./main.py \
  --stage 1 \
  --tasks examples/tasks_stage1_sample.csv \
  --horizon-minutes 600 \
  --energy-budget 400 \
  --overuse-penalty 5

对比“笨”贪心编排器:

  • 贪心策略不考虑能量预算与奖励优化,仅按固定事件先放置、其余任务按“输入顺序”尽早填缝。
  • 运行对比:
# CP-SAT(考虑奖励与能量惩罚)
uv run ./main.py --stage 1 --strategy cp \
  --tasks examples/tasks_stage1_sample.csv --horizon-minutes 600 \
  --energy-budget 400 --overuse-penalty 5

# Naive 贪心(不考虑预算与奖励)
uv run ./main.py --stage 1 --strategy naive \
  --tasks examples/tasks_stage1_sample.csv --horizon-minutes 600 \
  --energy-budget 400 --overuse-penalty 5

或使用仓库内示例数据:

uv run ortools-planner \
  --tasks examples/tasks_stage0_sample.csv \
  --horizon-minutes 480 \
  --start-minute 0 \
  --verbose

番茄钟疲劳与任务拆分(可选增强)

为避免“同一任务连续长时间”导致的非线性精力消耗,阶段一支持任务拆分与番茄钟惩罚(需显式启用):

  • --chunk-max-minutes <N>:将非固定开始的任务拆分为不超过 N 分钟的块(chunk)。0 表示禁用拆分。
  • --break-reset-minutes <B>:两个相邻块之间的休息时长阈值;休息不足 B 的部分将产生“疲劳惩罚”。
  • --fatigue-penalty <W>:疲劳惩罚权重。越大越倾向于在块之间留出休息以归零疲劳。
    • 全局休息惩罚:不仅同一任务的块之间,任意两个相邻工作区间(跨任务)只要休息不足,也会产生惩罚。
    • --fatigue-reset-strict:严格模式,要求休息 gap > break-reset-minutes 才视为重置;若只达到阈值(等于),仍有最小惩罚。
    • --fatigue-pw-s1-limit <L>:启用分段线性疲劳(piecewise),第一段上限为 L 分钟缺口;0 表示禁用分段线性。
    • --fatigue-pw-w1 <W1>--fatigue-pw-w2 <W2>:分段线性两段的权重倍率(第一段、剩余部分)。通常设置 W2 > W1 以对极短休息更严厉惩罚。
    • --fatigue-as-energy <K>:将疲劳惩罚视为能量消耗增加,按系数 KFatigue Penalty 加入能量核算(用于计算预算超标)。0 表示禁用耦合。

建模细节(务实近似):

  • 拆分仅作用于“非固定开始”的任务;课程等固定开始的事件不拆分。
  • 奖励以“任务”为单位:要获得任务奖励,必须调度其所有块;因此对每个块的存在变量与任务存在变量强绑定。
  • 疲劳惩罚通过线性项近似:对每对相邻块 k→k+1,惩罚 max(0, break_reset_minutes - gap),其中 gap = start_{k+1} - end_{k}
    • 这是对“指数耗损”的实用近似:只要休息不足,就增加线性惩罚;权重 W 决定惩罚强度。
    • 如需更激进的非线性,可后续扩展为分段线性多阈值(piecewise),保持 CP-SAT 可解性。
    • 分段线性(已支持):将缺口拆成两段 s1 + s2 = deficits1 ≤ L;总惩罚 W * (W1*s1 + W2*s2),以对“极短休息”施加更高斜率但仍保持线性可解。
    • 能量耦合(可选):启用 --fatigue-as-energy K 后,Effective Energy Used = Total Energy Used + K * Fatigue Penalty,预算超标按有效能量计算。

示例:

uv run ./main.py --stage 1 --strategy cp \
  --tasks examples/tasks_stage1_sample.csv --horizon-minutes 600 \
  --energy-budget 400 --overuse-penalty 5 \
  --chunk-max-minutes 30 --break-reset-minutes 10 --fatigue-penalty 50

输出中被拆分的任务以 task_id#index 形式展示每个块的调度结果。 同时会显示:Total RewardTotal Energy UsedFatigue PenaltyEffective Energy UsedBudget;其中“疲劳惩罚”单独报告,而在启用能量耦合时也反映到 Effective Energy Used

使用配置文件(JSON)

  • 通过 --config <path> 指定一个 JSON 配置文件,作为参数默认值来源;命令行上的参数会覆盖配置文件中的值(命令行优先)。

示例文件:examples/config_stage1_sample.json

{
  "stage": 1,
  "strategy": "cp",
  "tasks": "examples/tasks_stage1_sample.csv",
  "horizon_minutes": 600,
  "start_minute": 0,
  "energy_budget": 300,
  "overuse_penalty": 2,
  "chunk_max_minutes": 30,
  "break_reset_minutes": 150,
  "fatigue_penalty": 5,
  "fatigue_reset_strict": true,
  "fatigue_pw_s1_limit": 10,
  "fatigue_pw_w1": 1,
  "fatigue_pw_w2": 4,
  "fatigue_as_energy": 1
}

运行:

uv run ./main.py --config examples/config_stage1_sample.json

你仍可以在命令行上覆盖部分字段,例如提高休息阈值:

uv run ./main.py --config examples/config_stage1_sample.json --break-reset-minutes 180

阶段二(多能量/非线性/动态收益)

在阶段一基础上进一步细化能量模型与收益结构:

  • 多能量池:mentalwillphysical,分别有独立预算与超标惩罚。
  • 非线性近似:
    • 启动损耗(Startup Loss):开始每个任务消耗固定 willpower,通过 --startup-will-cost 控制。
    • (更新)心流与上下文切换已移除,统一并入起始开销,不再提供心流奖励或能耗折扣。
  • 动态收益:
    • 紧急度(Urgency):越靠近截止时间开始,奖励线性增加,--urgency-weight 控制权重。
    • 机会窗口(Opportunity Window):在指定时间窗内开始可获得额外奖励(每任务在 CSV 指定)。

输入格式(CSV)

新增列:

id,name,duration_minutes,reward,task_type,mental_cost_per_minute,will_cost_per_minute,physical_cost_per_minute,deadline_minute(optional),fixed_start_minute(optional),opportunity_start_minute(optional),opportunity_end_minute(optional),opportunity_bonus(optional)

示例:examples/tasks_stage2_sample.csv(包含截止促急、晚间健身窗口奖励、心流任务与固定会议)。

配置文件示例(JSON)

示例文件:examples/config_stage2_sample.json(心流字段已移除)

{
  "stage": 2,
  "tasks": "examples/tasks_stage2_sample.csv",
  "horizon_minutes": 480,
  "start_minute": 0,
  "verbose": true,
  "mental_budget": 300,
  "will_budget": 200,
  "physical_budget": 150,
  "energy_overuse_penalty": 2,
  "urgency_weight": 2
}

运行:

uv run ./main.py --config examples/config_stage2_sample.json

你可以覆盖部分字段,例如调整预算或启动损耗:

uv run ./main.py --config examples/config_stage2_sample.json --startup-will-cost 10 --mental-budget 260

输出说明

  • 打印按开始时间排序的任务调度。
  • 目标值 Objective = 总奖励(含紧急度/机会窗口)减去各能量类型的超标惩罚(心流加成已移除)。
  • Energy Totals 分别显示 mental/will/physical 的累计使用量,用于对比预算与调参。

阶段三(统一:番茄钟疲劳 + 多能量 + 动态收益)

将阶段一的拆分/疲劳(番茄钟)与阶段二的多能量池、启动损耗、紧急度、机会窗口整合到同一求解器中(心流与上下文切换已移除,统一为起始开销)。

  • 固定开始任务(会议等)不进行拆分,保证时间一致性。
  • 对可拆分任务采用“全或无”策略:任务存在时必须调度其所有分块,避免仅用最小分块获取全部奖励的投机行为。
  • 疲劳惩罚按线性近似作用于任意相邻工作区间之间的短休缺口,并可选择将其耦合为能量消耗。

示例配置:examples/config_unified_sample.json

{
  "stage": 3,
  "tasks": "examples/tasks_stage2_sample.csv",
  "horizon_minutes": 600,
  "start_minute": 0,
  "verbose": false,
  "mental_budget": 300,
  "will_budget": 250,
  "physical_budget": 200,
  "energy_overuse_penalty": 2,
  "urgency_weight": 2,
  "chunk_max_minutes": 50,
  "break_reset_minutes": 10,
  "enforce_min_rest": true,
  "fatigue_penalty": 3,
  "fatigue_reset_strict": false,
  "fatigue_pw_s1_limit": 5,
  "fatigue_pw_w1": 1,
  "fatigue_pw_w2": 3,
  "fatigue_as_energy": 0
}

运行:

uv run ./main.py --config examples/config_unified_sample.json

输出包含:统一调度列表、Objective、各能量池累计与 Fatigue 总量,便于调参验证组合效果。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors