docs: complete the bilingual module docs for the ops and sim layers

This commit is contained in:
ApsisRS contributors 2026-10-02 01:51:22 +08:00
parent b4f61085ce
commit 57316092eb
9 changed files with 158 additions and 18 deletions

View File

@ -1,7 +1,5 @@
//! Resource modeling for satellite operations. //! Resource modeling for satellite operations.
//! //!
//! 卫星运行的资源建模。
//!
//! A resource is anything a task can occupy: a satellite, a ground station, a //! A resource is anything a task can occupy: a satellite, a ground station, a
//! transmitter, an onboard recorder. This crate models the two things a //! transmitter, an onboard recorder. This crate models the two things a
//! scheduler needs to know about one: when it is available, and how much of //! scheduler needs to know about one: when it is available, and how much of
@ -34,6 +32,23 @@
//! assert!(resource.is_available_over(120.0, 80.0)); //! assert!(resource.is_available_over(120.0, 80.0));
//! assert!(!resource.is_available_over(150.0, 100.0)); //! assert!(!resource.is_available_over(150.0, 100.0));
//! ``` //! ```
//!
//! 卫星运行的资源建模。
//!
//! 资源是任务可以占用的任何东西:一颗卫星、一座地面站、一台发射机、一台星载
//! 记录器。本 crate 为调度器需要了解的关于它的两件事建模:它何时可用,以及一个
//! 任务消耗它多少。
//!
//! 可用性表达为单一时间轴上互不相交的区间集合,称为窗口。在某瞬时有窗口包含该
//! 瞬时,资源即可用。这些窗口可来自任何地方:`apsis-access` 中的可见性分析为
//! 地面站产生它们,操作员则手工录入维护时段。
//!
//! 容量是一个正数,其含义由调用方定义。一次只能运行一项观测的卫星容量为一;记录
//! 器的容量以兆比特计;功率母线的以瓦特计。两个任务只有在它们的需求合起来超过
//! 容量时才冲突,这使同一个类型既能表达独占资源也能表达共享资源。
//!
//! 时间以距调用方所选原点的秒数计,故同一模型可服务于场景时钟、流逝时间与儒略日
//! 偏移。
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(missing_docs)] #![deny(missing_docs)]

View File

@ -1,7 +1,5 @@
//! Schedule representation and evaluation. //! Schedule representation and evaluation.
//! //!
//! 调度的表示与评估。
//!
//! A schedule is the answer a scheduler produces: for each task, when it runs //! A schedule is the answer a scheduler produces: for each task, when it runs
//! and on which resources. This crate holds that answer and evaluates it. //! and on which resources. This crate holds that answer and evaluates it.
//! It does not decide the placements, which is the job of `apsis-scheduler`; //! It does not decide the placements, which is the job of `apsis-scheduler`;
@ -32,6 +30,18 @@
//! assert_eq!(schedule.len(), 1); //! assert_eq!(schedule.len(), 1);
//! assert!(schedule.is_placed(TaskId::new(0))); //! assert!(schedule.is_placed(TaskId::new(0)));
//! ``` //! ```
//!
//! 调度的表示与评估。
//!
//! 调度是调度器所产生的答案:对每个任务,它何时运行以及在哪些资源上运行。本
//! crate 保存该答案并评估它。它不决定放置,那是 `apsis-scheduler` 的事;把二者
//! 分开,使一个调度可以从文件读取、由调度器产生,或手工书写,并以相同方式评估。
//!
//! 一处放置记录任务、其开始时间,以及它所持有的资源。放置时各资源会针对任务的需求
//! 检查,故调度无法描述一个运行在它并未请求的资源上的任务。
//!
//! 评估报告操作员对已完成计划所问的:放置了多少任务、每种资源在其最繁忙时被用去
//! 多少,以及可用时间实际花去多少。这些数字正是规划器在候选调度之间比较的。
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(missing_docs)] #![deny(missing_docs)]

View File

