更新日志 ======== 本文档记录 PyNetIM 项目的所有重要变更。 格式基于 `Keep a Changelog `_。 [0.4.5] - 2026-04-04 ------------------------ 新增 ~~~~ **SI 和 SIR 扩散模型 (C++ 后端)**: * 新增 ``SusceptibleInfectedModel`` - SI 传播模型 * 新增 ``SusceptibleInfectedRecoveredModel`` - SIR 传播模型 * 支持参数设置:``beta``(感染概率)、``gamma``(恢复概率)、``max_steps``(最大步数) * 支持单次模拟和 Monte Carlo 多轮模拟 * 支持多线程并行模拟 * 支持激活节点记录和激活频率记录 **Graph 构造函数支持统一权重**: * ``IMGraphCpp(num_nodes, edges, weights=1.0)`` - 默认所有边权重为 1.0 * ``IMGraphCpp(num_nodes, edges, 0.3)`` - 所有边使用统一权重 0.3 * ``IMGraphCpp(num_nodes, edges, [0.1, 0.2, ...])`` - 每条边使用各自的权重 API 更新 ~~~~~~~~ **SusceptibleInfectedModel**: * 构造函数:``SusceptibleInfectedModel(graph, seeds, beta=0.1, max_steps=100, record_activated=False, record_activation_frequency=False)`` * ``set_beta(beta: float)`` - 设置感染概率 * ``set_max_steps(max_steps: int)`` - 设置最大传播步数 * ``run_single_simulation(seed=None) -> int`` - 单次模拟 * ``run_monte_carlo_diffusion(rounds, seed=None, use_multithread=False, num_threads=0) -> float`` - Monte Carlo 模拟 * ``get_activated_nodes() -> Set[int]`` - 获取激活节点集合 * ``get_activation_frequency() -> List[int]`` - 获取激活频率 **SusceptibleInfectedRecoveredModel**: * 构造函数:``SusceptibleInfectedRecoveredModel(graph, seeds, beta=0.1, gamma=0.1, record_activated=False, record_activation_frequency=False)`` * ``set_beta(beta: float)`` - 设置感染概率 * ``set_gamma(gamma: float)`` - 设置恢复概率 * ``run_single_simulation(seed=None) -> int`` - 单次模拟 * ``run_monte_carlo_diffusion(rounds, seed=None, use_multithread=False, num_threads=0) -> float`` - Monte Carlo 模拟 * ``get_activated_nodes() -> Set[int]`` - 获取激活节点集合 * ``get_activation_frequency() -> List[int]`` - 获取激活频率 **IMGraphCpp**: * ``weights`` 参数现在支持 ``float`` 类型,表示所有边使用统一权重 代码重构 ~~~~~~~~ **扩散模型文件分离**: * 将扩散模型从单一文件分离到独立文件 * ``independent_cascade.h`` - IC 模型 * ``linear_threshold.h`` - LT 模型 * ``susceptible_infected.h`` - SI 模型 * ``susceptible_infected_recovered.h`` - SIR 模型 * ``common.h`` - 共享代码(ObjectPool、RNG 工具函数) 测试 ~~~~ **新增完整测试覆盖**: * ``test_ic_model.py`` - IC 模型完整测试 * ``test_lt_model.py`` - LT 模型完整测试 * ``test_si_model.py`` - SI 模型完整测试 * ``test_sir_model.py`` - SIR 模型完整测试 * 单线程和多线程结果一致性验证通过 * 参数验证测试通过(beta、gamma 范围检查) 技术细节 ~~~~~~~~ **修改文件**: * ``src/pynetim/cpp/include/common.h`` - 共享工具代码 * ``src/pynetim/cpp/include/independent_cascade.h`` - IC 模型 * ``src/pynetim/cpp/include/linear_threshold.h`` - LT 模型 * ``src/pynetim/cpp/include/susceptible_infected.h`` - SI 模型 * ``src/pynetim/cpp/include/susceptible_infected_recovered.h`` - SIR 模型 * ``src/pynetim/cpp/include/diffusion_model.h`` - 主头文件 * ``src/pynetim/cpp/bindings/si_bind.cpp`` - SI 模型绑定 * ``src/pynetim/cpp/bindings/sir_bind.cpp`` - SIR 模型绑定 * ``src/pynetim/cpp/include/Graph.h`` - Graph 类统一权重支持 * ``src/pynetim/cpp/bindings/graph_bind.cpp`` - Graph 绑定更新 **实现细节**: * SI 模型:每个时间步,感染节点以概率 beta 尝试感染邻居 * SIR 模型:在 SI 基础上,感染节点每步以概率 gamma 恢复 * 参数验证:beta、gamma ∈ (0, 1],max_steps > 0 * 多线程种子预生成策略确保单线程和多线程结果完全一致 使用示例 ~~~~~~~~ .. code-block:: python import pynetim.cpp.graph as im_graph import pynetim.cpp.diffusion_model as diffusion_model # 创建图(统一权重) graph = im_graph.IMGraphCpp(100, [(i, i+1) for i in range(99)], 0.3) seeds = {0} # SI 模型 si = diffusion_model.SusceptibleInfectedModel(graph, seeds, beta=0.3) avg = si.run_monte_carlo_diffusion(1000, seed=42) print(f"SI 平均感染节点数: {avg:.2f}") # SIR 模型 sir = diffusion_model.SusceptibleInfectedRecoveredModel(graph, seeds, beta=0.3, gamma=0.1) avg = sir.run_monte_carlo_diffusion(1000, seed=42) print(f"SIR 平均感染节点数: {avg:.2f}") # 多线程模拟 avg = sir.run_monte_carlo_diffusion(10000, seed=42, use_multithread=True) print(f"多线程 SIR 平均感染节点数: {avg:.2f}") # 记录激活节点 sir = diffusion_model.SusceptibleInfectedRecoveredModel( graph, seeds, beta=0.3, gamma=0.1, record_activated=True ) count = sir.run_single_simulation(seed=42) activated = sir.get_activated_nodes() print(f"激活节点: {activated}") [0.4.4] - 2026-03-30 ------------------------ 新增 ~~~~ **分离模拟执行和结果获取**: * ``run_single_simulation()`` 现在只返回激活节点数量(``int``),不再返回节点集合 * 新增 ``get_activated_nodes()`` 方法,专门用于获取记录的激活节点集合 * 只有在 ``record_activated=True`` 时,``get_activated_nodes()`` 才返回有效数据 * 当 ``record_activated=False`` 时,``get_activated_nodes()`` 返回空集合 **多轮模拟记录激活节点并集**: * ``run_monte_carlo_diffusion()`` 现在支持记录所有试验的激活节点并集 * 当 ``record_activated=True`` 时,``get_activated_nodes()`` 返回所有试验中被激活过的节点(并集) * 对于单次模拟:返回该次模拟的激活节点集合 * 对于 Monte Carlo 模拟:返回所有试验的激活节点并集 **激活频率记录功能**: * 新增 ``record_activation_frequency`` 参数(默认为 ``false``),用于控制是否记录每个节点的激活频率 * 新增 ``set_record_activation_frequency(record)`` 方法,可在运行时动态开启/关闭记录功能 * 新增 ``get_activation_frequency()`` 方法,返回每个节点被激活的次数 * 只有在 ``record_activation_frequency=True`` 时,``get_activation_frequency()`` 才返回有效数据 * 当 ``record_activation_frequency=False`` 时,``get_activation_frequency()`` 返回全 0 的列表 * 可以同时开启 ``record_activated`` 和 ``record_activation_frequency``,记录两种数据 API 更新 ~~~~~~~~ **IndependentCascadeModel**: * ``run_single_simulation()`` 的返回值从 ``Set[int]`` 改为 ``int``(激活节点数量) * 新增 ``get_activated_nodes() -> Set[int]`` 方法,用于获取记录的激活节点集合 * 新增 ``get_activation_frequency() -> List[int]`` 方法,用于获取每个节点的激活频率 * 新增 ``set_record_activation_frequency(record: bool)`` 方法,用于动态开启/关闭激活频率记录 * ``run_single_simulation()`` 的 ``seed`` 参数类型从 ``int`` 改为 ``int | None``,默认值从 ``0`` 改为 ``None`` * ``run_monte_carlo_diffusion()`` 的 ``seed`` 参数类型从 ``int`` 改为 ``int | None``,默认值从 ``0`` 改为 ``None`` * 构造函数新增 ``record_activation_frequency`` 参数(默认为 ``false``) **LinearThresholdModel**: * ``run_single_simulation()`` 的返回值从 ``Set[int]`` 改为 ``int``(激活节点数量) * 新增 ``get_activated_nodes() -> Set[int]`` 方法,用于获取记录的激活节点集合 * 新增 ``get_activation_frequency() -> List[int]`` 方法,用于获取每个节点的激活频率 * 新增 ``set_record_activation_frequency(record: bool)`` 方法,用于动态开启/关闭激活频率记录 * ``run_single_simulation()`` 的 ``seed`` 参数类型从 ``int`` 改为 ``int | None``,默认值从 ``0`` 改为 ``None`` * ``run_monte_carlo_diffusion()`` 的 ``seed`` 参数类型从 ``int`` 改为 ``int | None``,默认值从 ``0`` 改为 ``None`` * 构造函数新增 ``record_activation_frequency`` 参数(默认为 ``false``) 优化 ~~~~ **改进随机种子生成机制**: * ``run_single_simulation()`` 和 ``run_monte_carlo_diffusion()`` 方法现在都支持 ``seed=None`` 参数 * 当 ``seed=None`` 时,使用多个 ``std::random_device`` 值的组合来增强随机性 * 当 ``seed=固定值`` 时,使用固定种子,确保模拟结果可重现 * 改进后的随机种子生成方式解决了在某些平台(虚拟环境、容器)上 ``std::random_device`` 返回相同值的问题 * 使用 ``std::seed_seq`` 和多个随机值组合,确保每次调用都能得到不同的结果 **多线程随机种子一致性**: * ``run_monte_carlo_diffusion()`` 采用种子预生成策略 * 在开始任何模拟之前,使用主随机数生成器预生成所有试验的种子 * 每个试验使用独立的种子,确保单线程和多线程结果完全一致 * 多线程只是改变了试验的执行顺序和并行度,但没有改变每个试验使用的随机数序列 修复 ~~~~ **修复 ``set_record_activated()`` 的清空逻辑**: * 当 ``set_record_activated(False)`` 被调用时,现在会清空 ``last_activated_nodes`` * 避免了返回过期的激活节点数据 * 确保当 ``record_activated=False`` 时,``get_activated_nodes()`` 总是返回空集合 **修复 ``set_record_activation_frequency()`` 的清空逻辑**: * 当 ``set_record_activation_frequency(False)`` 被调用时,现在会清空 ``activation_frequency`` * 避免了返回过期的激活频率数据 * 确保当 ``record_activation_frequency=False`` 时,``get_activation_frequency()`` 总是返回全 0 的列表 测试 ~~~~ **新增功能验证测试**: * IC 模型单次模拟测试(简单链式图、星形图、低权重图) * LT 模型单次模拟测试 * 多个种子节点测试 * ``record_activated=False`` 测试 * ``set_record_activated()`` 动态切换测试 * 多次调用 ``get_activated_nodes()`` 测试 * 无向图测试 * 随机种子功能测试 * 多轮模拟测试(单线程和多线程) * 大规模模拟测试(10000 轮) * ``record_activated`` 对多轮模拟性能影响测试 * 多轮模拟 vs 单次模拟对比测试 * 编译和运行测试全部通过 **测试结果**: * 简单链式图 (权重=1.0): 激活节点数量=5, 激活节点集合={0, 1, 2, 3, 4} ✅ * 星形图 (权重=1.0): 激活节点数量=5, 激活节点集合={0, 1, 2, 3, 4} ✅ * 低权重图 (权重=0.01): 激活节点数量=1, 激活节点集合={0} ✅ * 多个种子节点: 激活节点数量=6, 激活节点集合={0, 1, 2, 3, 4, 5} ✅ * record_activated=False: 返回激活节点数量,不记录节点集合 ✅ * record_activated=True: 返回激活节点数量,记录节点集合 ✅ * 动态切换 record_activated: 正确清空和记录节点集合 ✅ * 多次调用 get_activated_nodes(): 返回相同的集合 ✅ * 无向图: 正确处理无向图的传播 ✅ * 随机种子 (seed=None): 每次模拟结果可能不同 ✅ * 固定种子 (seed=42): 多次模拟结果完全相同 ✅ * 单线程和多线程: 多轮模拟结果完全一致(差异 < 1e-10)✅ * 固定种子可重现性: 3次运行结果完全相同 ✅ * record_activated 影响: 不影响多轮模拟结果(差异 = 0.0000)✅ * 大规模模拟: 10000 轮模拟稳定运行 ✅ 技术细节 ~~~~~~~~ **修改文件**: * ``src/pynetim/cpp/include/diffusion_model.h`` - 添加核心功能实现、改进随机种子生成、修复清空逻辑 * ``src/pynetim/cpp/bindings/ic_bind.cpp`` - IC 模型 Python 绑定,更新 API 文档 * ``src/pynetim/cpp/bindings/lt_bind.cpp`` - LT 模型 Python 绑定,更新 API 文档 * ``src/pynetim/cpp/diffusion_model/independent_cascade_model.pyi`` - 类型提示 * ``src/pynetim/cpp/diffusion_model/linear_threshold_model.pyi`` - 类型提示 **实现细节**: * ``run_single_trial`` 方法新增 ``activated_nodes`` 参数,用于记录激活节点 * 添加 ``last_activated_nodes`` 成员变量(``mutable std::set``),存储最后一次模拟的激活节点 * 当 ``record_activated`` 为 ``true`` 时,遍历所有节点收集激活的节点到 ``last_activated_nodes`` * 当 ``record_activated`` 为 ``false`` 时,不收集激活节点,``last_activated_nodes`` 保持为空 * ``run_single_simulation()`` 返回激活节点数量(``int``),不再返回节点集合 * 新增 ``get_activated_nodes()`` 方法,返回 ``last_activated_nodes`` 的副本 * ``set_record_activated()`` 方法在设置为 ``false`` 时清空 ``last_activated_nodes`` * 使用独立的随机数生成器确保每次模拟的独立性 * 保持向后兼容性,``record_activated`` 默认为 ``false`` * 随机种子生成改进: 使用多个 ``std::random_device`` 值和 ``std::seed_seq`` 组合 * 多线程种子预生成策略: 在开始任何模拟之前,使用主随机数生成器预生成所有试验的种子 * Python 绑定层检测 ``seed`` 参数是否为 ``None``,自动转换为 ``use_random_seed`` 标志 * ``record_activated`` 参数不影响 ``run_monte_carlo_diffusion()`` 的性能和结果 * 多线程模式下,每个线程使用独立的随机数生成器,确保线程安全和结果一致性 使用示例 ~~~~~~~~ .. code-block:: python # IC 模型 from pynetim.cpp.diffusion_model import IndependentCascadeModel # 不记录激活节点(默认) ic_model = IndependentCascadeModel(graph, seeds) count = ic_model.run_single_simulation() # 随机种子 print(f"激活节点数量: {count}") # 记录激活节点 ic_model = IndependentCascadeModel(graph, seeds, record_activated=True) count = ic_model.run_single_simulation(seed=42) # 固定种子 activated_nodes = ic_model.get_activated_nodes() print(f"激活节点数量: {count}") print(f"激活的节点: {activated_nodes}") # 动态切换记录 ic_model.set_record_activated(True) count = ic_model.run_single_simulation() activated_nodes = ic_model.get_activated_nodes() ic_model.set_record_activated(False) count = ic_model.run_single_simulation() activated_nodes = ic_model.get_activated_nodes() # 空集合 # LT 模型 from pynetim.cpp.diffusion_model import LinearThresholdModel lt_model = LinearThresholdModel(graph, seeds, theta_l=0.0, theta_h=1.0, record_activated=True) count = lt_model.run_single_simulation() # 随机种子 activated_nodes = lt_model.get_activated_nodes() print(f"激活节点数量: {count}") print(f"激活的节点: {activated_nodes}") # 多轮模拟 avg_count = ic_model.run_monte_carlo_diffusion(1000) # 随机种子 print(f"平均激活节点数: {avg_count:.2f}") avg_count = ic_model.run_monte_carlo_diffusion(1000, seed=42) # 固定种子 print(f"平均激活节点数: {avg_count:.2f}") # 多线程多轮模拟 avg_count = ic_model.run_monte_carlo_diffusion(1000, seed=42, use_multithread=True, num_threads=4) print(f"平均激活节点数: {avg_count:.2f}") # 激活频率记录 ic_model = IndependentCascadeModel(graph, seeds, record_activation_frequency=True) avg_count = ic_model.run_monte_carlo_diffusion(1000, seed=42) freq = ic_model.get_activation_frequency() print(f"节点激活频率: {freq}") # 同时记录激活节点和频率 ic_model = IndependentCascadeModel(graph, seeds, record_activated=True, record_activation_frequency=True) avg_count = ic_model.run_monte_carlo_diffusion(1000, seed=42) activated_nodes = ic_model.get_activated_nodes() # 所有试验的激活节点并集 freq = ic_model.get_activation_frequency() # 每个节点的激活次数 print(f"所有试验中被激活过的节点: {activated_nodes}") print(f"节点激活频率: {freq}") [0.4.3] - 2026-03-30 ------------------------ 新增 ~~~~ **IC 和 LT 模型新增激活节点记录功能**: * 添加 ``record_activated`` 参数(默认为 ``false``),用于控制是否记录种子集激活的节点 * 添加 ``set_record_activated(record)`` 方法,可在运行时动态开启/关闭记录功能 * 添加 ``run_single_simulation(seed=0)`` 方法,用于单次独立传播模拟 * 每次调用 ``run_single_simulation`` 都会进行一次独立的传播模拟,从种子集出发,返回该次模拟中被激活的所有节点 * 支持通过不同的 ``seed`` 参数进行多次独立的模拟实验 API 更新 ~~~~~~~~ **IndependentCascadeModel**: * 构造函数新增 ``record_activated`` 参数 * 新增 ``set_record_activated(record: bool)`` 方法 * 新增 ``run_single_simulation(seed: int = 0) -> Set[int]`` 方法 **LinearThresholdModel**: * 构造函数新增 ``record_activated`` 参数 * 新增 ``set_record_activated(record: bool)`` 方法 * 新增 ``run_single_simulation(seed: int = 0) -> Set[int]`` 方法 测试 ~~~~ **新增功能验证测试**: * IC 模型单次模拟测试 * LT 模型单次模拟测试 * 多次独立模拟测试(使用不同 seed) * ``set_record_activated`` 动态切换测试 * 编译和运行测试全部通过 技术细节 ~~~~~~~~ **修改文件**: * ``src/pynetim/cpp/include/diffusion_model.h`` - 添加核心功能实现 * ``src/pynetim/cpp/bindings/ic_bind.cpp`` - IC 模型 Python 绑定 * ``src/pynetim/cpp/bindings/lt_bind.cpp`` - LT 模型 Python 绑定 * ``src/pynetim/cpp/diffusion_model/independent_cascade_model.pyi`` - 类型提示 * ``src/pynetim/cpp/diffusion_model/linear_threshold_model.pyi`` - 类型提示 **实现细节**: * ``run_single_trial`` 方法新增 ``activated_nodes`` 参数,用于记录激活节点 * 当 ``record_activated`` 为 ``true`` 时,遍历所有节点收集激活的节点 * 使用独立的随机数生成器确保每次模拟的独立性 * 保持向后兼容性,``record_activated`` 默认为 ``false`` 使用示例 ~~~~~~~~ .. code-block:: python # IC 模型 from pynetim.cpp.diffusion_model import IndependentCascadeModel ic_model = IndependentCascadeModel(graph, seeds, record_activated=True) activated_nodes = ic_model.run_single_simulation(seed=42) print(f"激活的节点: {activated_nodes}") # LT 模型 from pynetim.cpp.diffusion_model import LinearThresholdModel lt_model = LinearThresholdModel(graph, seeds, theta_l=0.0, theta_h=1.0, record_activated=True) activated_nodes = lt_model.run_single_simulation(seed=42) print(f"激活的节点: {activated_nodes}") # 动态开启/关闭记录 ic_model.set_record_activated(True) [0.4.2] - 2026-03-24 ------------------------ 修复 ~~~~ **C++ 扩展线程安全修复**: * 修复 ``IndependentCascadeModel`` 和 ``LinearThresholdModel`` 在多线程模式下的线程安全问题 * 通过参数传递替代直接访问成员变量 ``seeds``,消除跨线程共享 ``std::set`` 的状态 * 解决了与 PyTorch 等多线程库结合使用时的 segmentation fault 问题 * 经过严格测试:5000 次迭代、8 线程并发、10 图并发均稳定运行 * 单线程和多线程结果完全一致,确保正确性 测试 ~~~~ **新增严格验证测试**: * 单线程/多线程一致性测试 * 长时间多线程压力测试 (2000 次迭代) * 多线程并发访问测试 (8 线程) * 多图并发处理测试 (10 个图) * 极限压力测试 (5000 次迭代) [0.4.0] - 2026-03-23 ------------------------ 新增 ~~~~ * **C++ 图支持**: 为所有工具函数添加了对 ``IMGraphCpp``(C++ 图)的完整支持 - ``set_edge_weight()`` - 支持 C++ 图的边权重设置 - ``infection_threshold()`` - 支持 C++ 图的感染阈值计算 - ``graph_statistics()`` - 支持 C++ 图的统计信息计算 - ``graph_density()`` - 支持 C++ 图的密度计算 - ``connectivity_analysis()`` - 支持 C++ 图的连通性分析 优化 ~~~~ **性能优化**: * ``infection_threshold()`` - 避免重复计算度字典 * ``graph_statistics()`` - 使用 ``Counter`` 替代手动循环统计度分布 * ``connectivity_analysis()`` - 合并有向图和无向图的分支逻辑,消除重复代码 * ``graph_density()`` - 修复整数除法问题,确保返回浮点数 **代码质量**: * 删除无用的 ``TYPE_CHECKING`` 代码块 * 统一函数签名,支持多种图类型 * 优化导入语句,添加缺失的 ``networkx`` 模块 修复 ~~~~ **Bug 修复**: * 修复 ``utils.py`` 中缺失的 ``import networkx as nx`` 导入 * 修复 ``graph_density()`` 函数中的整数除法 ``// 2`` 导致的精度丢失 * 修复 ``infection_threshold()`` 函数中重复调用 ``dict(graph.degree())`` 的性能问题 文档 ~~~~ **学术参考文献**: 为所有主要模型和算法添加了学术参考文献 **传播模型**: * Linear Threshold Model - Granovetter (1978) * Independent Cascade Model - Kempe et al. (2003) * SIR Model - Kermack & McKendrick (1927) * SI Model - Kermack & McKendrick (1927) **影响力最大化算法**: * Degree Discount Algorithm - Chen et al. (2009) * Reverse Influence Sampling (RIS) - Borgs et al. (2014) * IMM Algorithm - Tang et al. (2015) **工具函数**: * ``infection_threshold()`` - Pastor-Satorras & Vespignani (2001, 2015) **新增文档**: * ``UTILS_OPTIMIZATION_SUMMARY.md`` - utils.py 优化总结 * ``OPTIMIZATION_SUMMARY.md`` - C++ 模块优化总结 * ``REFERENCES_DOCUMENTATION.md`` - 参考文献添加文档 * ``CHANGELOG.md`` - 本更新日志 兼容性 ~~~~~~ **向后兼容**: 所有修改都保持了向后兼容性 * NetworkX 图的使用方式完全不变 * 新增的 C++ 图支持是可选的 * 函数签名使用 ``Union`` 类型,支持两种图类型 技术细节 ~~~~~~~~ * **图类型检测**: 使用 ``hasattr(graph, 'num_nodes') and hasattr(graph, 'directed')`` 检测 C++ 图 * **类型注解**: 使用 ``TYPE_CHECKING`` 避免循环导入 ``IMGraphCpp`` * **统一接口**: NetworkX 图和 C++ 图使用相同的函数接口 [0.3.0] - 2025-XX-XX ------------------------ 新增 ~~~~ * 初始版本发布 * 实现了多种影响力最大化算法 * 实现了多种传播模型 * 提供了 Python 和 C++ 双实现 版本说明 ======== PyNetIM 遵循 `语义化版本控制 `_ (Semantic Versioning): * **主版本号 (MAJOR)**: 不兼容的 API 修改 * **次版本号 (MINOR)**: 向下兼容的功能性新增 * **修订号 (PATCH)**: 向下兼容的问题修正 版本类型 -------- * **主版本更新**: 重大架构变更、API 不兼容 * **次版本更新**: 新增功能、性能优化 * **修订版本更新**: Bug 修复、文档更新 更新分类 -------- 功能新增 ~~~~~~~~ * 新的算法实现 * 新的传播模型 * 新的图操作功能 性能优化 ~~~~~~~~ * 算法效率提升 * 内存使用优化 * 计算速度提升 Bug 修复 ~~~~~~~~ * 代码错误修复 * 边界情况处理 * 兼容性问题修复 文档改进 ~~~~~~~~ * API 文档更新 * 示例代码更新 * 学术参考文献添加 内部改进 ~~~~~~~~ * 代码重构 * 测试覆盖提升 * 构建流程优化 贡献指南 ======== 如果您想为 PyNetIM 做出贡献,请: 1. Fork 本仓库 2. 创建特性分支 (``git checkout -b feature/AmazingFeature``) 3. 提交更改 (``git commit -m 'Add some AmazingFeature'``) 4. 推送到分支 (``git push origin feature/AmazingFeature``) 5. 开启 Pull Request 许可证 ======= 本项目采用 MIT 许可证 - 详见 `LICENSE <../LICENSE>`_ 文件。 联系方式 ======== * **作者**: Zhang Kaijing * **项目主页**: https://zzzkhj.github.io/PyNetIM/ * **问题反馈**: `GitHub Issues `_ **最后更新**: 2026-04-04