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:
@@ -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()
|
||||
Reference in New Issue
Block a user