@ -1,7 +1,5 @@
//! Scheduling algorithms for satellite task planning. //! Scheduling algorithms for satellite task planning.
//! //!
//! 卫星任务规划的调度算法。
//!
//! A scheduler takes a list of tasks and a set of resources and produces a //! A scheduler takes a list of tasks and a set of resources and produces a
//! schedule. This crate provides a greedy scheduler and the pieces needed to //! schedule. This crate provides a greedy scheduler and the pieces needed to
//! build others. //! build others.
@ -41,6 +39,23 @@
//! assert_eq!(result.schedule.len(), 1); //! assert_eq!(result.schedule.len(), 1);
//! assert!(result.is_complete()); //! assert!(result.is_complete());
//! ``` //! ```
//!
//! 卫星任务规划的调度算法。
//!
//! 调度器接收任务列表与资源集合,产生一个调度。本 crate 提供一个贪心调度器以及
//! 构建其他调度器所需的构件。
//!
//! 带资源约束的调度一般是难解的:判定是否每个任务都放得下是一个装箱问题,它是
//! NP 难的。卫星规划问题规模小,有数百个任务而非数百万个,但对例行的规划周期而言,
//! 精确搜索仍不切实际。故此处的调度器是贪心启发式。
//!
//! 该算法把任务排序,并把每个放到其全部资源同时空闲的最早时间。任务按加权价值递减
//! 的次序考虑,这是一个好的启发式:最有价值的工作先被放置,最不有价值的填充剩余
//! 空隙。强制任务不论其价值都先放置,因为一个必须运行的任务比任何可以运行的任务
//! 都值更多。
//!
//! 结果不保证最优,且本 crate 报告它无法放置的内容而非无声丢弃,使操作员能看到该
//! 计划的代价。
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(missing_docs)] #![deny(missing_docs)]

View File

@ -1,7 +1,5 @@
//! Task modeling for satellite operations. //! Task modeling for satellite operations.
//! //!
//! 卫星运行的任务建模。
//!
//! A task is a unit of work that a scheduler places on a set of resources. It //! A task is a unit of work that a scheduler places on a set of resources. It
//! carries everything a scheduler needs to decide whether and where to run //! carries everything a scheduler needs to decide whether and where to run
//! it: how long it takes, when it may run, which resources it needs and in //! it: how long it takes, when it may run, which resources it needs and in
@ -35,6 +33,19 @@
//! assert_eq!(task.requirements.len(), 2); //! assert_eq!(task.requirements.len(), 2);
//! assert!(task.is_valid()); //! assert!(task.is_valid());
//! ``` //! ```
//!
//! 卫星运行的任务建模。
//!
//! 任务是调度器放置到一组资源上的工作单元。它携带调度器决定是否运行它、在哪里
//! 运行它所需的一切:耗时多久、何时可以运行、需要哪些资源及多少量,以及它值多少。
//!
//! 一个任务在其整个时长内同时需要它的全部资源。这是观测所具有的模型:取数期间
//! 卫星与地面站必须都可用。需要按序使用资源的任务,表达为两个由
//! [`PrecedenceGraph`] 中先后约束连接的任务,该约束说一个任务必须在另一个开始
//! 之前完成。
//!
//! 任务一旦构建便不可变。调度器赋给它的状态分开保存在调度中,使同一个任务可以
//! 被考虑用于多处放置而不被修改。
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(missing_docs)] #![deny(missing_docs)]

View File

@ -1,7 +1,5 @@
//! Simulation event types and event queue. //! Simulation event types and event queue.
//! //!
//! 仿真事件类型与事件队列。
//!
//! A discrete-event simulation advances by jumping from one event to the //! A discrete-event simulation advances by jumping from one event to the
//! next rather than by stepping through every instant. This crate provides //! next rather than by stepping through every instant. This crate provides
//! the queue that makes that possible: a priority queue ordered by time, //! the queue that makes that possible: a priority queue ordered by time,
@ -31,6 +29,19 @@
//! assert_eq!(event.time, 5.0); //! assert_eq!(event.time, 5.0);
//! assert_eq!(event.payload, "first"); //! assert_eq!(event.payload, "first");
//! ``` //! ```
//!
//! 仿真事件类型与事件队列。
//!
//! 离散事件仿真通过从一个事件跳到下一个来推进,而不是逐步走过每个瞬时。本 crate
//! 提供使之成为可能的队列:一个按时间排序的优先队列,并在落在同一瞬时的各事件之间
//! 有明确定义的次序。
//!
//! 该并列打破规则比它初看更重要。为同一瞬时调度的两个事件必须以可重复的次序投递,
//! 否则仿真每次运行都会产生不同结果,与另一实现的交叉核对也不可能。故每个事件携带
//! 一个在调度时赋予的序号,时间相等的事件按该序号排序,故该次序即它们被调度的次序。
//! 这是每个离散事件仿真器所用的约定。
//!
//! 时间以距仿真起点的秒数计,故队列对日历与时标一无所知。
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(missing_docs)] #![deny(missing_docs)]

