refactor: 重组项目目录结构

以讲义内容为骨架迁移到标准目录格式:
- officefile/ 主内容(12章 + 附录 + CC4SI补充)
- dofile/ 代码示例(11个Python脚本)
- data/ 图片资源
- output/ 生成输出(忽略)
- Archive/ 归档旧目录(忽略)
- .claude/skills/ 保留markdown-to-docx工具链
- .pandoc/ 保留CSL和本地化配置

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 14:00:56 +08:00
parent af083069d0
commit 219232de74
91 changed files with 39365 additions and 10 deletions
@@ -0,0 +1,827 @@
"""
反馈与学习示例 (Feedback and Learning Example)
=============================================
本示例展示如何在空间智能系统中实现反馈机制和学习能力。
反馈和学习使系统能够从经验中改进,提高决策质量。
核心概念:
1. 反馈循环 - 收集用户/系统的反馈
2. 性能评估 - 评估决策效果
3. 参数调整 - 根据反馈调整系统参数
4. 经验存储 - 保存和检索历史经验
5. 迁移学习 - 将知识应用到新场景
应用场景:
- 自适应决策权重调整
- 模型参数优化
- 用户偏好学习
- 决策效果跟踪
作者: CC4SI 项目组
"""
import math
import json
from typing import List, Dict, Tuple, Optional, Any, Callable
from dataclasses import dataclass, field
from enum import Enum
from datetime import datetime
import random
# ============================================================================
# 反馈类型定义
# ============================================================================
class FeedbackType(Enum):
"""反馈类型枚举"""
EXPLICIT = "explicit" # 显式反馈 (用户评分/评价)
IMPLICIT = "implicit" # 隐式反馈 (行为数据)
OUTCOME = "outcome" # 结果反馈 (实际结果)
CORRECTION = "correction" # 纠正反馈 (修正建议)
RANKING = "ranking" # 排序反馈 (偏好排序)
class FeedbackSource(Enum):
"""反馈来源枚举"""
HUMAN_EXPERT = "human_expert" # 人类专家
SYSTEM_AUTO = "system_auto" # 系统自动
SENSOR_DATA = "sensor_data" # 传感器数据
CROWDSOURCING = "crowdsourcing" # 众包
PEER_REVIEW = "peer_review" # 同行评审
@dataclass
class Feedback:
"""
反馈数据结构
表示一次具体的反馈事件。
"""
feedback_id: str
feedback_type: FeedbackType
source: FeedbackSource
target_decision_id: str
value: float # 反馈值 (如评分)
content: Optional[str] = None # 反馈内容
metadata: Dict[str, Any] = field(default_factory=dict)
timestamp: datetime = field(default_factory=datetime.now)
def __repr__(self) -> str:
return f"Feedback({self.feedback_type.value}, value={self.value:.2f})"
# ============================================================================
# 决策记录
# ============================================================================
@dataclass
class Decision:
"""
决策记录
保存系统做出的一次决策的完整信息。
"""
decision_id: str
context: Dict[str, Any] # 决策上下文
alternatives: List[Dict[str, Any]] # 可选方案
selected_alternative: int # 选择的方案索引
model_version: str # 使用的模型版本
parameters: Dict[str, Any] # 决策参数
predicted_outcome: Optional[float] = None # 预测结果
actual_outcome: Optional[float] = None # 实际结果
feedback_list: List[Feedback] = field(default_factory=list)
timestamp: datetime = field(default_factory=datetime.now)
def add_feedback(self, feedback: Feedback) -> None:
"""添加反馈"""
self.feedback_list.append(feedback)
def get_average_feedback(self) -> float:
"""获取平均反馈分数"""
if not self.feedback_list:
return 0.0
return sum(f.value for f in self.feedback_list) / len(self.feedback_list)
def get_outcome_error(self) -> Optional[float]:
"""获取预测误差"""
if self.predicted_outcome is not None and self.actual_outcome is not None:
return abs(self.predicted_outcome - self.actual_outcome)
return None
def calculate_regret(self) -> float:
"""
计算后悔值
后悔值 = 最优选择的结果 - 实际选择的结果
"""
if not self.alternatives or self.actual_outcome is None:
return 0.0
# 假设alternatives中存储了各个选项的实际结果
best_outcome = max(
alt.get("actual_outcome", self.actual_outcome)
for alt in self.alternatives
)
return best_outcome - self.actual_outcome
# ============================================================================
# 经验存储
# ============================================================================
class ExperienceStore:
"""
经验存储
存储和检索历史决策经验,用于学习和改进。
"""
def __init__(self, capacity: int = 1000):
"""
初始化经验存储
Args:
capacity: 最大存储容量
"""
self.capacity = capacity
self.decisions: Dict[str, Decision] = {}
self.decision_list: List[str] = [] # 按时间顺序的ID列表
def add_decision(self, decision: Decision) -> None:
"""添加决策记录"""
self.decisions[decision.decision_id] = decision
self.decision_list.append(decision.decision_id)
# 超过容量时删除最旧的
if len(self.decision_list) > self.capacity:
oldest_id = self.decision_list.pop(0)
del self.decisions[oldest_id]
def get_decision(self, decision_id: str) -> Optional[Decision]:
"""获取决策记录"""
return self.decisions.get(decision_id)
def get_recent_decisions(self, n: int = 10) -> List[Decision]:
"""获取最近的n条决策"""
recent_ids = self.decision_list[-n:]
return [self.decisions[id] for id in recent_ids]
def find_similar_decisions(self, context: Dict[str, Any],
threshold: float = 0.8) -> List[Decision]:
"""
查找相似上下文的决策
Args:
context: 目标上下文
threshold: 相似度阈值
Returns:
相似决策列表
"""
similar = []
for decision in self.decisions.values():
similarity = self._calculate_similarity(context, decision.context)
if similarity >= threshold:
similar.append((decision, similarity))
similar.sort(key=lambda x: x[1], reverse=True)
return [d for d, _ in similar]
def _calculate_similarity(self, ctx1: Dict[str, Any],
ctx2: Dict[str, Any]) -> float:
"""计算上下文相似度 (简化版本)"""
# 简化: 使用键的交集比例
keys1 = set(ctx1.keys())
keys2 = set(ctx2.keys())
intersection = keys1 & keys2
union = keys1 | keys2
if not union:
return 0.0
# 值相似度
value_similarity = 0.0
count = 0
for key in intersection:
v1 = ctx1.get(key)
v2 = ctx2.get(key)
if isinstance(v1, (int, float)) and isinstance(v2, (int, float)):
# 归一化差异
max_val = max(abs(v1), abs(v2), 1)
diff = abs(v1 - v2) / max_val
value_similarity += (1 - diff)
count += 1
if count > 0:
value_similarity /= count
# 组合相似度
key_similarity = len(intersection) / len(union)
return 0.3 * key_similarity + 0.7 * value_similarity
def get_statistics(self) -> Dict[str, Any]:
"""获取统计信息"""
total = len(self.decisions)
if total == 0:
return {"total_decisions": 0}
with_feedback = sum(1 for d in self.decisions.values() if d.feedback_list)
with_outcome = sum(1 for d in self.decisions.values()
if d.actual_outcome is not None)
avg_feedback = sum(d.get_average_feedback()
for d in self.decisions.values()
if d.feedback_list) / max(with_feedback, 1)
return {
"total_decisions": total,
"decisions_with_feedback": with_feedback,
"decisions_with_outcome": with_outcome,
"average_feedback_score": avg_feedback
}
# ============================================================================
# 学习器接口
# ============================================================================
class Learner(ABC):
"""学习器抽象基类"""
def __init__(self, name: str = ""):
self.name = name
@abstractmethod
def learn_from_feedback(self, decision: Decision, feedback: Feedback) -> None:
"""从反馈中学习"""
pass
@abstractmethod
def learn_from_outcome(self, decision: Decision) -> None:
"""从结果中学习"""
pass
@abstractmethod
def get_parameters(self) -> Dict[str, Any]:
"""获取当前参数"""
pass
@abstractmethod
def update_parameters(self, params: Dict[str, Any]) -> None:
"""更新参数"""
pass
# ============================================================================
# 权重学习器
# ============================================================================
class WeightLearner(Learner):
"""
权重学习器
通过反馈学习多准则决策的权重。
"""
def __init__(self, initial_weights: List[float],
learning_rate: float = 0.1,
min_weight: float = 0.05,
max_weight: float = 0.5):
"""
初始化权重学习器
Args:
initial_weights: 初始权重列表
learning_rate: 学习率
min_weight: 最小权重
max_weight: 最大权重
"""
super().__init__("WeightLearner")
self.weights = initial_weights.copy()
self.learning_rate = learning_rate
self.min_weight = min_weight
self.max_weight = max_weight
self.update_count = 0
def learn_from_feedback(self, decision: Decision, feedback: Feedback) -> None:
"""
从反馈中学习权重
使用梯度下降法调整权重:
- 如果反馈为正,增加选中选项的优势准则权重
- 如果反馈为负,减少选中选项的优势准则权重
"""
if not decision.alternatives or decision.selected_alternative >= len(decision.alternatives):
return
selected = decision.alternatives[decision.selected_alternative]
# 计算调整方向
feedback_normalized = (feedback.value - 0.5) * 2 # 转换到 [-1, 1]
# 获取准则值 (假设存储在criteria字段)
criteria_values = selected.get("criteria", [])
if len(criteria_values) != len(self.weights):
return
# 计算梯度
# 简化: 增加高值准则的权重 (如果反馈为正)
max_value = max(criteria_values) if criteria_values else 1
gradients = []
for i, value in enumerate(criteria_values):
# 归一化值
norm_value = value / max_value if max_value > 0 else 0
# 梯度: 高值准则应该有更大权重
gradient = (norm_value - 0.5) * feedback_normalized
gradients.append(gradient)
# 更新权重
for i, gradient in enumerate(gradients):
self.weights[i] += self.learning_rate * gradient
# 归一化权重
self._normalize_weights()
self.update_count += 1
def learn_from_outcome(self, decision: Decision) -> None:
"""
从结果中学习
如果实际结果好于预期,增加选中策略的权重
"""
if decision.predicted_outcome is None or decision.actual_outcome is None:
return
# 计算结果误差
error = decision.actual_outcome - decision.predicted_outcome
# 归一化误差
error_normalized = math.tanh(error / 100) # 假设100为合理的误差范围
# 根据误差调整权重
feedback = Feedback(
feedback_id=f"outcome_{decision.decision_id}",
feedback_type=FeedbackType.OUTCOME,
source=FeedbackSource.SYSTEM_AUTO,
target_decision_id=decision.decision_id,
value=0.5 + error_normalized * 0.25 # 转换到合理范围
)
self.learn_from_feedback(decision, feedback)
def _normalize_weights(self) -> None:
"""归一化权重并限制范围"""
# 限制范围
self.weights = [
max(self.min_weight, min(self.max_weight, w))
for w in self.weights
]
# 归一化使和为1
total = sum(self.weights)
self.weights = [w / total for w in self.weights]
def get_parameters(self) -> Dict[str, Any]:
return {
"weights": self.weights,
"learning_rate": self.learning_rate,
"update_count": self.update_count
}
def update_parameters(self, params: Dict[str, Any]) -> None:
if "weights" in params:
self.weights = params["weights"].copy()
if "learning_rate" in params:
self.learning_rate = params["learning_rate"]
# ============================================================================
# 自适应决策系统
# ============================================================================
class AdaptiveDecisionSystem:
"""
自适应决策系统
结合反馈和学习的智能决策系统。
"""
def __init__(self, criteria: List[str],
initial_weights: List[float] = None):
"""
初始化自适应决策系统
Args:
criteria: 决策准则列表
initial_weights: 初始权重
"""
self.criteria = criteria
self.n_criteria = len(criteria)
if initial_weights is None:
# 均匀初始权重
initial_weights = [1.0 / self.n_criteria] * self.n_criteria
# 归一化权重
total = sum(initial_weights)
self.weights = [w / total for w in initial_weights]
# 创建学习器
self.learner = WeightLearner(self.weights)
# 创建经验存储
self.experience_store = ExperienceStore()
# 决策计数器
self.decision_counter = 0
print(f"[自适应决策系统] 初始化完成")
print(f" 准则: {self.criteria}")
print(f" 初始权重: {[f'{w:.3f}' for w in self.weights]}")
def make_decision(self, alternatives: List[Dict[str, float]],
context: Dict[str, Any] = None) -> Tuple[int, Dict[str, Any]]:
"""
做出决策
Args:
alternatives: 备选方案列表,每个方案包含各准则的值
context: 决策上下文
Returns:
(选中方案索引, 决策信息)
"""
if not alternatives:
raise ValueError("没有备选方案")
# 计算每个方案的综合得分
scores = []
for alt in alternatives:
score = self._calculate_score(alt)
scores.append(score)
# 选择得分最高的
selected_idx = max(range(len(scores)), key=lambda i: scores[i])
# 创建决策记录
decision_id = f"decision_{self.decision_counter}"
self.decision_counter += 1
decision = Decision(
decision_id=decision_id,
context=context or {},
alternatives=[
{"criteria": alt, "score": score}
for alt, score in zip(alternatives, scores)
],
selected_alternative=selected_idx,
model_version="1.0",
parameters=self.get_parameters()
)
decision_info = {
"decision_id": decision_id,
"selected_index": selected_idx,
"selected_alternative": alternatives[selected_idx],
"score": scores[selected_idx],
"all_scores": scores,
"weights": self.weights.copy()
}
# 存储决策
self.experience_store.add_decision(decision)
return selected_idx, decision_info
def _calculate_score(self, alternative: Dict[str, float]) -> float:
"""
计算方案的综合得分
使用加权求和模型
"""
score = 0.0
for i, criterion in enumerate(self.criteria):
if criterion in alternative:
score += self.weights[i] * alternative[criterion]
return score
def provide_feedback(self, decision_id: str, feedback_value: float,
feedback_type: FeedbackType = FeedbackType.EXPLICIT,
source: FeedbackSource = FeedbackSource.HUMAN_EXPERT,
content: str = None) -> None:
"""
为决策提供反馈
Args:
decision_id: 决策ID
feedback_value: 反馈值 (通常在0-1范围)
feedback_type: 反馈类型
source: 反馈来源
content: 反馈内容
"""
decision = self.experience_store.get_decision(decision_id)
if not decision:
print(f"警告: 找不到决策 {decision_id}")
return
# 创建反馈
feedback = Feedback(
feedback_id=f"fb_{decision_id}_{len(decision.feedback_list)}",
feedback_type=feedback_type,
source=source,
target_decision_id=decision_id,
value=feedback_value,
content=content
)
# 添加到决策记录
decision.add_feedback(feedback)
# 从反馈中学习
self.learner.learn_from_feedback(decision, feedback)
# 更新系统权重
self.weights = self.learner.weights.copy()
print(f"[反馈] 收到反馈: {feedback_value:.2f}")
print(f"[学习] 更新后权重: {[f'{w:.3f}' for w in self.weights]}")
def report_outcome(self, decision_id: str, actual_outcome: float) -> None:
"""
报告实际结果
Args:
decision_id: 决策ID
actual_outcome: 实际结果值
"""
decision = self.experience_store.get_decision(decision_id)
if not decision:
print(f"警告: 找不到决策 {decision_id}")
return
decision.actual_outcome = actual_outcome
# 从结果中学习
self.learner.learn_from_outcome(decision)
# 更新系统权重
self.weights = self.learner.weights.copy()
print(f"[结果] 决策 {decision_id} 实际结果: {actual_outcome:.2f}")
def get_parameters(self) -> Dict[str, Any]:
"""获取当前系统参数"""
return {
"weights": self.weights.copy(),
"criteria": self.criteria.copy()
}
def set_parameters(self, params: Dict[str, Any]) -> None:
"""设置系统参数"""
if "weights" in params:
self.weights = params["weights"].copy()
def get_performance_summary(self) -> Dict[str, Any]:
"""获取性能摘要"""
stats = self.experience_store.get_statistics()
# 计算平均反馈分数
decisions = list(self.experience_store.decisions.values())
if decisions:
avg_feedback = sum(d.get_average_feedback()
for d in decisions if d.feedback_list)
feedback_count = sum(1 for d in decisions if d.feedback_list)
avg_feedback = avg_feedback / feedback_count if feedback_count > 0 else None
else:
avg_feedback = None
# 计算平均后悔值
regrets = [d.calculate_regret() for d in decisions
if d.actual_outcome is not None]
avg_regret = sum(regrets) / len(regrets) if regrets else None
return {
"total_decisions": stats["total_decisions"],
"decisions_with_feedback": stats["decisions_with_feedback"],
"average_feedback_score": avg_feedback,
"average_regret": avg_regret,
"current_weights": self.weights.copy()
}
def print_summary(self) -> None:
"""打印系统摘要"""
print("\n" + "="*60)
print("自适应决策系统摘要")
print("="*60)
print("\n决策准则:")
for i, criterion in enumerate(self.criteria):
print(f" {i+1}. {criterion:15s} 权重: {self.weights[i]:.4f}")
perf = self.get_performance_summary()
print(f"\n性能统计:")
print(f" 总决策数: {perf['total_decisions']}")
print(f" 有反馈的决策: {perf['decisions_with_feedback']}")
if perf['average_feedback_score'] is not None:
print(f" 平均反馈分数: {perf['average_feedback_score']:.3f}")
if perf['average_regret'] is not None:
print(f" 平均后悔值: {perf['average_regret']:.3f}")
print("="*60 + "\n")
# ============================================================================
# 主程序
# ============================================================================
def main():
"""主程序 - 演示反馈与学习的使用"""
print("="*70)
print("反馈与学习示例演示")
print("="*70)
# ========================================================================
# 1. 创建自适应决策系统
# ========================================================================
print("\n[步骤 1] 创建自适应决策系统")
print("-" * 50)
criteria = ["经济效益", "环境影响", "社会影响", "技术可行性"]
initial_weights = [0.4, 0.3, 0.2, 0.1] # 偏重经济效益
system = AdaptiveDecisionSystem(criteria, initial_weights)
system.print_summary()
# ========================================================================
# 2. 第一次决策
# ========================================================================
print("\n[步骤 2] 第一次决策 - 工厂选址")
print("-" * 50)
alternatives = [
{"经济效益": 0.8, "环境影响": 0.3, "社会影响": 0.5, "技术可行性": 0.9}, # 位置A
{"经济效益": 0.5, "环境影响": 0.7, "社会影响": 0.8, "技术可行性": 0.6}, # 位置B
{"经济效益": 0.6, "环境影响": 0.9, "社会影响": 0.6, "技术可行性": 0.7}, # 位置C
]
selected_idx, decision_info = system.make_decision(
alternatives,
context={"task": "工厂选址", "region": "华东地区"}
)
print(f"\n决策结果:")
print(f" 选中方案: 位置{chr(65 + selected_idx)}")
print(f" 得分: {decision_info['score']:.3f}")
print(f" 各方案得分: {[f'{s:.2f}' for s in decision_info['all_scores']]}")
decision_id_1 = decision_info['decision_id']
# ========================================================================
# 3. 提供反馈
# ========================================================================
print("\n[步骤 3] 收集反馈")
print("-" * 50)
# 专家反馈: 环境影响被低估了
print("\n3.1 专家反馈: 环境影响应该更重视")
system.provide_feedback(
decision_id_1,
feedback_value=0.6, # 中等偏下的评分
feedback_type=FeedbackType.EXPLICIT,
source=FeedbackSource.HUMAN_EXPERT,
content="环境影响权重太低,应提高"
)
# 更多反馈强化
system.provide_feedback(
decision_id_1,
feedback_value=0.5,
feedback_type=FeedbackType.CORRECTION,
source=FeedbackSource.HUMAN_EXPERT
)
# ========================================================================
# 4. 第二次决策 (学习后的权重)
# ========================================================================
print("\n[步骤 4] 第二次决策 - 另一个选址")
print("-" * 50)
alternatives_2 = [
{"经济效益": 0.7, "环境影响": 0.4, "社会影响": 0.6, "技术可行性": 0.8}, # 位置D
{"经济效益": 0.4, "环境影响": 0.9, "社会影响": 0.7, "技术可行性": 0.7}, # 位置E
]
selected_idx_2, decision_info_2 = system.make_decision(
alternatives_2,
context={"task": "工厂选址", "region": "华南地区"}
)
print(f"\n决策结果:")
print(f" 选中方案: 位置{chr(68 + selected_idx_2)}")
print(f" 得分: {decision_info_2['score']:.3f}")
print(f" 当前权重: {[f'{w:.3f}' for w in system.weights]}")
decision_id_2 = decision_info_2['decision_id']
# ========================================================================
# 5. 报告结果并学习
# ========================================================================
print("\n[步骤 5] 报告实际结果")
print("-" * 50)
# 第一个决策的结果
print(f"\n5.1 决策 {decision_id_1} 的实际结果")
system.report_outcome(decision_id_1, actual_outcome=75) # 预测可能不同
# 第二个决策的结果
print(f"\n5.2 决策 {decision_id_2} 的实际结果")
system.report_outcome(decision_id_2, actual_outcome=85)
# ========================================================================
# 6. 多轮学习
# ========================================================================
print("\n[步骤 6] 多轮学习")
print("-" * 50)
# 模拟多次决策和反馈
for i in range(10):
alt1 = {
"经济效益": random.uniform(0.5, 0.9),
"环境影响": random.uniform(0.3, 0.7),
"社会影响": random.uniform(0.4, 0.8),
"技术可行性": random.uniform(0.5, 0.9)
}
alt2 = {
"经济效益": random.uniform(0.3, 0.7),
"环境影响": random.uniform(0.6, 0.95),
"社会影响": random.uniform(0.5, 0.9),
"技术可行性": random.uniform(0.4, 0.8)
}
idx, info = system.make_decision([alt1, alt2])
did = info['decision_id']
# 模拟反馈 (随着环境意识增强,对高环境影响的方案给低分)
selected_env_impact = ([alt1, alt2][idx])["环境影响"]
if selected_env_impact < 0.6:
feedback_val = random.uniform(0.3, 0.5) # 低分
else:
feedback_val = random.uniform(0.7, 0.95) # 高分
system.provide_feedback(did, feedback_val)
system.report_outcome(did, actual_outcome=random.uniform(60, 90))
print("\n多轮学习后:")
system.print_summary()
# ========================================================================
# 7. 权重变化分析
# ========================================================================
print("\n[步骤 7] 权重变化分析")
print("-" * 50)
final_weights = system.weights
print(f"\n初始权重: {[f'{w:.3f}' for w in initial_weights]}")
print(f"最终权重: {[f'{w:.3f}' for w in final_weights]}")
print("\n权重变化:")
for i, criterion in enumerate(criteria):
change = final_weights[i] - initial_weights[i]
arrow = "" if change > 0 else "" if change < 0 else ""
print(f" {criterion:15s}: {initial_weights[i]:.3f}{final_weights[i]:.3f} "
f"({arrow}{abs(change):.3f})")
# ========================================================================
# 8. 经验检索
# ========================================================================
print("\n[步骤 8] 相似决策检索")
print("-" * 50)
similar_decisions = system.experience_store.find_similar_decisions(
{"task": "工厂选址", "region": "华东地区"},
threshold=0.3
)
print(f"\n找到 {len(similar_decisions)} 个相似决策:")
for i, decision in enumerate(similar_decisions[:3], 1):
print(f" {i}. {decision.decision_id} - "
f"选中: {decision.selected_alternative}, "
f"反馈: {decision.get_average_feedback():.2f}")
print("\n" + "="*70)
print("演示完成!")
print("="*70)
if __name__ == "__main__":
main()
@@ -0,0 +1,824 @@
"""
人机协同示例 (Human-in-the-Loop Example)
========================================
本示例展示如何在空间智能系统中实现人机协同工作模式。
人机协同 (HITL) 结合人类专家的领域知识和AI的计算能力,
实现更可靠的决策。
核心概念:
1. 主动学习 - AI主动请求人类帮助
2. 交互式决策 - 人机共同完成决策
3. 反馈收集 - 收集并整合人类反馈
4. 置信度估计 - AI评估自身确定性
5. 专业知识注入 - 将专家知识整合到系统中
应用场景:
- 空间数据标注与验证
- 复杂选址决策
- 应急响应规划
- 土地利用评估
作者: CC4SI 项目组
"""
import math
import json
from typing import List, Dict, Tuple, Optional, Any, Callable
from dataclasses import dataclass, field
from enum import Enum
from datetime import datetime
import random
# ============================================================================
# 协同模式枚举
# ============================================================================
class HITLMode(Enum):
"""人机协同模式"""
AUTOMATIC = "automatic" # 全自动模式
ADVISORY = "advisory" # 建议模式 (AI提供建议,人类决策)
INTERACTIVE = "interactive" # 交互模式 (人机共同决策)
SUPERVISED = "supervised" # 监督模式 (人类监督AI)
MANUAL = "manual" # 手动模式 (人类完全控制)
class ConfidenceLevel(Enum):
"""置信度级别"""
VERY_LOW = "very_low" # 0.0 - 0.3
LOW = "low" # 0.3 - 0.5
MEDIUM = "medium" # 0.5 - 0.7
HIGH = "high" # 0.7 - 0.9
VERY_HIGH = "very_high" # 0.9 - 1.0
class InteractionType(Enum):
"""交互类型"""
CONFIRMATION = "confirmation" # 确认请求
CLARIFICATION = "clarification" # 澄清请求
VALIDATION = "validation" # 验证请求
CORRECTION = "correction" # 纠正请求
RANKING = "ranking" # 排序请求
ANNOTATION = "annotation" # 标注请求
# ============================================================================
# 交互数据结构
# ============================================================================
@dataclass
class AIConfidence:
"""AI置信度"""
value: float # 0-1之间的值
reason: str = ""
metadata: Dict[str, Any] = field(default_factory=dict)
@property
def level(self) -> ConfidenceLevel:
"""获取置信度级别"""
if self.value < 0.3:
return ConfidenceLevel.VERY_LOW
elif self.value < 0.5:
return ConfidenceLevel.LOW
elif self.value < 0.7:
return ConfidenceLevel.MEDIUM
elif self.value < 0.9:
return ConfidenceLevel.HIGH
else:
return ConfidenceLevel.VERY_HIGH
def __repr__(self) -> str:
return f"Confidence({self.value:.2f}, {self.level.value})"
@dataclass
class HumanInput:
"""人类输入"""
interaction_type: InteractionType
response: Any
confidence: float = 1.0 # 人类对自己回答的置信度
timestamp: datetime = field(default_factory=datetime.now)
expert_id: str = "default_expert"
metadata: Dict[str, Any] = field(default_factory=dict)
@dataclass
class InteractionRequest:
"""交互请求"""
request_id: str
interaction_type: InteractionType
question: str
context: Dict[str, Any]
options: Optional[List[Any]] = None
ai_suggestion: Optional[Any] = None
ai_confidence: Optional[AIConfidence] = None
priority: int = 0 # 优先级 (0=普通, 1=重要, 2=紧急)
deadline: Optional[datetime] = None
metadata: Dict[str, Any] = field(default_factory=dict)
# ============================================================================
# 决策建议
# ============================================================================
@dataclass
class DecisionProposal:
"""决策建议"""
proposal_id: str
decision: Any
reasoning: str
confidence: AIConfidence
alternatives: List[Any] = field(default_factory=list)
supporting_evidence: List[str] = field(default_factory=list)
caveats: List[str] = field(default_factory=list) # 警告/注意事项
requires_human_review: bool = False
timestamp: datetime = field(default_factory=datetime.now)
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
return {
"proposal_id": self.proposal_id,
"decision": self.decision,
"reasoning": self.reasoning,
"confidence": self.confidence.value,
"alternatives": self.alternatives,
"supporting_evidence": self.supporting_evidence,
"caveats": self.caveats,
"requires_human_review": self.requires_human_review
}
# ============================================================================
# 人类专家接口
# ============================================================================
class HumanExpert(ABC):
"""人类专家抽象接口"""
def __init__(self, expert_id: str, name: str = "", expertise: List[str] = None):
self.expert_id = expert_id
self.name = name or expert_id
self.expertise = expertise or []
@abstractmethod
def respond_to_request(self, request: InteractionRequest) -> HumanInput:
"""响应交互请求"""
pass
def can_handle(self, request: InteractionRequest) -> bool:
"""检查是否能处理请求"""
return True
def get_expertise_summary(self) -> str:
"""获取专长摘要"""
return f"{self.name}: {', '.join(self.expertise) if self.expertise else '通用'}"
class MockHumanExpert(HumanExpert):
"""
模拟人类专家 (用于演示)
在实际应用中,这会连接到真实的用户界面。
"""
def __init__(self, expert_id: str, name: str = "",
expertise: List[str] = None,
response_style: str = "balanced"):
super().__init__(expert_id, name, expertise)
self.response_style = response_style
self.response_log: List[Dict[str, Any]] = []
def respond_to_request(self, request: InteractionRequest) -> HumanInput:
"""模拟响应请求"""
# 记录请求
self.response_log.append({
"request_id": request.request_id,
"type": request.interaction_type.value,
"question": request.question,
"timestamp": datetime.now()
})
# 根据不同类型生成响应
if request.interaction_type == InteractionType.CONFIRMATION:
# 确认请求 - 模拟基于置信度的决策
if request.ai_confidence and request.ai_confidence.value > 0.7:
# 高置信度时倾向于接受AI建议
response = "accept" if random.random() > 0.2 else "reject"
else:
# 低置信度时更谨慎
response = "accept" if random.random() > 0.5 else "reject"
return HumanInput(
interaction_type=request.interaction_type,
response=response,
confidence=0.8
)
elif request.interaction_type == InteractionType.VALIDATION:
# 验证请求
is_valid = random.random() > 0.3 # 70%概率验证通过
return HumanInput(
interaction_type=request.interaction_type,
response=is_valid,
confidence=0.9,
metadata={"comment": "看起来正确" if is_valid else "需要修正"}
)
elif request.interaction_type == InteractionType.RANKING:
# 排序请求
if request.options:
# 随机打乱选项作为人类排序
shuffled = request.options.copy()
random.shuffle(shuffled)
return HumanInput(
interaction_type=request.interaction_type,
response=shuffled,
confidence=0.7
)
elif request.interaction_type == InteractionType.ANNOTATION:
# 标注请求
return HumanInput(
interaction_type=request.interaction_type,
response={
"label": random.choice(["高价值", "中价值", "低价值"]),
"notes": "基于现场评估"
},
confidence=0.75
)
# 默认响应
return HumanInput(
interaction_type=request.interaction_type,
response="acknowledged",
confidence=0.5
)
# ============================================================================
# 人机协同系统
# ============================================================================
class HITLSystem:
"""
人机协同系统
管理AI与人类专家之间的交互。
"""
def __init__(self, name: str = "HITL系统",
default_mode: HITLMode = HITLMode.INTERACTIVE,
confidence_threshold: float = 0.7):
"""
初始化HITL系统
Args:
name: 系统名称
default_mode: 默认协同模式
confidence_threshold: 请求人类帮助的置信度阈值
"""
self.name = name
self.current_mode = default_mode
self.confidence_threshold = confidence_threshold
# 注册的专家
self.experts: Dict[str, HumanExpert] = {}
# 待处理的请求队列
self.pending_requests: List[InteractionRequest] = []
# 交互历史
self.interaction_history: List[Dict[str, Any]] = []
# 统计信息
self.stats = {
"total_requests": 0,
"auto_resolved": 0,
"human_resolved": 0,
"human_acceptance_rate": 0.0
}
print(f"[{self.name}] 初始化完成")
print(f" 模式: {default_mode.value}")
print(f" 置信度阈值: {confidence_threshold}")
def register_expert(self, expert: HumanExpert) -> None:
"""注册人类专家"""
self.experts[expert.expert_id] = expert
print(f"[专家注册] {expert.get_expertise_summary()}")
def set_mode(self, mode: HITLMode) -> None:
"""设置协同模式"""
self.current_mode = mode
print(f"[模式切换] {mode.value}")
def make_decision(self, proposal: DecisionProposal,
auto_threshold: float = None) -> Any:
"""
做出决策 (带人机协同)
Args:
proposal: AI的决策建议
auto_threshold: 自动决策的置信度阈值
Returns:
最终决策
"""
threshold = auto_threshold or self.confidence_threshold
# 根据模式和置信度决定是否需要人类介入
needs_human = self._needs_human_intervention(proposal, threshold)
if not needs_human:
# 自动决策
self.stats["auto_resolved"] += 1
self._record_interaction(proposal, None, "automatic")
return proposal.decision
# 请求人类帮助
return self._request_human_input(proposal)
def _needs_human_intervention(self, proposal: DecisionProposal,
threshold: float) -> bool:
"""判断是否需要人类介入"""
# 检查强制人工审查标记
if proposal.requires_human_review:
return True
# 检查置信度
if proposal.confidence.value < threshold:
return True
# 根据模式判断
if self.current_mode == HITLMode.MANUAL:
return True
elif self.current_mode == HITLMode.SUPERVISED:
return True
elif self.current_mode == HITLMode.AUTOMATIC:
return False
elif self.current_mode == HITLMode.INTERACTIVE:
# 交互模式下,低置信度需要人类
return proposal.confidence.value < 0.8
elif self.current_mode == HITLMode.ADVISORY:
# 建议模式下,总是需要人类确认
return True
return False
def _request_human_input(self, proposal: DecisionProposal) -> Any:
"""请求人类输入"""
# 创建交互请求
request = InteractionRequest(
request_id=f"req_{len(self.interaction_history)}",
interaction_type=InteractionType.CONFIRMATION,
question=f"请确认AI建议: {proposal.reasoning}",
context={"proposal_id": proposal.proposal_id},
options=["accept", "reject", "modify"],
ai_suggestion=proposal.decision,
ai_confidence=proposal.confidence
)
self.pending_requests.append(request)
self.stats["total_requests"] += 1
# 选择专家
expert = self._select_expert(request)
if not expert:
print("警告: 没有可用的专家,使用AI建议")
return proposal.decision
# 获取专家响应
print(f"\n[人类交互] 向专家 {expert.name} 请求确认...")
print(f" AI建议: {proposal.decision}")
print(f" 置信度: {proposal.confidence}")
print(f" 理由: {proposal.reasoning}")
human_input = expert.respond_to_request(request)
print(f" 专家响应: {human_input.response}")
# 处理响应
result = self._process_human_response(proposal, human_input)
# 记录交互
self._record_interaction(proposal, human_input, "human_assisted")
# 清理请求
if request in self.pending_requests:
self.pending_requests.remove(request)
self.stats["human_resolved"] += 1
return result
def _select_expert(self, request: InteractionRequest) -> Optional[HumanExpert]:
"""选择合适的专家"""
if not self.experts:
return None
# 简单实现: 返回第一个可用的专家
for expert in self.experts.values():
if expert.can_handle(request):
return expert
return None
def _process_human_response(self, proposal: DecisionProposal,
human_input: HumanInput) -> Any:
"""处理人类响应"""
if human_input.interaction_type == InteractionType.CONFIRMATION:
if human_input.response == "accept":
# 接受AI建议
return proposal.decision
elif human_input.response == "reject":
# 拒绝AI建议,返回次优选项
if proposal.alternatives:
return proposal.alternatives[0]
return None
elif human_input.response == "modify":
# 需要修改 (简化: 返回原建议)
return proposal.decision
return human_input.response
def _record_interaction(self, proposal: DecisionProposal,
human_input: Optional[HumanInput],
resolution_type: str) -> None:
"""记录交互"""
record = {
"proposal_id": proposal.proposal_id,
"timestamp": datetime.now(),
"ai_confidence": proposal.confidence.value,
"human_input": human_input.response if human_input else None,
"resolution_type": resolution_type
}
self.interaction_history.append(record)
def request_annotation(self, item: Any, context: Dict[str, Any] = None) -> Any:
"""请求人类标注"""
request = InteractionRequest(
request_id=f"annotate_{len(self.interaction_history)}",
interaction_type=InteractionType.ANNOTATION,
question=f"请对以下项目进行标注: {item}",
context=context or {},
ai_suggestion=item
)
expert = self._select_expert(request)
if not expert:
return None
return expert.respond_to_request(request)
def request_validation(self, item: Any, context: Dict[str, Any] = None) -> bool:
"""请求人类验证"""
request = InteractionRequest(
request_id=f"validate_{len(self.interaction_history)}",
interaction_type=InteractionType.VALIDATION,
question=f"以下内容是否正确: {item}",
context=context or {},
ai_suggestion=item
)
expert = self._select_expert(request)
if not expert:
return True # 默认有效
response = expert.respond_to_request(request)
return response.response if isinstance(response.response, bool) else True
def get_statistics(self) -> Dict[str, Any]:
"""获取统计信息"""
stats = self.stats.copy()
stats["pending_requests"] = len(self.pending_requests)
stats["total_interactions"] = len(self.interaction_history)
# 计算接受率
human_interactions = [i for i in self.interaction_history
if i["resolution_type"] == "human_assisted"]
if human_interactions:
accepted = sum(1 for i in human_interactions
if i["human_input"] == "accept")
stats["human_acceptance_rate"] = accepted / len(human_interactions)
return stats
def print_statistics(self) -> None:
"""打印统计信息"""
stats = self.get_statistics()
print(f"\n{self.name} 统计信息:")
print("-" * 50)
print(f"总请求数: {stats['total_requests']}")
print(f"自动解决: {stats['auto_resolved']}")
print(f"人类协助: {stats['human_resolved']}")
print(f"待处理请求: {stats['pending_requests']}")
print(f"人类接受率: {stats['human_acceptance_rate']:.2%}")
print("-" * 50)
# ============================================================================
# 空间决策HITL系统
# ============================================================================
class SpatialDecisionHITL(HITLSystem):
"""
空间决策人机协同系统
专门用于空间决策场景的HITL实现。
"""
def __init__(self, confidence_threshold: float = 0.7):
super().__init__(
name="空间决策HITL系统",
default_mode=HITLMode.INTERACTIVE,
confidence_threshold=confidence_threshold
)
def analyze_site_suitability(self, site_data: Dict[str, Any]) -> DecisionProposal:
"""
分析场地适宜性
Args:
site_data: 场地数据
Returns:
决策建议
"""
# 简化的适宜性评分
score = self._calculate_suitability_score(site_data)
# 确定置信度
confidence = self._assess_confidence(site_data, score)
# 生成建议
if score > 0.7:
decision = "highly_suitable"
reasoning = f"综合评分 {score:.2f} 较高,适宜开发"
elif score > 0.5:
decision = "moderately_suitable"
reasoning = f"综合评分 {score:.2f} 中等,需谨慎评估"
else:
decision = "not_suitable"
reasoning = f"综合评分 {score:.2f} 较低,不建议开发"
# 检查注意事项
caveats = []
if site_data.get("environmental_risk", 0) > 0.6:
caveats.append("存在环境风险")
if site_data.get("infrastructure_score", 1) < 0.4:
caveats.append("基础设施不足")
# 低置信度时标记需要人工审查
requires_review = confidence.value < 0.6 or len(caveats) > 0
return DecisionProposal(
proposal_id=f"suitability_{random.randint(1000, 9999)}",
decision=decision,
reasoning=reasoning,
confidence=confidence,
alternatives=["moderately_suitable", "not_suitable"]
if decision != "not_suitable" else ["moderately_suitable", "highly_suitable"],
supporting_evidence=[
f"评分: {score:.2f}",
f"环境因子: {site_data.get('environmental_score', 0):.2f}",
f"经济因子: {site_data.get('economic_score', 0):.2f}"
],
caveats=caveats,
requires_human_review=requires_review
)
def _calculate_suitability_score(self, site_data: Dict[str, Any]) -> float:
"""计算适宜性评分"""
env = site_data.get("environmental_score", 0.5)
econ = site_data.get("economic_score", 0.5)
social = site_data.get("social_score", 0.5)
infra = site_data.get("infrastructure_score", 0.5)
# 加权平均
return 0.3 * env + 0.3 * econ + 0.2 * social + 0.2 * infra
def _assess_confidence(self, site_data: Dict[str, Any],
score: float) -> AIConfidence:
"""评估置信度"""
# 检查数据完整性
has_all_data = all(k in site_data for k in [
"environmental_score", "economic_score",
"social_score", "infrastructure_score"
])
if not has_all_data:
return AIConfidence(
value=0.4,
reason="数据不完整"
)
# 检查数据质量
data_quality = site_data.get("data_quality", 0.8)
confidence = data_quality * 0.9
# 检查是否有冲突因素
if site_data.get("environmental_risk", 0) > 0.7:
confidence *= 0.7 # 降低置信度
return AIConfidence(
value=min(confidence, 0.95),
reason="基于数据质量和完整性评估"
)
# ============================================================================
# 主程序
# ============================================================================
def main():
"""主程序 - 演示人机协同的使用"""
print("="*70)
print("人机协同示例演示")
print("="*70)
random.seed(42)
# ========================================================================
# 1. 创建HITL系统
# ========================================================================
print("\n[步骤 1] 创建人机协同系统")
print("-" * 50)
hitl_system = SpatialDecisionHITL(confidence_threshold=0.7)
# 注册专家
expert1 = MockHumanExpert(
expert_id="expert_001",
name="张工程师",
expertise=["环境影响评估", "基础设施规划"],
response_style="conservative"
)
expert2 = MockHumanExpert(
expert_id="expert_002",
name="李规划师",
expertise=["经济效益分析", "社会影响评估"],
response_style="balanced"
)
hitl_system.register_expert(expert1)
hitl_system.register_expert(expert2)
# ========================================================================
# 2. 场景1: 高置信度自动决策
# ========================================================================
print("\n[场景 1] 高置信度 - 自动决策")
print("-" * 50)
site1 = {
"environmental_score": 0.85,
"economic_score": 0.90,
"social_score": 0.88,
"infrastructure_score": 0.92,
"data_quality": 0.95,
"environmental_risk": 0.1
}
proposal1 = hitl_system.analyze_site_suitability(site1)
print(f"\nAI分析结果:")
print(f" 建议: {proposal1.decision}")
print(f" 理由: {proposal1.reasoning}")
print(f" 置信度: {proposal1.confidence}")
decision1 = hitl_system.make_decision(proposal1)
print(f"\n最终决策: {decision1} (自动)")
print(f" → 置信度高,无需人工介入")
# ========================================================================
# 3. 场景2: 低置信度请求人类帮助
# ========================================================================
print("\n\n[场景 2] 低置信度 - 请求人类确认")
print("-" * 50)
site2 = {
"environmental_score": 0.45, # 环境评分低
"economic_score": 0.85, # 但经济评分高
"social_score": 0.60,
"infrastructure_score": 0.50,
"data_quality": 0.70,
"environmental_risk": 0.65 # 存在环境风险
}
proposal2 = hitl_system.analyze_site_suitability(site2)
print(f"\nAI分析结果:")
print(f" 建议: {proposal2.decision}")
print(f" 理由: {proposal2.reasoning}")
print(f" 置信度: {proposal2.confidence}")
print(f" 注意事项: {', '.join(proposal2.caveats)}")
decision2 = hitl_system.make_decision(proposal2)
print(f"\n最终决策: {decision2} (人工协助)")
print(f" → 置信度低且存在注意事项,请求专家确认")
# ========================================================================
# 4. 场景3: 批量决策
# ========================================================================
print("\n\n[场景 3] 批量场地评估")
print("-" * 50)
sites = []
for i in range(5):
site = {
"environmental_score": random.uniform(0.3, 0.95),
"economic_score": random.uniform(0.3, 0.95),
"social_score": random.uniform(0.3, 0.95),
"infrastructure_score": random.uniform(0.3, 0.95),
"data_quality": random.uniform(0.5, 0.95),
"environmental_risk": random.uniform(0.0, 0.8)
}
sites.append(site)
results = []
for i, site in enumerate(sites, 1):
proposal = hitl_system.analyze_site_suitability(site)
decision = hitl_system.make_decision(proposal)
results.append({
"site": i,
"decision": decision,
"confidence": proposal.confidence.value,
"auto": proposal.confidence.value >= hitl_system.confidence_threshold
})
print("\n批量评估结果:")
print(f"{'场地':<6} {'决策':<20} {'置信度':<10} {'模式':<10}")
print("-" * 50)
for r in results:
mode = "自动" if r["auto"] else "人工"
print(f"{r['site']:<6} {r['decision']:<20} {r['confidence']:<10.2f} {mode:<10}")
# ========================================================================
# 5. 场景4: 数据标注
# ========================================================================
print("\n\n[场景 4] 数据标注")
print("-" * 50)
unlabeled_items = [
{"coordinates": (120.5, 30.2), "features": "residential"},
{"coordinates": (121.0, 30.5), "features": "commercial"},
{"coordinates": (120.8, 30.0), "features": "industrial"}
]
for item in unlabeled_items:
annotation = hitl_system.request_annotation(
item,
context={"task": "land_use_classification"}
)
if annotation:
print(f"\n标注 {item['features']}:")
print(f" 标签: {annotation.response.get('label')}")
print(f" 备注: {annotation.response.get('notes')}")
# ========================================================================
# 6. 场景5: 模式切换
# ========================================================================
print("\n\n[场景 5] 模式切换对比")
print("-" * 50)
test_site = {
"environmental_score": 0.70,
"economic_score": 0.75,
"social_score": 0.68,
"infrastructure_score": 0.72,
"data_quality": 0.85,
"environmental_risk": 0.3
}
proposal = hitl_system.analyze_site_suitability(test_site)
print(f"\nAI分析: 置信度 = {proposal.confidence.value:.2f}")
# 尝试不同模式
for mode in [HITLMode.AUTOMATIC, HITLMode.INTERACTIVE, HITLMode.MANUAL]:
hitl_system.set_mode(mode)
decision = hitl_system.make_decision(proposal)
mode_name = {
HITLMode.AUTOMATIC: "全自动",
HITLMode.INTERACTIVE: "交互式",
HITLMode.MANUAL: "手动"
}[mode]
print(f" {mode_name}: {decision}")
# 恢复默认模式
hitl_system.set_mode(HITLMode.INTERACTIVE)
# ========================================================================
# 7. 统计信息
# ========================================================================
print("\n\n[步骤 7] 系统统计")
print("-" * 50)
hitl_system.print_statistics()
print("\n" + "="*70)
print("演示完成!")
print("="*70)
if __name__ == "__main__":
main()
@@ -0,0 +1,684 @@
"""
模块化系统示例 (Modular System Example)
========================================
本示例展示了空间智能系统的模块化设计原则。
模块化是构建可维护、可扩展系统的基础。
核心概念:
1. 关注点分离 - 每个模块负责特定功能
2. 接口设计 - 定义清晰的模块间通信协议
3. 依赖注入 - 降低模块间耦合
4. 插件架构 - 支持动态扩展功能
作者: CC4SI 项目组
"""
from abc import ABC, abstractmethod
from typing import Dict, List, Any, Optional, Callable
from dataclasses import dataclass, field
from enum import Enum
import json
# ============================================================================
# 模块接口定义 (抽象基类)
# ============================================================================
class ModuleType(Enum):
"""模块类型枚举"""
DATA_LOADER = "data_loader"
DATA_PROCESSOR = "data_processor"
ANALYZER = "analyzer"
VISUALIZER = "visualizer"
EXPORTER = "exporter"
class ModuleStatus(Enum):
"""模块状态枚举"""
IDLE = "idle"
INITIALIZING = "initializing"
READY = "ready"
RUNNING = "running"
ERROR = "error"
@dataclass
class ModuleMetadata:
"""模块元数据"""
name: str
version: str
module_type: ModuleType
description: str = ""
dependencies: List[str] = field(default_factory=list)
author: str = ""
config_schema: Dict[str, Any] = field(default_factory=dict)
class IModule(ABC):
"""
模块接口 - 所有模块必须实现此接口
这是一个抽象基类,定义了所有模块必须遵循的契约。
"""
def __init__(self, config: Dict[str, Any] = None):
"""
初始化模块
Args:
config: 模块配置字典
"""
self.config = config or {}
self.status = ModuleStatus.IDLE
self._context: Optional['ModuleContext'] = None
@property
@abstractmethod
def metadata(self) -> ModuleMetadata:
"""返回模块元数据"""
pass
@abstractmethod
def initialize(self, context: 'ModuleContext') -> bool:
"""
初始化模块
Args:
context: 模块上下文,提供对系统资源的访问
Returns:
初始化是否成功
"""
pass
@abstractmethod
def execute(self, input_data: Any) -> Any:
"""
执行模块功能
Args:
input_data: 输入数据
Returns:
处理结果
"""
pass
@abstractmethod
def shutdown(self) -> None:
"""关闭模块,释放资源"""
pass
def get_config(self, key: str, default: Any = None) -> Any:
"""获取配置值"""
return self.config.get(key, default)
def set_config(self, key: str, value: Any) -> None:
"""设置配置值"""
self.config[key] = value
# ============================================================================
# 模块上下文 - 提供模块间通信
# ============================================================================
class ModuleContext:
"""
模块上下文
提供模块间通信和资源共享机制,实现松耦合设计。
"""
def __init__(self):
self._modules: Dict[str, IModule] = {}
self._shared_data: Dict[str, Any] = {}
self._event_handlers: Dict[str, List[Callable]] = {}
def register_module(self, name: str, module: IModule) -> bool:
"""注册模块"""
if name in self._modules:
print(f"警告: 模块 '{name}' 已存在,将被覆盖")
self._modules[name] = module
print(f"模块 '{name}' 已注册 (类型: {module.metadata.module_type.value})")
return True
def get_module(self, name: str) -> Optional[IModule]:
"""获取模块实例"""
return self._modules.get(name)
def has_module(self, name: str) -> bool:
"""检查模块是否存在"""
return name in self._modules
def set_shared_data(self, key: str, value: Any) -> None:
"""设置共享数据"""
self._shared_data[key] = value
def get_shared_data(self, key: str, default: Any = None) -> Any:
"""获取共享数据"""
return self._shared_data.get(key, default)
def subscribe_event(self, event_name: str, handler: Callable) -> None:
"""订阅事件"""
if event_name not in self._event_handlers:
self._event_handlers[event_name] = []
self._event_handlers[event_name].append(handler)
def publish_event(self, event_name: str, *args, **kwargs) -> None:
"""发布事件"""
if event_name in self._event_handlers:
for handler in self._event_handlers[event_name]:
handler(*args, **kwargs)
# ============================================================================
# 模块基类 - 提供通用功能实现
# ============================================================================
class BaseModule(IModule):
"""
模块基类
提供IModule接口的默认实现,子类只需实现特定功能。
"""
def __init__(self, config: Dict[str, Any] = None):
super().__init__(config)
self._metadata: Optional[ModuleMetadata] = None
@property
def metadata(self) -> ModuleMetadata:
if self._metadata is None:
raise NotImplementedError("子类必须设置 _metadata")
return self._metadata
def initialize(self, context: ModuleContext) -> bool:
"""默认初始化实现"""
self._context = context
self.status = ModuleStatus.INITIALIZING
# 检查依赖
for dep in self.metadata.dependencies:
if not context.has_module(dep):
print(f"错误: 依赖模块 '{dep}' 不存在")
self.status = ModuleStatus.ERROR
return False
self.status = ModuleStatus.READY
print(f"模块 '{self.metadata.name}' 初始化完成")
return True
def shutdown(self) -> None:
"""默认关闭实现"""
self.status = ModuleStatus.IDLE
print(f"模块 '{self.metadata.name}' 已关闭")
# ============================================================================
# 具体模块实现
# ============================================================================
class CSVDataLoaderModule(BaseModule):
"""
CSV 数据加载模块
负责从CSV文件加载空间数据。
"""
def __init__(self, config: Dict[str, Any] = None):
super().__init__(config)
self._metadata = ModuleMetadata(
name="csv_data_loader",
version="1.0.0",
module_type=ModuleType.DATA_LOADER,
description="从CSV文件加载空间数据",
author="CC4SI"
)
self._data: List[Dict[str, Any]] = []
def execute(self, input_data: Any) -> Any:
"""
执行数据加载
Args:
input_data: 文件路径或模拟数据
Returns:
加载的数据列表
"""
self.status = ModuleStatus.RUNNING
if isinstance(input_data, str):
# 实际场景中应从文件读取
print(f"从文件 '{input_data}' 加载数据...")
# 模拟加载
self._data = self._load_sample_data()
elif isinstance(input_data, list):
self._data = input_data
else:
self._data = self._load_sample_data()
# 将数据存入共享上下文
if self._context:
self._context.set_shared_data("raw_data", self._data)
self._context.publish_event("data_loaded", len(self._data))
self.status = ModuleStatus.READY
return self._data
def _load_sample_data(self) -> List[Dict[str, Any]]:
"""加载示例数据"""
return [
{"id": 1, "x": 10, "y": 20, "value": 100, "type": "A"},
{"id": 2, "x": 30, "y": 40, "value": 200, "type": "B"},
{"id": 3, "x": 50, "y": 60, "value": 150, "type": "A"},
{"id": 4, "x": 70, "y": 80, "value": 300, "type": "C"},
{"id": 5, "x": 90, "y": 100, "value": 250, "type": "B"},
]
class DataValidationModule(BaseModule):
"""
数据验证模块
负责验证数据质量和完整性。
"""
def __init__(self, config: Dict[str, Any] = None):
super().__init__(config)
self._metadata = ModuleMetadata(
name="data_validator",
version="1.0.0",
module_type=ModuleType.DATA_PROCESSOR,
description="验证数据质量和完整性",
dependencies=["csv_data_loader"],
author="CC4SI"
)
self.validation_rules: List[Callable] = []
def add_validation_rule(self, rule: Callable[[Dict], bool], name: str = ""):
"""添加验证规则"""
self.validation_rules.append(rule)
if name:
print(f"添加验证规则: {name}")
def execute(self, input_data: Any) -> Any:
"""
执行数据验证
Args:
input_data: 待验证的数据
Returns:
验证结果
"""
self.status = ModuleStatus.RUNNING
if not isinstance(input_data, list):
return {"valid": False, "errors": ["输入数据格式错误"]}
errors = []
warnings = []
for i, item in enumerate(input_data):
# 检查必需字段
if "id" not in item:
errors.append(f"{i} 项缺少 'id' 字段")
if "x" not in item or "y" not in item:
errors.append(f"{i} 项缺少坐标字段")
# 应用自定义验证规则
for rule in self.validation_rules:
try:
if not rule(item):
warnings.append(f"{i} 项未通过自定义规则验证")
except Exception as e:
errors.append(f"{i} 项验证时出错: {e}")
result = {
"valid": len(errors) == 0,
"total": len(input_data),
"errors": errors,
"warnings": warnings
}
if self._context:
self._context.set_shared_data("validation_result", result)
self._context.publish_event("data_validated", result)
self.status = ModuleStatus.READY
return result
class StatisticsAnalyzerModule(BaseModule):
"""
统计分析模块
负责计算数据的统计指标。
"""
def __init__(self, config: Dict[str, Any] = None):
super().__init__(config)
self._metadata = ModuleMetadata(
name="statistics_analyzer",
version="1.0.0",
module_type=ModuleType.ANALYZER,
description="计算数据统计指标",
dependencies=["csv_data_loader"],
author="CC4SI"
)
def execute(self, input_data: Any) -> Any:
"""
执行统计分析
Args:
input_data: 待分析的数据
Returns:
统计结果
"""
self.status = ModuleStatus.RUNNING
if not isinstance(input_data, list) or len(input_data) == 0:
return {"error": "没有可分析的数据"}
# 提取数值字段
values = [item.get("value", 0) for item in input_data if "value" in item]
if not values:
return {"error": "没有找到可分析的数值"}
import statistics
result = {
"count": len(values),
"mean": statistics.mean(values),
"median": statistics.median(values),
"stdev": statistics.stdev(values) if len(values) > 1 else 0,
"min": min(values),
"max": max(values),
"sum": sum(values)
}
if self._context:
self._context.set_shared_data("statistics", result)
self._context.publish_event("analysis_complete", result)
self.status = ModuleStatus.READY
return result
class ReportExporterModule(BaseModule):
"""
报告导出模块
负责生成分析报告。
"""
def __init__(self, config: Dict[str, Any] = None):
super().__init__(config)
self._metadata = ModuleMetadata(
name="report_exporter",
version="1.0.0",
module_type=ModuleType.EXPORTER,
description="生成分析报告",
dependencies=["statistics_analyzer"],
author="CC4SI"
)
def execute(self, input_data: Any) -> Any:
"""
生成报告
Args:
input_data: 统计结果或其他数据
Returns:
报告字符串
"""
self.status = ModuleStatus.RUNNING
report_lines = [
"=" * 60,
"空间数据分析报告",
"=" * 60,
""
]
# 从上下文获取数据
if self._context:
validation = self._context.get_shared_data("validation_result")
statistics = self._context.get_shared_data("statistics")
if validation:
report_lines.extend([
"数据验证结果:",
f" 总数: {validation.get('total', 0)}",
f" 有效: {validation.get('valid', False)}",
f" 错误数: {len(validation.get('errors', []))}",
""
])
if statistics:
report_lines.extend([
"统计分析结果:",
f" 样本数: {statistics.get('count', 0)}",
f" 均值: {statistics.get('mean', 0):.2f}",
f" 中位数: {statistics.get('median', 0):.2f}",
f" 标准差: {statistics.get('stdev', 0):.2f}",
f" 最小值: {statistics.get('min', 0)}",
f" 最大值: {statistics.get('max', 0)}",
""
])
report_lines.append("=" * 60)
report = "\n".join(report_lines)
if self._context:
self._context.publish_event("report_generated", report)
self.status = ModuleStatus.READY
return report
# ============================================================================
# 模块系统管理器
# ============================================================================
class ModularSystem:
"""
模块化系统管理器
负责管理模块的生命周期和模块间通信。
"""
def __init__(self, name: str = "模块化空间智能系统"):
self.name = name
self.context = ModuleContext()
self._pipeline: List[str] = [] # 处理流程
def register_module(self, module: IModule, alias: str = None) -> bool:
"""
注册模块到系统
Args:
module: 模块实例
alias: 模块别名 (可选)
Returns:
是否注册成功
"""
name = alias or module.metadata.name
return self.context.register_module(name, module)
def initialize_all(self) -> bool:
"""初始化所有模块"""
print(f"\n初始化 {self.name}...")
success = True
for name, module in self.context._modules.items():
if not module.initialize(self.context):
print(f"模块 '{name}' 初始化失败")
success = False
return success
def define_pipeline(self, module_names: List[str]) -> None:
"""
定义处理流程
Args:
module_names: 按顺序执行的模块名称列表
"""
self._pipeline = module_names
print(f"定义处理流程: {' -> '.join(module_names)}")
def execute(self, input_data: Any = None) -> Any:
"""
执行处理流程
Args:
input_data: 输入数据
Returns:
最终输出结果
"""
if not self._pipeline:
print("错误: 没有定义处理流程")
return None
print(f"\n执行处理流程...")
current_data = input_data
for module_name in self._pipeline:
module = self.context.get_module(module_name)
if not module:
print(f"错误: 找不到模块 '{module_name}'")
return None
print(f" -> 执行模块: {module.metadata.name}")
current_data = module.execute(current_data)
# 如果模块返回错误,终止流程
if isinstance(current_data, dict) and current_data.get("error"):
print(f" 模块 '{module_name}' 返回错误: {current_data['error']}")
return current_data
return current_data
def shutdown_all(self) -> None:
"""关闭所有模块"""
print(f"\n关闭 {self.name}...")
for module in self.context._modules.values():
module.shutdown()
def print_system_info(self) -> None:
"""打印系统信息"""
print(f"\n{'='*60}")
print(f"系统: {self.name}")
print(f"{'='*60}")
print(f"已注册模块数: {len(self.context._modules)}")
for name, module in self.context._modules.items():
print(f" - {name:20s} [{module.metadata.module_type.value:15s}] {module.metadata.name}")
if module.metadata.dependencies:
print(f" 依赖: {', '.join(module.metadata.dependencies)}")
if self._pipeline:
print(f"\n处理流程: {' -> '.join(self._pipeline)}")
else:
print(f"\n处理流程: 未定义")
print(f"{'='*60}\n")
# ============================================================================
# 事件处理示例
# ============================================================================
def setup_event_handlers(system: ModularSystem):
"""设置事件处理器"""
def on_data_loaded(count):
print(f" [事件] 数据加载完成,共 {count} 条记录")
def on_data_validated(result):
status = "通过" if result.get("valid") else "失败"
print(f" [事件] 数据验证{status},错误: {len(result.get('errors', []))}")
def on_analysis_complete(result):
print(f" [事件] 分析完成,均值: {result.get('mean', 0):.2f}")
system.context.subscribe_event("data_loaded", on_data_loaded)
system.context.subscribe_event("data_validated", on_data_validated)
system.context.subscribe_event("analysis_complete", on_analysis_complete)
# ============================================================================
# 主程序
# ============================================================================
def main():
"""主程序 - 演示模块化系统的使用"""
print("="*70)
print("模块化系统示例演示")
print("="*70)
# 1. 创建系统
print("\n[步骤 1] 创建模块化系统")
system = ModularSystem("空间数据分析系统")
# 2. 注册模块
print("\n[步骤 2] 注册模块")
system.register_module(CSVDataLoaderModule())
system.register_module(DataValidationModule())
system.register_module(StatisticsAnalyzerModule())
system.register_module(ReportExporterModule())
# 3. 设置事件处理
print("\n[步骤 3] 设置事件处理")
setup_event_handlers(system)
# 4. 初始化所有模块
print("\n[步骤 4] 初始化模块")
if not system.initialize_all():
print("初始化失败,退出")
return
# 5. 定义处理流程
print("\n[步骤 5] 定义处理流程")
system.define_pipeline([
"csv_data_loader",
"data_validator",
"statistics_analyzer",
"report_exporter"
])
# 6. 打印系统信息
print("\n[步骤 6] 系统信息")
system.print_system_info()
# 7. 执行处理流程
print("\n[步骤 7] 执行处理流程")
result = system.execute("sample_data.csv")
# 8. 输出结果
print("\n[步骤 8] 最终结果")
if isinstance(result, str):
print(result)
# 9. 清理
print("\n[步骤 9] 清理资源")
system.shutdown_all()
print("\n" + "="*70)
print("演示完成!")
print("="*70)
if __name__ == "__main__":
main()
@@ -0,0 +1,938 @@
"""
概率与不确定性示例 (Probability and Uncertainty Example)
========================================================
本示例展示如何在空间智能系统中处理概率和不确定性。
在空间决策中,不确定性是普遍存在的,理解和管理不确定性
对于做出可靠的决策至关重要。
核心概念:
1. 概率分布 - 描述随机变量的可能取值及其概率
2. 贝叶斯推理 - 基于新证据更新信念
3. 蒙特卡洛模拟 - 通过随机采样评估不确定性
4. 置信区间 - 估计结果的范围
5. 敏感性分析 - 评估输入变化对输出的影响
应用场景:
- 空间插值的不确定性量化
- 多准则决策的敏感性分析
- 风险评估与概率预测
- 传感器数据的可靠性分析
作者: CC4SI 项目组
"""
import math
import random
from typing import List, Dict, Tuple, Optional, Callable, Any
from dataclasses import dataclass, field
from abc import ABC, abstractmethod
from enum import Enum
import statistics
# ============================================================================
# 概率分布基础类
# ============================================================================
class DistributionType(Enum):
"""分布类型枚举"""
NORMAL = "normal" # 正态分布
UNIFORM = "uniform" # 均匀分布
TRIANGULAR = "triangular" # 三角分布
EXPONENTIAL = "exponential" # 指数分布
BETA = "beta" # Beta分布
class ProbabilityDistribution(ABC):
"""概率分布抽象基类"""
def __init__(self, name: str = ""):
self.name = name
@abstractmethod
def sample(self) -> float:
"""从分布中采样一个值"""
pass
@abstractmethod
def mean(self) -> float:
"""计算期望值"""
pass
@abstractmethod
def std(self) -> float:
"""计算标准差"""
pass
@abstractmethod
def pdf(self, x: float) -> float:
"""概率密度函数"""
pass
def cdf(self, x: float) -> float:
"""累积分布函数 (近似计算)"""
# 使用蒙特卡洛积分近似
n_samples = 10000
count = sum(1 for _ in range(n_samples) if self.sample() <= x)
return count / n_samples
def confidence_interval(self, confidence: float = 0.95) -> Tuple[float, float]:
"""计算置信区间"""
n_samples = 10000
samples = [self.sample() for _ in range(n_samples)]
alpha = 1 - confidence
lower = quantile(samples, alpha / 2)
upper = quantile(samples, 1 - alpha / 2)
return lower, upper
def quantile(data: List[float], q: float) -> float:
"""计算分位数"""
sorted_data = sorted(data)
index = int(q * len(sorted_data))
return sorted_data[min(index, len(sorted_data) - 1)]
# ============================================================================
# 具体概率分布实现
# ============================================================================
class NormalDistribution(ProbabilityDistribution):
"""
正态分布 (高斯分布)
最常用的连续概率分布,由均值和标准差参数化。
"""
def __init__(self, mu: float = 0.0, sigma: float = 1.0, name: str = ""):
super().__init__(name)
self.mu = mu # 均值
self.sigma = sigma # 标准差
if sigma <= 0:
raise ValueError("标准差必须为正数")
def sample(self) -> float:
"""使用 Box-Muller 变换生成正态分布随机数"""
u1 = random.random()
u2 = random.random()
while u1 == 0: # 避免log(0)
u1 = random.random()
z0 = math.sqrt(-2 * math.log(u1)) * math.cos(2 * math.pi * u2)
return self.mu + self.sigma * z0
def mean(self) -> float:
return self.mu
def std(self) -> float:
return self.sigma
def pdf(self, x: float) -> float:
"""正态分布概率密度函数"""
coeff = 1 / (self.sigma * math.sqrt(2 * math.pi))
exponent = -0.5 * ((x - self.mu) / self.sigma) ** 2
return coeff * math.exp(exponent)
def __repr__(self) -> str:
return f"Normal(μ={self.mu}, σ={self.sigma})"
class UniformDistribution(ProbabilityDistribution):
"""
均匀分布
在指定范围内等概率取值。
"""
def __init__(self, a: float = 0.0, b: float = 1.0, name: str = ""):
super().__init__(name)
self.a = a # 下界
self.b = b # 上界
if a >= b:
raise ValueError("下界必须小于上界")
def sample(self) -> float:
return self.a + (self.b - self.a) * random.random()
def mean(self) -> float:
return (self.a + self.b) / 2
def std(self) -> float:
return (self.b - self.a) / math.sqrt(12)
def pdf(self, x: float) -> float:
if self.a <= x <= self.b:
return 1 / (self.b - self.a)
return 0.0
def __repr__(self) -> str:
return f"Uniform({self.a}, {self.b})"
class TriangularDistribution(ProbabilityDistribution):
"""
三角分布
由最小值、最大值和众数定义的分布,常用于
当只知道边界和最可能值时建模不确定性。
"""
def __init__(self, a: float, b: float, c: float, name: str = ""):
super().__init__(name)
self.a = a # 最小值
self.b = b # 最大值
self.c = c # 众数 (最可能值)
if not (a <= c <= b):
raise ValueError("必须满足 a <= c <= b")
def sample(self) -> float:
u = random.random()
fc = (self.c - self.a) / (self.b - self.a)
if u < fc:
return self.a + math.sqrt(u * (self.b - self.a) * (self.c - self.a))
else:
return self.b - math.sqrt((1 - u) * (self.b - self.a) * (self.b - self.c))
def mean(self) -> float:
return (self.a + self.b + self.c) / 3
def std(self) -> float:
numerator = (self.a**2 + self.b**2 + self.c**2
- self.a * self.b - self.a * self.c - self.b * self.c)
return math.sqrt(numerator / 18)
def pdf(self, x: float) -> float:
if x < self.a or x > self.b:
return 0.0
if x < self.c:
return 2 * (x - self.a) / ((self.b - self.a) * (self.c - self.a))
else:
return 2 * (self.b - x) / ((self.b - self.a) * (self.b - self.c))
def __repr__(self) -> str:
return f"Triangular({self.a}, {self.c}, {self.b})"
# ============================================================================
# 贝叶斯推理
# ============================================================================
@dataclass
class BayesianBelief:
"""
贝叶斯信念状态
表示对某个假设的信念,包含先验、似然和后验。
"""
hypothesis: str
prior: float # 先验概率 P(H)
likelihood: float # 似然 P(E|H)
evidence: Optional[float] = None # 证据概率 P(E)
posterior: Optional[float] = None # 后验概率 P(H|E)
def update(self, evidence_prob: float = None) -> float:
"""
更新后验概率
Args:
evidence_prob: P(E),如果None则使用归一化
Returns:
后验概率
"""
# P(H|E) = P(E|H) * P(H) / P(E)
numerator = self.likelihood * self.prior
if evidence_prob is not None:
self.evidence = evidence_prob
self.posterior = numerator / evidence_prob
else:
# 假设有多个假设,需要归一化
self.posterior = numerator # 简化版本
return self.posterior
class BayesianUpdater:
"""
贝叶斯更新器
管理多个假设的贝叶斯更新。
"""
def __init__(self, hypotheses: List[str]):
"""
初始化贝叶斯更新器
Args:
hypotheses: 假设列表
"""
# 初始化先验概率 (均匀分布)
prior = 1.0 / len(hypotheses)
self.beliefs: Dict[str, BayesianBelief] = {
h: BayesianBelief(hypothesis=h, prior=prior, likelihood=1.0)
for h in hypotheses
}
def set_prior(self, hypothesis: str, prior: float) -> None:
"""设置先验概率"""
if hypothesis in self.beliefs:
self.beliefs[hypothesis].prior = prior
def update_with_evidence(self, likelihoods: Dict[str, float]) -> None:
"""
用证据更新所有假设
Args:
likelihoods: 每个假设的似然 P(E|H)
"""
# 更新似然
for h, likelihood in likelihoods.items():
if h in self.beliefs:
self.beliefs[h].likelihood = likelihood
# 计算证据概率 (归一化常数)
evidence = sum(
b.likelihood * b.prior
for b in self.beliefs.values()
)
# 更新后验
for belief in self.beliefs.values():
belief.update(evidence)
def get_posteriors(self) -> Dict[str, float]:
"""获取所有后验概率"""
return {
h: b.posterior or b.prior
for h, b in self.beliefs.items()
}
def get_most_likely(self) -> Tuple[str, float]:
"""获取最可能的假设"""
posteriors = self.get_posteriors()
return max(posteriors.items(), key=lambda x: x[1])
def print_beliefs(self) -> None:
"""打印信念状态"""
print("\n贝叶斯信念状态:")
print("-" * 60)
print(f"{'假设':<20} {'先验':<12} {'似然':<12} {'后验':<12}")
print("-" * 60)
for belief in self.beliefs.values():
posterior = belief.posterior if belief.posterior is not None else belief.prior
print(f"{belief.hypothesis:<20} {belief.prior:<12.4f} "
f"{belief.likelihood:<12.4f} {posterior:<12.4f}")
print("-" * 60)
# ============================================================================
# 蒙特卡洛模拟
# ============================================================================
@dataclass
class SimulationResult:
"""模拟结果"""
samples: List[float] = field(default_factory=list)
mean: float = 0.0
std: float = 0.0
min: float = 0.0
max: float = 0.0
median: float = 0.0
confidence_interval: Tuple[float, float] = (0.0, 0.0)
percentiles: Dict[float, float] = field(default_factory=dict)
def calculate_statistics(self, confidence: float = 0.95) -> None:
"""计算统计量"""
if not self.samples:
return
self.mean = statistics.mean(self.samples)
self.std = statistics.stdev(self.samples) if len(self.samples) > 1 else 0
self.min = min(self.samples)
self.max = max(self.samples)
self.median = statistics.median(self.samples)
# 置信区间
alpha = 1 - confidence
sorted_samples = sorted(self.samples)
n = len(sorted_samples)
self.confidence_interval = (
sorted_samples[int(alpha / 2 * n)],
sorted_samples[int((1 - alpha / 2) * n)]
)
# 常用百分位数
for p in [0.01, 0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95, 0.99]:
self.percentiles[p] = sorted_samples[int(p * n)]
def print_summary(self) -> None:
"""打印结果摘要"""
print(f"\n蒙特卡洛模拟结果 (n={len(self.samples)}):")
print("-" * 50)
print(f"均值: {self.mean:.4f}")
print(f"中位数: {self.median:.4f}")
print(f"标准差: {self.std:.4f}")
print(f"范围: [{self.min:.4f}, {self.max:.4f}]")
print(f"95% 置信区间: [{self.confidence_interval[0]:.4f}, "
f"{self.confidence_interval[1]:.4f}]")
print(f"\n百分位数:")
for p, value in sorted(self.percentiles.items()):
print(f" {p*100:>5.0f}%: {value:.4f}")
print("-" * 50)
class MonteCarloSimulator:
"""
蒙特卡洛模拟器
通过随机采样评估不确定性。
"""
def __init__(self, seed: int = None):
"""初始化模拟器"""
if seed is not None:
random.seed(seed)
def simulate(self, model: Callable[[], float],
n_runs: int = 10000) -> SimulationResult:
"""
运行模拟
Args:
model: 返回模拟值的函数
n_runs: 运行次数
Returns:
模拟结果
"""
samples = [model() for _ in range(n_runs)]
result = SimulationResult(samples=samples)
result.calculate_statistics()
return result
def simulate_with_inputs(self,
model: Callable[[Dict[str, float]], float],
input_distributions: Dict[str, ProbabilityDistribution],
n_runs: int = 10000) -> SimulationResult:
"""
使用输入分布运行模拟
Args:
model: 接受输入字典的函数
input_distributions: 输入变量到其分布的映射
n_runs: 运行次数
Returns:
模拟结果
"""
samples = []
for _ in range(n_runs):
inputs = {
name: dist.sample()
for name, dist in input_distributions.items()
}
samples.append(model(inputs))
result = SimulationResult(samples=samples)
result.calculate_statistics()
return result
# ============================================================================
# 敏感性分析
# ============================================================================
@dataclass
class SensitivityResult:
"""敏感性分析结果"""
sensitivity_coefficients: Dict[str, float] = field(default_factory=dict)
rankings: List[Tuple[str, float]] = field(default_factory=list)
tornado_data: Dict[str, Tuple[float, float]] = field(default_factory=dict)
def print_summary(self) -> None:
"""打印敏感性分析摘要"""
print("\n敏感性分析结果:")
print("-" * 50)
print("排名 | 变量 | 敏感性系数")
print("-" * 50)
for i, (var, coef) in enumerate(self.rankings, 1):
print(f"{i:4d} | {var:<11} | {coef:10.4f}")
print("-" * 50)
class SensitivityAnalyzer:
"""
敏感性分析器
评估输入变化对输出的影响。
"""
def __init__(self):
self.model: Optional[Callable] = None
self.base_inputs: Optional[Dict[str, float]] = None
def simple_sensitivity(self,
model: Callable[[Dict[str, float]], float],
base_inputs: Dict[str, float],
variations: Dict[str, float] = None) -> SensitivityResult:
"""
简单敏感性分析 (单因素)
Args:
model: 待分析模型
base_inputs: 基准输入值
variations: 各变量的变化幅度 (默认 ±10%)
Returns:
敏感性结果
"""
if variations is None:
variations = {k: 0.1 for k in base_inputs.keys()}
# 计算基准输出
base_output = model(base_inputs)
# 计算敏感性系数
coefficients = {}
tornado_data = {}
for var, variation in variations.items():
original_value = base_inputs[var]
# 正向变化
base_inputs[var] = original_value * (1 + variation)
output_plus = model(base_inputs)
# 负向变化
base_inputs[var] = original_value * (1 - variation)
output_minus = model(base_inputs)
# 恢复原值
base_inputs[var] = original_value
# 计算敏感性系数 (归一化)
delta_output = output_plus - output_minus
delta_input = 2 * variation * original_value
coefficient = delta_output / delta_input if delta_input != 0 else 0
coefficients[var] = coefficient
tornado_data[var] = (output_minus, output_plus)
# 排名
rankings = sorted(coefficients.items(), key=lambda x: abs(x[1]), reverse=True)
return SensitivityResult(
sensitivity_coefficients=coefficients,
rankings=rankings,
tornado_data=tornado_data
)
def regression_sensitivity(self,
model: Callable[[Dict[str, float]], float],
input_distributions: Dict[str, ProbabilityDistribution],
n_samples: int = 1000) -> SensitivityResult:
"""
基于回归的敏感性分析
Args:
model: 待分析模型
input_distributions: 输入分布
n_samples: 样本数量
Returns:
敏感性结果
"""
simulator = MonteCarloSimulator()
# 生成样本
input_samples = []
output_samples = []
for _ in range(n_samples):
inputs = {
name: dist.sample()
for name, dist in input_distributions.items()
}
input_samples.append(inputs)
output_samples.append(model(inputs))
# 计算标准化回归系数 (SRC)
# SRC = beta * (std_x / std_y)
import statistics
std_y = statistics.stdev(output_samples)
coefficients = {}
for var in input_distributions.keys():
x_values = [s[var] for s in input_samples]
std_x = statistics.stdev(x_values)
# 计算相关系数
mean_x = statistics.mean(x_values)
mean_y = statistics.mean(output_samples)
numerator = sum((x - mean_x) * (y - mean_y)
for x, y in zip(x_values, output_samples))
denominator = math.sqrt(
sum((x - mean_x)**2 for x in x_values) *
sum((y - mean_y)**2 for y in output_samples)
)
correlation = numerator / denominator if denominator != 0 else 0
src = correlation * (std_x / std_y) if std_y > 0 else 0
coefficients[var] = src
rankings = sorted(coefficients.items(), key=lambda x: abs(x[1]), reverse=True)
return SensitivityResult(
sensitivity_coefficients=coefficients,
rankings=rankings
)
# ============================================================================
# 空间概率应用示例
# ============================================================================
class SpatialProbabilityModel:
"""
空间概率模型
将概率理论应用于空间问题。
"""
@staticmethod
def uncertain_distance(point1: Tuple[float, float],
point2: Tuple[float, float],
distance_error_std: float = 5.0) -> NormalDistribution:
"""
带不确定性的距离计算
Args:
point1: 第一个点 (x, y)
point2: 第二个点 (x, y)
distance_error_std: 距离测量误差的标准差
Returns:
距离的概率分布
"""
# 计算确定性距离
dx = point2[0] - point1[0]
dy = point2[1] - point1[1]
true_distance = math.sqrt(dx**2 + dy**2)
# 返回正态分布
return NormalDistribution(mu=true_distance, sigma=distance_error_std)
@staticmethod
def location_probability(measurement: Tuple[float, float],
true_location: Tuple[float, float],
measurement_error: float = 10.0) -> float:
"""
计算测量位置的似然概率
Args:
measurement: 测量位置
true_location: 真实位置
measurement_error: 测量误差标准差
Returns:
似然概率
"""
dist = SpatialProbabilityModel.uncertain_distance(
measurement, true_location, measurement_error
)
# 使用正态分布 PDF
return dist.pdf(0)
@staticmethod
def bayesian_location_update(prior_locations: List[Tuple[float, float]],
measurements: List[Tuple[float, float]],
measurement_error: float = 10.0) -> List[float]:
"""
贝叶斯位置更新
Args:
prior_locations: 候选真实位置列表
measurements: 测量位置列表
measurement_error: 测量误差
Returns:
每个候选位置的后验概率
"""
n = len(prior_locations)
posteriors = []
for candidate in prior_locations:
# 计算似然 (所有测量的乘积)
likelihood = 1.0
for measurement in measurements:
prob = SpatialProbabilityModel.location_probability(
measurement, candidate, measurement_error
)
likelihood *= prob
# 先验 (均匀)
prior = 1.0 / n
# 后验 (未归一化)
posterior = likelihood * prior
posteriors.append(posterior)
# 归一化
total = sum(posteriors)
if total > 0:
posteriors = [p / total for p in posteriors]
return posteriors
# ============================================================================
# 主程序
# ============================================================================
def main():
"""主程序 - 演示概率与不确定性的使用"""
print("="*70)
print("概率与不确定性示例演示")
print("="*70)
random.seed(42) # 可重现的结果
# ========================================================================
# 1. 概率分布示例
# ========================================================================
print("\n[部分 1] 概率分布")
print("-" * 50)
# 创建不同的分布
normal = NormalDistribution(mu=100, sigma=15, name="温度")
uniform = UniformDistribution(a=50, b=150, name="范围")
triangular = TriangularDistribution(a=60, c=100, b=140, name="估计")
distributions = [normal, uniform, triangular]
for dist in distributions:
print(f"\n{dist}:")
print(f" 均值: {dist.mean():.2f}")
print(f" 标准差: {dist.std():.2f}")
samples = [dist.sample() for _ in range(5)]
print(f" 样本: {[f'{s:.2f}' for s in samples]}")
ci = dist.confidence_interval(0.95)
print(f" 95% CI: [{ci[0]:.2f}, {ci[1]:.2f}]")
# ========================================================================
# 2. 贝叶斯推理示例
# ========================================================================
print("\n\n[部分 2] 贝叶斯推理")
print("-" * 50)
print("问题: 根据土壤测试结果判断土地适宜性")
# 假设: 土地适宜性等级
hypotheses = ["高适宜", "中适宜", "低适宜", "不适宜"]
updater = BayesianUpdater(hypotheses)
# 设置不同的先验 (基于历史数据)
updater.set_prior("高适宜", 0.2)
updater.set_prior("中适宜", 0.3)
updater.set_prior("低适宜", 0.3)
updater.set_prior("不适宜", 0.2)
print("\n初始信念:")
updater.print_beliefs()
# 证据1: 土壤pH值检测
print("\n证据1: 土壤pH值适中 (似然更新)")
updater.update_with_evidence({
"高适宜": 0.8, # pH值对高适宜的可能性高
"中适宜": 0.6,
"低适宜": 0.3,
"不适宜": 0.1
})
updater.print_beliefs()
# 证据2: 有机质含量检测
print("\n证据2: 有机质含量高 (似然更新)")
updater.update_with_evidence({
"高适宜": 0.9,
"中适宜": 0.5,
"低适宜": 0.2,
"不适宜": 0.05
})
updater.print_beliefs()
most_likely = updater.get_most_likely()
print(f"\n最可能的假设: {most_likely[0]} (概率: {most_likely[1]:.2%})")
# ========================================================================
# 3. 蒙特卡洛模拟示例
# ========================================================================
print("\n\n[部分 3] 蒙特卡洛模拟")
print("-" * 50)
print("问题: 评估房地产开发项目的预期收益")
def development_model(inputs: Dict[str, float]) -> float:
"""房地产开发收益模型"""
land_cost = inputs["land_cost"]
construction_cost = inputs["construction_cost"]
selling_price = inputs["selling_price"]
units = inputs["units"]
sales_rate = inputs["sales_rate"]
# 收益 = (售价 * 单元数 * 销售率) - (土地成本 + 建设成本 * 单元数)
revenue = selling_price * units * sales_rate
total_cost = land_cost + construction_cost * units
return revenue - total_cost
# 定义输入分布
input_dists = {
"land_cost": TriangularDistribution(800000, 1000000, 1500000), # 土地成本
"construction_cost": NormalDistribution(50000, 5000), # 单元建设成本
"selling_price": NormalDistribution(150000, 15000), # 单元售价
"units": TriangularDistribution(80, 100, 120), # 单元数量
"sales_rate": BetaDistribution(alpha=8, beta=2, a=0, b=1) # 销售率
}
simulator = MonteCarloSimulator()
result = simulator.simulate_with_inputs(development_model, input_dists, n_runs=10000)
result.print_summary()
# 风险评估
negative_prob = sum(1 for s in result.samples if s < 0) / len(result.samples)
print(f"\n风险分析:")
print(f" 亏损概率: {negative_prob:.2%}")
profit_prob = sum(1 for s in result.samples if s > 1000000) / len(result.samples)
print(f" 超过100万利润概率: {profit_prob:.2%}")
# ========================================================================
# 4. 敏感性分析示例
# ========================================================================
print("\n\n[部分 4] 敏感性分析")
print("-" * 50)
print("问题: 分析各因素对收益的影响程度")
analyzer = SensitivityAnalyzer()
# 简单敏感性分析
base_inputs = {
"land_cost": 1000000,
"construction_cost": 50000,
"selling_price": 150000,
"units": 100,
"sales_rate": 0.85
}
sensitivity_result = analyzer.simple_sensitivity(
development_model, base_inputs, variations={k: 0.1 for k in base_inputs.keys()}
)
sensitivity_result.print_summary()
# ========================================================================
# 5. 空间概率应用
# ========================================================================
print("\n\n[部分 5] 空间概率应用")
print("-" * 50)
print("问题: GPS定位的不确定性")
# 真实位置
true_location = (1000, 2000)
# 带误差的测量
measurements = [
(1005, 2003),
(998, 1998),
(1002, 2005),
(995, 2000)
]
# 候选位置
candidates = [
(1000, 2000), # 真实位置
(1015, 2015),
(990, 1990),
(1005, 1995)
]
posteriors = SpatialProbabilityModel.bayesian_location_update(
candidates, measurements, measurement_error=5.0
)
print("\n候选位置的后验概率:")
for i, (loc, prob) in enumerate(zip(candidates, posteriors)):
print(f" 位置 {i+1} {loc}: {prob:.4f}")
most_likely_idx = max(range(len(posteriors)), key=lambda i: posteriors[i])
print(f"\n最可能的位置: 位置 {most_likely_idx+1} {candidates[most_likely_idx]}")
print("\n" + "="*70)
print("演示完成!")
print("="*70)
# Beta分布实现 (用于上面代码中的引用)
class BetaDistribution(ProbabilityDistribution):
"""Beta分布 - 用于建模[0,1]区间内的概率"""
def __init__(self, alpha: float, beta: float, a: float = 0, b: float = 1, name: str = ""):
super().__init__(name)
self.alpha = alpha
self.beta = beta
self.a = a # 下界
self.b = b # 上界
def sample(self) -> float:
# 使用numpy的gamma函数近似
import math
import random
# 生成Gamma随机变量
def gamma(alpha):
if alpha < 1:
return gamma(alpha + 1) * (random.random() ** (1 / alpha))
# Marsaglia and Tsang's method
d = alpha - 1/3
c = 1 / math.sqrt(9 * d)
while True:
x = random.gauss(0, 1)
v = (1 + c * x) ** 3
if v > 0:
u = random.random()
if u < 1 - 0.0331 * (x * x) ** 2:
return d * v
if math.log(u) < 0.5 * x * x + d * (1 - v + math.log(v)):
return d * v
x = gamma(self.alpha)
y = gamma(self.beta)
beta_sample = x / (x + y)
# 转换到[a, b]区间
return self.a + (self.b - self.a) * beta_sample
def mean(self) -> float:
return self.a + (self.b - self.a) * self.alpha / (self.alpha + self.beta)
def std(self) -> float:
mean_raw = self.alpha / (self.alpha + self.beta)
var_raw = (self.alpha * self.beta) / (
(self.alpha + self.beta) ** 2 * (self.alpha + self.beta + 1)
)
return (self.b - self.a) * math.sqrt(var_raw)
def pdf(self, x: float) -> float:
# 简化版本,仅返回近似值
return 1.0 # 实际应实现Beta分布的PDF
def __repr__(self) -> str:
return f"Beta(α={self.alpha}, β={self.beta})"
if __name__ == "__main__":
main()
@@ -0,0 +1,748 @@
"""
状态机工作流示例 (State Machine Workflow Example)
==================================================
本示例展示如何使用状态机模式管理复杂的空间分析工作流。
状态机是一种行为设计模式,允许对象在其内部状态改变时改变其行为。
核心概念:
1. 状态 (State) - 系统在特定时刻的模式
2. 转换 (Transition) - 从一个状态到另一个状态的变化
3. 事件 (Event) - 触发状态转换的外部或内部条件
4. 动作 (Action) - 状态转换时执行的操作
应用场景:
- 空间数据处理流水线
- 多阶段决策流程
- 任务调度与监控
- 用户交互流程控制
作者: CC4SI 项目组
"""
from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Callable, Any
from dataclasses import dataclass, field
from enum import Enum
import json
from datetime import datetime
# ============================================================================
# 状态定义
# ============================================================================
class WorkflowState(Enum):
"""工作流状态枚举"""
# 初始状态
IDLE = "idle"
INITIALIZED = "initialized"
# 数据处理状态
LOADING_DATA = "loading_data"
DATA_LOADED = "data_loaded"
VALIDATING_DATA = "validating_data"
DATA_VALIDATED = "data_validated"
# 分析状态
ANALYZING = "analyzing"
ANALYSIS_COMPLETE = "analysis_complete"
# 决策状态
DECIDING = "deciding"
DECISION_MADE = "decision_made"
# 输出状态
GENERATING_OUTPUT = "generating_output"
OUTPUT_COMPLETE = "output_complete"
# 异常状态
ERROR = "error"
PAUSED = "paused"
CANCELLED = "cancelled"
# 最终状态
COMPLETED = "completed"
class EventType(Enum):
"""事件类型枚举"""
# 控制事件
START = "start"
PAUSE = "pause"
RESUME = "resume"
CANCEL = "cancel"
RESET = "reset"
# 数据事件
DATA_LOAD_REQUEST = "data_load_request"
DATA_LOAD_SUCCESS = "data_load_success"
DATA_LOAD_FAILURE = "data_load_failure"
DATA_VALIDATE_REQUEST = "data_validate_request"
DATA_VALIDATE_SUCCESS = "data_validate_success"
DATA_VALIDATE_FAILURE = "data_validate_failure"
# 分析事件
ANALYZE_REQUEST = "analyze_request"
ANALYSIS_SUCCESS = "analysis_success"
ANALYSIS_FAILURE = "analysis_failure"
# 决策事件
DECIDE_REQUEST = "decide_request"
DECISION_SUCCESS = "decision_success"
DECISION_FAILURE = "decision_failure"
# 输出事件
OUTPUT_REQUEST = "output_request"
OUTPUT_SUCCESS = "output_success"
OUTPUT_FAILURE = "output_failure"
# 错误事件
ERROR_OCCURRED = "error_occurred"
RETRY = "retry"
# ============================================================================
# 状态机数据结构
# ============================================================================
@dataclass
class StateTransition:
"""状态转换定义"""
from_state: WorkflowState
event: EventType
to_state: WorkflowState
action: Optional[Callable] = None
guard: Optional[Callable[[], bool]] = None # 守卫条件
description: str = ""
def can_execute(self) -> bool:
"""检查转换是否可执行"""
if self.guard is None:
return True
return self.guard()
@dataclass
class StateContext:
"""状态上下文 - 存储工作流数据"""
data: Dict[str, Any] = field(default_factory=dict)
errors: List[str] = field(default_factory=list)
warnings: List[str] = field(default_factory=list)
history: List[Dict[str, Any]] = field(default_factory=list)
start_time: Optional[datetime] = None
end_time: Optional[datetime] = None
def add_history(self, from_state: WorkflowState, event: EventType,
to_state: WorkflowState, timestamp: datetime = None):
"""添加历史记录"""
self.history.append({
"from_state": from_state.value,
"event": event.value,
"to_state": to_state.value,
"timestamp": timestamp or datetime.now()
})
def get_data(self, key: str, default: Any = None) -> Any:
"""获取数据"""
return self.data.get(key, default)
def set_data(self, key: str, value: Any) -> None:
"""设置数据"""
self.data[key] = value
def add_error(self, error: str) -> None:
"""添加错误"""
self.errors.append(error)
def add_warning(self, warning: str) -> None:
"""添加警告"""
self.warnings.append(warning)
# ============================================================================
# 状态机实现
# ============================================================================
class StateMachine:
"""
状态机实现
管理状态转换和状态相关的行为。
"""
def __init__(self, initial_state: WorkflowState = WorkflowState.IDLE):
"""
初始化状态机
Args:
initial_state: 初始状态
"""
self._current_state = initial_state
self._transitions: Dict[WorkflowState, Dict[EventType, StateTransition]] = {}
self._context = StateContext()
self._state_listeners: Dict[WorkflowState, List[Callable]] = {}
print(f"[状态机] 初始化,初始状态: {initial_state.value}")
@property
def current_state(self) -> WorkflowState:
"""获取当前状态"""
return self._current_state
@property
def context(self) -> StateContext:
"""获取状态上下文"""
return self._context
def add_transition(self, transition: StateTransition) -> None:
"""
添加状态转换
Args:
transition: 状态转换定义
"""
if transition.from_state not in self._transitions:
self._transitions[transition.from_state] = {}
self._transitions[transition.from_state][transition.event] = transition
print(f"[状态机] 添加转换: {transition.from_state.value} + {transition.event.value} -> {transition.to_state.value}")
def add_state_listener(self, state: WorkflowState, listener: Callable) -> None:
"""
添加状态监听器
Args:
state: 要监听的状态
listener: 状态进入时调用的函数
"""
if state not in self._state_listeners:
self._state_listeners[state] = []
self._state_listeners[state].append(listener)
def trigger(self, event: EventType, payload: Any = None) -> bool:
"""
触发事件
Args:
event: 事件类型
payload: 事件负载
Returns:
是否成功触发状态转换
"""
# 检查当前状态是否有对应转换
if self._current_state not in self._transitions:
print(f"[状态机] 当前状态 {self._current_state.value} 没有定义任何转换")
return False
if event not in self._transitions[self._current_state]:
print(f"[状态机] 状态 {self._current_state.value} 不处理事件 {event.value}")
return False
transition = self._transitions[self._current_state][event]
# 检查守卫条件
if not transition.can_execute():
print(f"[状态机] 守卫条件不满足,转换被阻止")
return False
# 执行状态转换
old_state = self._current_state
self._current_state = transition.to_state
# 记录历史
if payload:
self._context.set_data("last_payload", payload)
self._context.add_history(old_state, event, self._current_state)
print(f"[状态机] 状态转换: {old_state.value} -> {self._current_state.value} (事件: {event.value})")
# 执行转换动作
if transition.action:
try:
transition.action(self._context, payload)
except Exception as e:
print(f"[状态机] 执行动作时出错: {e}")
self._context.add_error(f"转换动作执行失败: {e}")
# 触发状态监听器
if self._current_state in self._state_listeners:
for listener in self._state_listeners[self._current_state]:
try:
listener(self._current_state, self._context)
except Exception as e:
print(f"[状态机] 监听器执行出错: {e}")
return True
def can_trigger(self, event: EventType) -> bool:
"""
检查是否可以触发指定事件
Args:
event: 事件类型
Returns:
是否可以触发
"""
if self._current_state not in self._transitions:
return False
if event not in self._transitions[self._current_state]:
return False
transition = self._transitions[self._current_state][event]
return transition.can_execute()
def get_available_events(self) -> List[EventType]:
"""获取当前状态下可用的事件列表"""
if self._current_state not in self._transitions:
return []
available = []
for event, transition in self._transitions[self._current_state].items():
if transition.can_execute():
available.append(event)
return available
def reset(self) -> None:
"""重置状态机"""
self._current_state = WorkflowState.IDLE
self._context = StateContext()
print(f"[状态机] 状态机已重置")
def print_state(self) -> None:
"""打印当前状态"""
print(f"\n当前状态: {self._current_state.value}")
available = self.get_available_events()
if available:
print(f"可用事件: {', '.join(e.value for e in available)}")
else:
print("可用事件: 无")
# ============================================================================
# 空间分析工作流状态机
# ============================================================================
class SpatialAnalysisWorkflow:
"""
空间分析工作流
使用状态机实现的空间数据处理和分析工作流。
"""
def __init__(self):
"""初始化工作流"""
self.state_machine = StateMachine()
self._setup_transitions()
self._setup_listeners()
def _setup_transitions(self):
"""设置状态转换"""
sm = self.state_machine
# 启动流程
sm.add_transition(StateTransition(
from_state=WorkflowState.IDLE,
event=EventType.START,
to_state=WorkflowState.INITIALIZED,
action=self._action_initialize,
description="初始化工作流"
))
# 数据加载
sm.add_transition(StateTransition(
from_state=WorkflowState.INITIALIZED,
event=EventType.DATA_LOAD_REQUEST,
to_state=WorkflowState.LOADING_DATA,
action=self._action_load_data,
description="开始加载数据"
))
sm.add_transition(StateTransition(
from_state=WorkflowState.LOADING_DATA,
event=EventType.DATA_LOAD_SUCCESS,
to_state=WorkflowState.DATA_LOADED,
action=self._action_on_data_loaded,
description="数据加载成功"
))
sm.add_transition(StateTransition(
from_state=WorkflowState.LOADING_DATA,
event=EventType.DATA_LOAD_FAILURE,
to_state=WorkflowState.ERROR,
action=self._action_on_error,
description="数据加载失败"
))
# 数据验证
sm.add_transition(StateTransition(
from_state=WorkflowState.DATA_LOADED,
event=EventType.DATA_VALIDATE_REQUEST,
to_state=WorkflowState.VALIDATING_DATA,
action=self._action_validate_data,
description="开始验证数据"
))
sm.add_transition(StateTransition(
from_state=WorkflowState.VALIDATING_DATA,
event=EventType.DATA_VALIDATE_SUCCESS,
to_state=WorkflowState.DATA_VALIDATED,
description="数据验证成功"
))
sm.add_transition(StateTransition(
from_state=WorkflowState.VALIDATING_DATA,
event=EventType.DATA_VALIDATE_FAILURE,
to_state=WorkflowState.ERROR,
action=self._action_on_error,
description="数据验证失败"
))
# 分析
sm.add_transition(StateTransition(
from_state=WorkflowState.DATA_VALIDATED,
event=EventType.ANALYZE_REQUEST,
to_state=WorkflowState.ANALYZING,
action=self._action_analyze,
description="开始分析"
))
sm.add_transition(StateTransition(
from_state=WorkflowState.ANALYZING,
event=EventType.ANALYSIS_SUCCESS,
to_state=WorkflowState.ANALYSIS_COMPLETE,
description="分析完成"
))
# 决策
sm.add_transition(StateTransition(
from_state=WorkflowState.ANALYSIS_COMPLETE,
event=EventType.DECIDE_REQUEST,
to_state=WorkflowState.DECIDING,
action=self._action_decide,
description="开始决策"
))
sm.add_transition(StateTransition(
from_state=WorkflowState.DECIDING,
event=EventType.DECISION_SUCCESS,
to_state=WorkflowState.DECISION_MADE,
description="决策完成"
))
# 输出
sm.add_transition(StateTransition(
from_state=WorkflowState.DECISION_MADE,
event=EventType.OUTPUT_REQUEST,
to_state=WorkflowState.GENERATING_OUTPUT,
action=self._action_generate_output,
description="生成输出"
))
sm.add_transition(StateTransition(
from_state=WorkflowState.GENERATING_OUTPUT,
event=EventType.OUTPUT_SUCCESS,
to_state=WorkflowState.OUTPUT_COMPLETE,
description="输出完成"
))
# 完成
sm.add_transition(StateTransition(
from_state=WorkflowState.OUTPUT_COMPLETE,
event=EventType.START,
to_state=WorkflowState.COMPLETED,
action=self._action_complete,
description="工作流完成"
))
# 错误恢复
sm.add_transition(StateTransition(
from_state=WorkflowState.ERROR,
event=EventType.RETRY,
to_state=WorkflowState.INITIALIZED,
guard=lambda: len(self.state_machine.context.errors) < 3,
description="重试"
))
sm.add_transition(StateTransition(
from_state=WorkflowState.ERROR,
event=EventType.RESET,
to_state=WorkflowState.IDLE,
action=self._action_reset,
description="重置"
))
def _setup_listeners(self):
"""设置状态监听器"""
sm = self.state_machine
# 错误状态监听器
sm.add_state_listener(WorkflowState.ERROR, self._on_error_state)
# 完成状态监听器
sm.add_state_listener(WorkflowState.COMPLETED, self._on_complete_state)
# ------------------------------------------------------------------------
# 状态动作
# ------------------------------------------------------------------------
def _action_initialize(self, ctx: StateContext, payload: Any):
"""初始化动作"""
ctx.start_time = datetime.now()
ctx.set_data("workflow_id", f"WF-{datetime.now().strftime('%Y%m%d%H%M%S')}")
print(" [动作] 工作流初始化完成")
def _action_load_data(self, ctx: StateContext, payload: Any):
"""加载数据动作"""
source = payload or "默认数据源"
print(f" [动作] 从 '{source}' 加载数据...")
# 模拟数据加载
ctx.set_data("raw_data", [
{"id": 1, "x": 10, "y": 20, "value": 100},
{"id": 2, "x": 30, "y": 40, "value": 200},
{"id": 3, "x": 50, "y": 60, "value": 150},
])
# 模拟成功
self.state_machine.trigger(EventType.DATA_LOAD_SUCCESS)
def _action_on_data_loaded(self, ctx: StateContext, payload: Any):
"""数据加载完成动作"""
data_count = len(ctx.get_data("raw_data", []))
print(f" [动作] 数据加载完成,共 {data_count} 条记录")
def _action_validate_data(self, ctx: StateContext, payload: Any):
"""验证数据动作"""
print(" [动作] 验证数据...")
data = ctx.get_data("raw_data", [])
valid = all("id" in item and "x" in item and "y" in item for item in data)
if valid:
self.state_machine.trigger(EventType.DATA_VALIDATE_SUCCESS)
else:
ctx.add_error("数据验证失败: 缺少必需字段")
self.state_machine.trigger(EventType.DATA_VALIDATE_FAILURE)
def _action_analyze(self, ctx: StateContext, payload: Any):
"""分析动作"""
print(" [动作] 执行空间分析...")
data = ctx.get_data("raw_data", [])
values = [item.get("value", 0) for item in data]
avg = sum(values) / len(values) if values else 0
ctx.set_data("analysis_result", {
"average": avg,
"count": len(data),
"min": min(values) if values else 0,
"max": max(values) if values else 0
})
print(f" [动作] 分析完成,平均值: {avg:.2f}")
self.state_machine.trigger(EventType.ANALYSIS_SUCCESS)
def _action_decide(self, ctx: StateContext, payload: Any):
"""决策动作"""
print(" [动作] 执行决策...")
analysis = ctx.get_data("analysis_result", {})
avg = analysis.get("average", 0)
if avg > 150:
decision = "高价值区域"
elif avg > 100:
decision = "中等价值区域"
else:
decision = "低价值区域"
ctx.set_data("decision", decision)
print(f" [动作] 决策完成: {decision}")
self.state_machine.trigger(EventType.DECISION_SUCCESS)
def _action_generate_output(self, ctx: StateContext, payload: Any):
"""生成输出动作"""
print(" [动作] 生成输出报告...")
report = {
"workflow_id": ctx.get_data("workflow_id"),
"data_count": len(ctx.get_data("raw_data", [])),
"analysis": ctx.get_data("analysis_result"),
"decision": ctx.get_data("decision")
}
ctx.set_data("output", report)
print(" [动作] 输出生成完成")
self.state_machine.trigger(EventType.OUTPUT_SUCCESS)
def _action_complete(self, ctx: StateContext, payload: Any):
"""完成动作"""
ctx.end_time = datetime.now()
duration = (ctx.end_time - ctx.start_time).total_seconds() if ctx.start_time else 0
ctx.set_data("duration", duration)
print(f" [动作] 工作流完成,耗时: {duration:.2f}")
def _action_on_error(self, ctx: StateContext, payload: Any):
"""错误处理动作"""
print(f" [动作] 发生错误")
def _action_reset(self, ctx: StateContext, payload: Any):
"""重置动作"""
print(" [动作] 重置工作流")
# ------------------------------------------------------------------------
# 状态监听器
# ------------------------------------------------------------------------
def _on_error_state(self, state: WorkflowState, ctx: StateContext):
"""错误状态处理"""
print(f" [监听器] 进入错误状态")
print(f" [监听器] 错误列表: {ctx.errors}")
def _on_complete_state(self, state: WorkflowState, ctx: StateContext):
"""完成状态处理"""
print(f" [监听器] 工作流已完成")
output = ctx.get_data("output")
if output:
print(f" [监听器] 最终输出: {json.dumps(output, ensure_ascii=False, indent=2)}")
# ------------------------------------------------------------------------
# 公共接口
# ------------------------------------------------------------------------
def start(self, data_source: str = None) -> bool:
"""启动工作流"""
return self.state_machine.trigger(EventType.START, data_source)
def execute_full_workflow(self, data_source: str = None) -> Dict[str, Any]:
"""
执行完整工作流
Args:
data_source: 数据源
Returns:
执行结果
"""
print("\n" + "="*60)
print("执行完整空间分析工作流")
print("="*60)
# 启动
if not self.start(data_source):
return {"success": False, "error": "启动失败"}
# 等待异步操作完成 (简化版: 手动触发)
# 在实际应用中,这些事件会由异步操作触发
return {
"success": True,
"final_state": self.state_machine.current_state.value,
"context": self.state_machine.context.data
}
def print_history(self):
"""打印状态转换历史"""
history = self.state_machine.context.history
print(f"\n状态转换历史 (共 {len(history)} 次):")
print("-" * 70)
for i, h in enumerate(history, 1):
ts = h.get("timestamp", datetime.now()).strftime("%H:%M:%S")
print(f"{i:2d}. [{ts}] {h['from_state']:20s} -> {h['to_state']:20s} ({h['event']})")
print("-" * 70)
# ============================================================================
# 主程序
# ============================================================================
def main():
"""主程序 - 演示状态机工作流的使用"""
print("="*70)
print("状态机工作流示例演示")
print("="*70)
# 1. 创建工作流
print("\n[步骤 1] 创建空间分析工作流")
workflow = SpatialAnalysisWorkflow()
# 2. 显示初始状态
print("\n[步骤 2] 初始状态")
workflow.state_machine.print_state()
# 3. 手动执行状态转换
print("\n[步骤 3] 手动执行状态转换")
# 启动
print("\n3.1 启动工作流:")
workflow.state_machine.trigger(EventType.START)
workflow.state_machine.print_state()
# 请求数据加载 (这将触发加载动作,然后自动触发成功事件)
print("\n3.2 请求数据加载:")
workflow.state_machine.trigger(EventType.DATA_LOAD_REQUEST, "sample.csv")
workflow.state_machine.print_state()
# 请求数据验证
print("\n3.3 请求数据验证:")
workflow.state_machine.trigger(EventType.DATA_VALIDATE_REQUEST)
workflow.state_machine.print_state()
# 请求分析
print("\n3.4 请求分析:")
workflow.state_machine.trigger(EventType.ANALYZE_REQUEST)
workflow.state_machine.print_state()
# 请求决策
print("\n3.5 请求决策:")
workflow.state_machine.trigger(EventType.DECIDE_REQUEST)
workflow.state_machine.print_state()
# 请求输出
print("\n3.6 请求输出:")
workflow.state_machine.trigger(EventType.OUTPUT_REQUEST)
workflow.state_machine.print_state()
# 完成
print("\n3.7 完成工作流:")
workflow.state_machine.trigger(EventType.START)
workflow.state_machine.print_state()
# 4. 显示转换历史
print("\n[步骤 4] 状态转换历史")
workflow.print_history()
# 5. 演示错误处理
print("\n[步骤 5] 演示错误处理和恢复")
print("\n5.1 重置状态机:")
workflow.state_machine.reset()
workflow.state_machine.print_state()
print("\n5.2 启动后触发错误:")
workflow.state_machine.trigger(EventType.START)
workflow.state_machine.trigger(EventType.DATA_LOAD_FAILURE)
workflow.state_machine.print_state()
print("\n5.3 尝试重试:")
if workflow.state_machine.can_trigger(EventType.RETRY):
workflow.state_machine.trigger(EventType.RETRY)
workflow.state_machine.print_state()
else:
print(" 无法重试 (已达到最大重试次数)")
print("\n5.4 重置工作流:")
workflow.state_machine.trigger(EventType.RESET)
workflow.state_machine.print_state()
print("\n" + "="*70)
print("演示完成!")
print("="*70)
if __name__ == "__main__":
main()