Sign in

    moonallen

    Bounded qualitative temporal interval constraint reasoning

    temporal
    allen
    interval-algebra
    constraints
    reasoning
    Download zip
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    9 hours ago
    Downloads
    2

    #MoonAllen

    MoonBit 原生的定性时间区间约束推理库,模块 yujieMamba/moonallen@0.1.0。

    当系统只知道“阶段 A 在 B 之前或与 B 相接”“标注 C 与 D 重叠”而没有精确时间戳时,MoonAllen 将这些关系作为可组合的约束,进行传播、有限搜索、见证校验和冲突解释。它不是日历、预约排程器或通用 SMT 求解器。

    #安装与最小集成

    moon add yujieMamba/moonallen@0.1.0

    在消费包的 moon.pkg 中导入:

    import {
    "yujieMamba/moonallen" @allen,
    }

    业务函数可以这样使用(调用方处理 AllenError):

    fn validate() -> @allen.SolveReport raise @allen.AllenError {
    let alg = @allen.Algebra::new()
    let net = @allen.Network::new(["ingest", "publish"])
    .restrict("ingest", "publish", @allen.parse_relset("b|m"))
    @allen.solve(alg, net, @allen.SearchOptions::new())
    }

    调用方应保留 SolveOutcome 的三个分支:可满足时校验见证,不可满足时处理冲突,未知时单独处理预算不足。完整的独立消费包位于 examples/,均通过公开 API 使用库,并带运行时断言。

    #三个完整工作流

    moon run examples/workflow # 相对阶段输入 -> 推理见证 -> 错误回边的可验证冲突核 moon run examples/annotation # 不确定事件标注 -> 精确可能关系 -> 蕴含反例 moon run examples/media # 具体区间观测 -> 策略检查/合并 -> JSON 和 DOT 报告

    • 工作流开发者:输入 ingest/validate/publish 的关系析取,传播后检验推导;为正常流程生成端点见证,对回边输出原始标签冲突核。
    • 事件标注工具作者:输入 speech/gesture/response 的不确定关系,逐原子查询可能性;每个可行关系有独立见证,并用反例否定过强标注。
    • 媒体编辑和质检系统:从合成数值片段导入定性观测,与 caption-contained 等策略合并;正常片段交换快照,越界片段定位冲突。示例不包含第三方媒体或个人数据。

    #关系与语义

    所有区间都是满足 start < end 的 proper intervals。坐标是整数序关系,不是闭/开区间交集或持续时间计算;相等端点按 Meets 区分。

    tokenRelationA 相对 B
    b / biBefore / After严格在前 / 在后
    m / miMeets / MetBy尾首相接 / 被相接
    o / oiOverlaps / OverlappedBy从前方重叠 / 从后方重叠
    s / siStarts / StartedBy同起点,A 更短 / 更长
    d / diDuring / Contains严格包含于 / 严格包含
    f / fiFinishes / FinishedBy同终点,A 更短 / 更长
    eqEqual两端点都相等

    b|m 表示备选关系,不是同时成立。* 为全部 13 个关系,- 为空集(明确矛盾)。重复约束取交集,逆向边自动保持 converse,对角线只允许 eq。冲突保留为空域,而非静默丢弃证据。Interval::relate 不做整数减法,可处理 Int 两端极值。

    #API 导航

    正式签名见 pkg.generated.mbti。

    API行为
    Relation, RelSet, Algebra13 关系、位集运算、converse、精确 composition
    Network::new/restrict/get不可变命名网络,源证据与当前域分离
    propagate, verify_trace有预算路径一致性传播、完整缩减轨迹重放
    solve, realize_atomicMRV 原子场景搜索;端点等式合并和严格序 DAG 实现
    possible_relations, entails可行/不可行/未知三分区;非空前提的蕴含及反例
    explain_unsat, verify_core源证据上的删除式 UNSAT 核、独立再验证
    observe, check_observations, add_observations数值区间到定性观测、部分观测核对
    merge_networks, compare_domains按名称合并当前矩阵、域变化统计
    induced, rename, components诱导子矩阵、重命名、独立分量
    parse_dsl, parse_network_json有界数据交换;快照与原始证据分别导出
    render, to_dot, to_json稳定可读报告、图和机器可读诊断

    #保证与不能推导的结论

    • PathConsistent 不是 SAT 证明;一般 Allen 析取约束不能只靠路径一致性完整判定。
    • Satisfiable(w) 包含可由 w.satisfies(net) 检查的具体序关系见证。见证坐标是端点秩,不能解读为实际时长或日程。
    • Unsatisfiable 来自空域、原子端点不可实现或完整分支排除。节点/操作预算不足返回 Unknown,不冒充 UNSAT。
    • entails 先确认前提可满足,矛盾前提返回 InconsistentInput,不作空真承诺。
    • 冲突核是原始 sources 的不可满足子集;minimal=true 仅表示删除任意一条后不再不可满足,不是最小条数。输入为闭包时,核解释的是其原始 sources,而非假设独立来源的推导边。
    • induced 只是保留当前两两域,不是完整的存在量词消去。
    • verify_trace 拒绝截断日志;它验证域缩减及状态,不认证公共报告中任意附加计数或冲突标签。

    #格式与预算

    DSL:空行及整行 # 注释;空格/制表符分词;允许先引用后声明。

    interval a interval b rel a b b|m input-ready

    名称以及可选 DSL 标签:1–128 个 ASCII 字符 [A-Za-z0-9_.-]。没有标签时自动采用行号标签。JSON 标签允许任意 Unicode(最长 256 个 UTF-16 单元)。格式详见 docs/formats.md。

    硬限制:64 个命名区间,4,096 条 sources,精确搜索最多 24 个区间;文本输入最多 1,048,576 个 UTF-16 单元,DSL 最多 10,000 行,JSON 嵌套最多 16 层。负值或过大预算抛出 AllenError。默认每次搜索 10,000 节点/1,000,000 次传播操作,每次传播至多记录 10,000 次缩减。最大允许预算为 1,000,000 节点/10,000,000 次操作/1,000,000 条轨迹。

    预算是逻辑工作量,不是毫秒或内存配额。关系可能性查询为每个 atom 独立分配预算;蕴含最多两次搜索,核提取为每次删除检查独立预算。服务端应在外部再加请求超时和并发限额。复杂度与语义论证见 docs/architecture.md,安全限制见 SECURITY.md。

    #验证

    发布验证工具链:moon 0.1.20261012 / moonc v0.10.15+943464bfa(2026-10-12)。使用 Int32 和当前 JSON 转换语法;不承诺旧编译器兼容。

    moon info && moon fmt moon fmt --check moon check --deny-warn moon test --deny-warn moon build --deny-warn # 针对 wasm-gc、wasm、js、native 重复严格检查、构建、测试和三个示例 moon test --target js --deny-warn

    测试包括全部 8,192 关系位集往返、169 composition 项的代数律、全部 2,197 个三节点原子网络与 256 个析取网络的独立端点穷举对照,以及畸形输入、资源上界、空网络、轨迹伪造、Unknown、冲突核和交换边界回归。所有数据和 oracle 由项目本身构造,不依赖网络或商业求解器。

    本机 wasm-gc/wasm/js 的检查、构建、49 个测试及三个示例均通过。native 严格类型检查通过;本机缺少 cc/gcc/clang,原生构建与执行由 Linux CI 实测。CI 在干净 Ubuntu runner 安装官方工具链,记录版本,执行全部四个目标。工程规模可运行 python scripts/audit.py 复算;不把示例、测试或生成接口计入生产行数,不宣称性能优于其他求解器或完整外部认证。

    #来源、许可与交付

    原创实现,Apache-2.0;无第三方 MoonCakes 依赖(仅标准 core)。Allen 理论参考、实现来源边界和相邻项目差异见 ATTRIBUTION.md、docs/competition/duplicate-check.md。AI 辅助范围见 AI-USE.md。

    本仓库不包含比赛申报书、私人联系资料、认证令牌或自动报名功能。比赛资格与验收由组织方最终决定。

    AllenError

    pub(all) suberror AllenError {
    InvalidRelation(String)
    InvalidMask(Int)
    InvalidInterval(Int, Int)
    InvalidName(String)
    DuplicateName(String)
    UnknownName(String)
    InvalidIndex(Int)
    InvalidLimit(String)
    InvalidFormat(String)
    TooLarge(Int)
    }

    Algebra

    pub struct Algebra {
    // private fields
    }

    Composition built from all weak order types of six endpoints. Any three intervals compress to at most six distinct ordered coordinates.

    Algebra::compose

    fn Algebra::compose(self : Algebra, a : RelSet, b : RelSet) -> RelSet

    Algebra::compose_atoms

    fn Algebra::compose_atoms(self : Algebra, a : Relation, b : Relation) -> RelSet

    Algebra::new

    fn Algebra::new() -> Algebra

    Algebra::row

    fn Algebra::row(self : Algebra, a : Relation) -> Array[RelSet]

    ClosureReport

    pub(all) struct ClosureReport {
    status : ClosureStatus
    network : Network
    operations : Int
    reductions : Array[Reduction]
    reduction_count : Int
    trace_complete : Bool
    conflict : Conflict?
    }

    ClosureReport::to_json

    fn ClosureReport::to_json(self : ClosureReport) -> Json

    ClosureStatus

    pub(all) enum ClosureStatus {
    PathConsistent
    Contradiction
    PropagationLimit
    } derive(Eq,
    Debug
    )

    ClosureStatus::equal

    ClosureStatus::not_equal

    fn ClosureStatus::not_equal(x : ClosureStatus, y : ClosureStatus) -> Bool

    ClosureStatus::token

    fn ClosureStatus::token(self : ClosureStatus) -> String

    Conflict

    pub(all) struct Conflict {
    left : String
    right : String
    via : String?
    }

    Constraint

    pub(all) struct Constraint {
    left : String
    right : String
    allowed : RelSet
    label : String
    } derive(Eq,
    Debug
    )

    Constraint::equal

    fn Constraint::equal(Constraint, Constraint) -> Bool

    Constraint::not_equal

    fn Constraint::not_equal(x : Constraint, y : Constraint) -> Bool

    CoreOutcome

    pub(all) enum CoreOutcome {
    ConflictCore(UnsatCore)
    SourceSatisfiable(Witness)
    CoreUnknown(SearchLimit)
    }

    DomainChange

    pub(all) struct DomainChange {
    left : String
    right : String
    before : RelSet
    after : RelSet
    removed : RelSet
    added : RelSet
    }

    Entailment

    pub(all) enum Entailment {
    Proven
    Refuted(Witness)
    InconsistentInput
    EntailmentUnknown(SearchLimit)
    }

    Interval

    pub struct Interval {
    // private fields
    } derive(Eq,
    Debug
    )

    Proper intervals require start < end. Coordinates have no calendar semantics.

    Interval::end

    fn Interval::end(self : Interval) -> Int

    Interval::equal

    fn Interval::equal(Interval, Interval) -> Bool

    Interval::new

    fn Interval::new(start : Int, end : Int) -> Interval raise AllenError

    Interval::not_equal

    fn Interval::not_equal(x : Interval, y : Interval) -> Bool

    Interval::relate

    fn Interval::relate(self : Interval, other : Interval) -> Relation

    Interval::start

    fn Interval::start(self : Interval) -> Int

    Interval::to_repr

    Network

    pub struct Network {
    // private fields
    }

    Immutable named matrix. Accessors copy arrays, and constraints intersect.

    Network::accepts

    fn Network::accepts(self : Network, spans : Array[Interval]) -> Bool

    Check an externally supplied model against every matrix domain.

    Network::at

    fn Network::at(self : Network, i : Int, j : Int) -> RelSet raise AllenError

    Network::components

    fn Network::components(self : Network) -> Array[Array[String]]

    Independent components of the non-universal domain graph, including isolates.

    Network::constrain

    fn Network::constrain(self : Network, constraint : Constraint) -> Network raise AllenError

    Network::constraints

    fn Network::constraints(self : Network) -> Array[Constraint]

    Network::domain_constraints

    fn Network::domain_constraints(self : Network, label? : String) -> Array[Constraint]

    Materialize current pairwise domains as fresh evidence. Original source labels are intentionally not claimed for inferred domains.

    Network::from_constraints

    fn Network::from_constraints(names : Array[String], constraints : Array[Constraint]) -> Network raise AllenError

    Network::get

    fn Network::get(self : Network, left : String, right : String) -> RelSet raise AllenError

    Network::index

    fn Network::index(self : Network, name : String) -> Int raise AllenError

    Network::induced

    fn Network::induced(self : Network, names : Array[String]) -> Network raise AllenError

    Induced pairwise view, NOT full existential quantifier elimination.

    Network::is_atomic

    fn Network::is_atomic(self : Network) -> Bool

    Network::is_refinement_of

    fn Network::is_refinement_of(self : Network, other : Network) -> Bool

    Network::names

    fn Network::names(self : Network) -> Array[String]

    Network::new

    fn Network::new(names : Array[String]) -> Network raise AllenError

    Network::rename

    fn Network::rename(self : Network, names : Array[String]) -> Network raise AllenError

    Positional renaming preserves all matrix domains and source labels.

    Network::render

    fn Network::render(self : Network) -> String

    Compact deterministic pair listing, including empty diagonal constraints.

    Network::restrict

    fn Network::restrict(self : Network, left : String, right : String, allowed : RelSet, label? : String) -> Network raise AllenError

    Network::same_domains

    fn Network::same_domains(self : Network, other : Network) -> Bool

    Network::size

    fn Network::size(self : Network) -> Int

    Network::sources_json

    fn Network::sources_json(self : Network) -> Json

    Export original evidence separately. For propagated networks, decoding this reconstructs the input domains, not the narrower inferred snapshot.

    Network::stats

    fn Network::stats(self : Network) -> NetworkStats

    Network::to_dot

    fn Network::to_dot(self : Network) -> String

    Names are restricted ASCII identifiers and all edge labels are canonical relation tokens. User-provided source labels are never interpolated into DOT.

    Network::to_dsl

    fn Network::to_dsl(self : Network) -> String

    Export the current matrix, not original provenance. Inferred domains get explicit snapshot labels. The result parses to exactly the same domains.

    Network::to_json

    fn Network::to_json(self : Network) -> Json

    Current-domain snapshot. Original labels are not attributed to deductions.

    NetworkStats

    pub(all) struct NetworkStats {
    intervals : Int
    pairs : Int
    constrained_pairs : Int
    atomic_pairs : Int
    ambiguous_pairs : Int
    empty_domains : Int
    alternatives : Int
    source_constraints : Int
    }

    NetworkStats::to_json

    fn NetworkStats::to_json(self : NetworkStats) -> Json

    ObservationConflict

    pub(all) struct ObservationConflict {
    left : String
    right : String
    expected : RelSet
    observed : Relation
    }

    PossibilityReport

    pub(all) struct PossibilityReport {
    possible : RelSet
    impossible : RelSet
    unknown : RelSet
    models : Array[RelationModel]
    nodes : Int
    operations : Int
    }

    PropagationOptions

    pub struct PropagationOptions {
    // private fields
    }

    PropagationOptions::new

    fn PropagationOptions::new(max_operations? : Int, max_trace? : Int) -> PropagationOptions raise AllenError

    Reduction

    pub(all) struct Reduction {
    left : Int
    right : Int
    via : Int
    before : RelSet
    after : RelSet
    }

    RelSet

    pub struct RelSet {
    // private fields
    } derive(Eq,
    Debug
    )

    A validated set of alternatives, not simultaneous relations.

    RelSet::all

    fn RelSet::all() -> RelSet

    RelSet::converse

    fn RelSet::converse(self : RelSet) -> RelSet

    RelSet::difference

    fn RelSet::difference(self : RelSet, other : RelSet) -> RelSet

    RelSet::empty

    fn RelSet::empty() -> RelSet

    RelSet::equal

    fn RelSet::equal(RelSet, RelSet) -> Bool

    RelSet::from_mask

    fn RelSet::from_mask(mask : Int) -> RelSet raise AllenError

    RelSet::has

    fn RelSet::has(self : RelSet, r : Relation) -> Bool

    RelSet::intersect

    fn RelSet::intersect(self : RelSet, other : RelSet) -> RelSet

    RelSet::is_empty

    fn RelSet::is_empty(self : RelSet) -> Bool

    RelSet::items

    fn RelSet::items(self : RelSet) -> Array[Relation]

    RelSet::mask

    fn RelSet::mask(self : RelSet) -> Int

    RelSet::not_equal

    fn RelSet::not_equal(x : RelSet, y : RelSet) -> Bool

    RelSet::of

    fn RelSet::of(items : Array[Relation]) -> RelSet

    RelSet::render

    fn RelSet::render(self : RelSet) -> String

    RelSet::single

    fn RelSet::single(r : Relation) -> RelSet

    RelSet::size

    fn RelSet::size(self : RelSet) -> Int

    RelSet::subset_of

    fn RelSet::subset_of(self : RelSet, other : RelSet) -> Bool

    RelSet::to_repr

    RelSet::union

    fn RelSet::union(self : RelSet, other : RelSet) -> RelSet

    Relation

    pub(all) enum Relation {
    Before
    Meets
    Overlaps
    Starts
    During
    Finishes
    Equal
    After
    MetBy
    OverlappedBy
    StartedBy
    Contains
    FinishedBy
    } derive(Eq,
    Debug
    )

    The thirteen jointly exhaustive, pairwise disjoint proper-interval relations.

    Relation::converse

    fn Relation::converse(self : Relation) -> Relation

    Relation::equal

    fn Relation::equal(Relation, Relation) -> Bool

    Relation::index

    fn Relation::index(self : Relation) -> Int

    Relation::not_equal

    fn Relation::not_equal(x : Relation, y : Relation) -> Bool

    Relation::to_repr

    Relation::token

    fn Relation::token(self : Relation) -> String

    RelationModel

    pub(all) struct RelationModel {
    relation : Relation
    witness : Witness
    }

    SearchLimit

    pub(all) enum SearchLimit {
    NodeBudget
    OperationBudget
    } derive(Eq,
    Debug
    )

    SearchLimit::equal

    fn SearchLimit::equal(SearchLimit, SearchLimit) -> Bool

    SearchLimit::not_equal

    fn SearchLimit::not_equal(x : SearchLimit, y : SearchLimit) -> Bool

    SearchLimit::token

    fn SearchLimit::token(self : SearchLimit) -> String

    SearchOptions

    pub struct SearchOptions {
    // private fields
    }

    SearchOptions::new

    fn SearchOptions::new(max_nodes? : Int, max_operations? : Int) -> SearchOptions raise AllenError

    SolveOutcome

    pub(all) enum SolveOutcome {
    Satisfiable(Witness)
    Unsatisfiable
    Unknown(SearchLimit)
    }

    SolveReport

    pub(all) struct SolveReport {
    outcome : SolveOutcome
    nodes : Int
    operations : Int
    maximum_depth : Int
    }

    SolveReport::to_json

    fn SolveReport::to_json(self : SolveReport) -> Json

    UnsatCore

    pub(all) struct UnsatCore {
    constraints : Array[Constraint]
    minimal : Bool
    checks : Int
    unresolved_checks : Int
    }

    Witness

    pub struct Witness {
    // private fields
    }

    Witness::get

    fn Witness::get(self : Witness, name : String) -> Interval raise AllenError

    Witness::intervals

    fn Witness::intervals(self : Witness) -> Array[Interval]

    Witness::names

    fn Witness::names(self : Witness) -> Array[String]

    Witness::render

    fn Witness::render(self : Witness) -> String

    Witness::satisfies

    fn Witness::satisfies(self : Witness, net : Network) -> Bool

    Witness::to_json

    fn Witness::to_json(self : Witness) -> Json

    add_observations

    fn add_observations(net : Network, names : Array[String], spans : Array[Interval]) -> Network raise AllenError

    Add measured qualitative evidence while preserving all earlier source labels.

    check_observations

    fn check_observations(net : Network, names : Array[String], spans : Array[Interval]) -> Array[ObservationConflict] raise AllenError

    Check only supplied observations without asserting anything about missing spans.

    compare_domains

    fn compare_domains(before : Network, after : Network) -> Array[DomainChange] raise AllenError

    Compare same-named matrices even when their positional orders differ.

    entails

    fn entails(alg : Algebra, net : Network, left : String, right : String, claim : RelSet, options : SearchOptions) -> Entailment raise AllenError

    Avoid vacuous entailment by requiring the premise network to be satisfiable.

    explain_unsat

    fn explain_unsat(alg : Algebra, net : Network, options : SearchOptions, max_checks? : Int) -> CoreOutcome raise AllenError

    Extract a subset of original source constraints, not a shortest contradiction. A core remains UNSAT throughout; minimal is true only after all deletion checks.

    is_path_consistent

    fn is_path_consistent(alg : Algebra, net : Network) -> Bool

    Validate that a matrix has no empty domains and is closed under composition.

    merge_networks

    fn merge_networks(left : Network, right : Network) -> Network raise AllenError

    Merge current domains by interval name; conflicts remain visible as empty sets. This is a matrix snapshot merge, so source evidence is labeled by input side.

    network_from_json

    fn network_from_json(value : Json) -> Network raise AllenError

    Schema-strict value decoder. Every object field is required; unknown fields and non-string relation sets are rejected. Empty relation sets are legal.

    observe

    fn observe(names : Array[String], spans : Array[Interval]) -> Network raise AllenError

    Import concrete spans as an atomic qualitative network; coordinates are discarded.

    parse_dsl

    fn parse_dsl(text : String) -> Network raise AllenError

    Bounded line DSL: interval NAME; rel LEFT RIGHT SET [ASCII-LABEL]. Only whole-line # comments are recognized. Declarations may follow relations.

    parse_network_json

    fn parse_network_json(text : String) -> Network raise AllenError

    Bounded core JSON parser (1 Mi UTF-16 units, depth 16). Duplicate object keys follow core JSON last-key-wins semantics; use unique keys for interchange.

    parse_relation

    fn parse_relation(text : String) -> Relation raise AllenError

    parse_relset

    fn parse_relset(text : String) -> RelSet raise AllenError

    possible_relations

    fn possible_relations(alg : Algebra, net : Network, left : String, right : String, options : SearchOptions) -> PossibilityReport raise AllenError

    Each atom gets an independent search budget. Unknown is not possible or impossible.

    propagate

    fn propagate(alg : Algebra, net : Network, options : PropagationOptions) -> ClosureReport

    Monotonic path-consistency closure; success is not a SAT claim.

    realize_atomic

    fn realize_atomic(net : Network) -> Witness? raise AllenError

    Atomic networks reduce exactly to endpoint equalities and strict inequalities. None means a cyclic strict order, not failure to find a heuristic schedule.

    relations

    fn relations() -> Array[Relation]

    solve

    fn solve(alg : Algebra, net : Network, options : SearchOptions) -> SolveReport raise AllenError

    Finite complete branching, bounded globally. Exhaustion is never UNSAT.

    verify_core

    fn verify_core(alg : Algebra, names : Array[String], core : UnsatCore, options : SearchOptions) -> SolveReport raise AllenError

    Validate UNSAT for a reported core; budget exhaustion returns Unknown.

    verify_trace

    fn verify_trace(alg : Algebra, initial : Network, report : ClosureReport) -> Bool

    Replay a complete trace against its initial matrix, rejecting forged steps. Truncated traces deliberately fail; their result may still be valid.