View File

@ -1,7 +1,5 @@
//! Simulation output recording. //! Simulation output recording.
//! //!
//! 仿真输出记录。
//!
//! A simulation produces more output than a caller can act on at once: event //! A simulation produces more output than a caller can act on at once: event
//! times, the values a model computes as it runs, and the warnings it raises. //! times, the values a model computes as it runs, and the warnings it raises.
//! This crate collects those into one trace, so that a run can be examined //! This crate collects those into one trace, so that a run can be examined
@ -34,6 +32,22 @@
//! assert_eq!(recorder.trace().value_of("altitude"), Some(550.0)); //! assert_eq!(recorder.trace().value_of("altitude"), Some(550.0));
//! let _ = RecordKind::Warning; //! let _ = RecordKind::Warning;
//! ``` //! ```
//!
//! 仿真输出记录。
//!
//! 一次仿真产生的输出多到调用方无法一次全部处理:事件时刻、模型运行时计算的值,以及
//! 它提出的警告。本 crate 把这些收集进一条轨迹,使一次运行可以在结束后被检视,而不
//! 只在发生时。
//!
//! 一条记录有一个时刻、一个类别、一个标签与一个值。时刻是作出该记录时的仿真瞬时,
//! 这正是使轨迹可排序、可与事件日志连接的原因。类别区分了调用方通常想分辨的三件事:
//! 模型作出的观测、它决定的变更,以及它想揭示的警告。标签指明该值所关于的内容,而
//! 值是一个单数,这覆盖了一次仿真所记录的绝大多数内容,而不强加调用方必须设计的
//! 模式。
//!
//! 轨迹保持记录在它们被作出的次序,而非时间次序。该区别要紧:处理器可能先为它刚
//! 调度的后续事件记录了一个值,再为它正在处理的事件记录一个值,而模型推理所用的
//! 次序值得保留。想要时间次序的调用方用 [`Trace::in_time_order`] 索取。
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(missing_docs)] #![deny(missing_docs)]

View File

@ -1,7 +1,5 @@
//! Scenario definition and loading. //! Scenario definition and loading.
//! //!
//! 场景的定义与加载。
//!
//! A scenario is a simulation's initial conditions: the resources a plan may //! A scenario is a simulation's initial conditions: the resources a plan may
//! use, the tasks it must place, the precedence constraints between those //! use, the tasks it must place, the precedence constraints between those
//! tasks, and the limits the run should respect. It is the input a run is //! tasks, and the limits the run should respect. It is the input a run is
@ -58,6 +56,42 @@
//! assert_eq!(scenario.tasks().len(), 1); //! assert_eq!(scenario.tasks().len(), 1);
//! assert_eq!(scenario.validate(), Ok(())); //! assert_eq!(scenario.validate(), Ok(()));
//! ``` //! ```
//!
//! 场景的定义与加载。
//!
//! 场景是一次仿真的初始条件:计划可用的资源、必须放置的任务、这些任务之间的先后
//! 约束,以及运行应遵守的限制。它是一次运行所据以构建的输入,把它保存在一处意味着
//! 一次运行可以从单一描述复现,而不必从散落的参数重建。
//!
//! 本 crate 提供两种构建方式。构建器方法是 Rust 代码所用的,它们在每次添加时就检查。
//! 文本格式是存储的场景所用的,[`Scenario::parse`] 把它读回。二者一致:用
//! [`Scenario::to_text`] 写出的场景解析回相等的场景,故场景可以被存储、编辑并重新
//! 加载而不漂移。
//!
//! 文本格式是面向行的,且不携带第三方依赖。空行与第一个非空格字符为 `#` 的行被忽略。
//! 其余每一行是一个关键字后接其参数:
//!
//! ```text
//! scenario leo downlink
//! epoch 0
//! time_limit 3600
//! event_limit 1000000
//!
//! resource 0 capacity 1
//! window 0 0 600
//! window 0 1200 1800
//!
//! task 0 duration 60
//! task_window 0 100 1000
//! task_priority 0 5
//! task_mandatory 0 true
//! require 0 0 1
//!
//! precedence 0 1
//! ```
//!
//! `epoch` 是仿真时钟的起始时刻,单位为秒。`time_limit` 与 `event_limit` 是两个运行
//! 限制;任一个都可省略,那会使该限制不被设置。
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(missing_docs)] #![deny(missing_docs)]

View File

@ -1,7 +1,5 @@
//! Discrete-event simulation engine. //! Discrete-event simulation engine.
//! //!
//! 离散事件仿真引擎。
//!
//! The engine advances a clock by jumping from one event to the next. It //! The engine advances a clock by jumping from one event to the next. It
//! holds the event queue, the current simulation time, and the statistics a //! holds the event queue, the current simulation time, and the statistics a
//! caller needs to judge a run. What an event means is the caller's: it //! caller needs to judge a run. What an event means is the caller's: it
@ -40,6 +38,20 @@
//! assert_eq!(outcome.executed, 2); //! assert_eq!(outcome.executed, 2);
//! assert_eq!(engine.now(), 20.0); //! assert_eq!(engine.now(), 20.0);
//! ``` //! ```
//!
//! 离散事件仿真引擎。
//!
//! 引擎通过从一个事件跳到下一个来推进时钟。它保存事件队列、当前仿真时刻,以及调用方
//! 判断一次运行所需的统计。一个事件意味着什么由调用方定义:它提供一个接收该事件并可
//! 再调度更多事件的处理器,而引擎只负责排序各次调用。
//!
//! 引擎保持仿真确定。同一瞬时的事件按它们被调度的次序投递,这是事件队列所保证的,故
//! 相同输入的一次运行产生相同输出。这正是使结果可复现、与另一实现的交叉核对有意义的
//! 原因。
//!
//! 引擎因四种原因之一停止,报告为一个 [`StopReason`]:队列排空、仿真达到其时限、
//! 调用方请求它停止,或达到事件上限。后两者存在,是为了让永远调度事件的模型无法无界
//! 运行。
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(missing_docs)] #![deny(missing_docs)]

View File

@ -1,7 +1,5 @@
//! Simulation facade that integrates the simulation layer. //! Simulation facade that integrates the simulation layer.
//! //!
//! 整合仿真层的仿真门面。
//!
//! This crate is the single entry point to the simulation layer. It ties the //! This crate is the single entry point to the simulation layer. It ties the
//! four pieces together: a [`Scenario`] describes the initial conditions, the //! four pieces together: a [`Scenario`] describes the initial conditions, the
//! ops layer plans it, the engine runs the resulting timeline, and a //! ops layer plans it, the engine runs the resulting timeline, and a
@ -51,6 +49,26 @@
//! assert_eq!(starts, 1); //! assert_eq!(starts, 1);
//! assert_eq!(report.outcome.executed, 2); //! assert_eq!(report.outcome.executed, 2);
//! ``` //! ```
//!
//! 整合仿真层的仿真门面。
//!
//! 本 crate 是仿真层的单一入口。它把四部分联系起来:[`Scenario`] 描述初始条件,
//! ops 层为其作计划,引擎运行所得时间线,[`Recorder`] 收集该运行所产生的。
//!
//! 调用方所遵循的序列很短:
//!
//! 1. [`Simulation::prepare`] 检查场景并为其作计划,产生一个调度。
//! 2. [`Simulation::start`] 把该调度转为由开始与结束事件构成的时间线,并交回一个
//! [`Session`]。
//! 3. [`Session::run`] 驱动引擎,在每个事件处调用一个处理器,并返回一个
//! [`RunReport`],其中含有引擎结果与轨迹。
//!
//! 该计划是贪心启发式,在 `apsis-scheduler` 中有述,故一次运行可能留下未放置的任务。
//! 门面报告这一点而非隐藏它:[`Simulation::plan`] 公开完整规划结果,而
//! [`Simulation::has_full_plan`] 直接回答那个常见的问题。
//!
//! 时间线是调度而非物理模型。任务开始时触发一个开始事件,结束时触发一个结束事件,
//! 这正是调用方随时间记录状态所需的;处理器提供该运行所需的任何物理或簿记。
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
#![deny(missing_docs)] #![deny(missing_docs)]