代码存档_古地图电子化_地物精度概率矩阵DAG

1_基本要素

共有 n 个节点(地物),每个节点都含有 n 个参数,第 i 个参数用于表示“本节点(地物)绘制时的相对位置关系参照于第 i 个节点”的概率,此时我们获得了一个 \(n \times n\) 的概率矩阵

2_概率的获取

通过角度精度、距离精度、距离三个参数的加权计算取得,其中角度精度、距离精度与概率呈正相关,距离与概率呈负相关

\[F_d[i,j] = exp(-α \cdot \frac{D_{real}[i,j]}{max(D_{real})}) \]

\(D_{real}[i,j]\):真实两点间距离

\(max⁡(D_{real})\):研究区域的最大距离,用于归一化

\(\alpha > 0\):控制衰减速度

\[S[i,j] = (w_d \cdot E_d[i,j] + w_a \cdot E_a[i,j]) \cdot F_d[i,j] \]

3_DAG生成

通过这种概率矩阵试图生成一个多入边有向无环图 (OBS、Greedy)

4_做健壮性检验

(方法未定)

点击查看代码
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
from typing import List, Tuple, Dict
import random
import matplotlib.colors as mcolors

class EnhancedGraphAnalysisFixed:
    def __init__(self, n_nodes: int = 15, alpha: float = 2.0, w_d: float = 0.3, w_a: float = 0.7, prob_threshold: float = 0.05):
        self.n_nodes = n_nodes
        self.alpha = alpha  # 距离衰减系数
        self.w_d = w_d      # 距离精度权重
        self.w_a = w_a      # 角度精度权重
        self.prob_threshold = prob_threshold  # 概率阈值,控制图的稀疏程度
        self.nodes_data = []
        self.probability_matrix = None
        self.coordinates = []
        self.distance_matrix = None
        
    def generate_data(self) -> List[Dict]:
        """生成模拟数据(重构版)"""
        print("生成模拟数据...")
        
        # 生成节点坐标
        np.random.seed(32)
        self.coordinates = np.random.rand(self.n_nodes, 2) * 100
        
        # 计算距离矩阵
        self.distance_matrix = np.zeros((self.n_nodes, self.n_nodes))
        for i in range(self.n_nodes):
            for j in range(self.n_nodes):
                self.distance_matrix[i, j] = np.linalg.norm(self.coordinates[i] - self.coordinates[j])
        
        self.nodes_data = []
        for i in range(self.n_nodes):
            node_data = {
                'node_id': i,
                'coordinates': self.coordinates[i],
                'angle_precisions': [],
                'distance_precisions': []
            }
            
            # 生成角度精度:0.5-1.0之间的高精度值(第i个为0)
            angle_prec = np.random.uniform(0.5, 1.0, self.n_nodes)
            angle_prec[i] = 0.0
            node_data['angle_precisions'] = angle_prec
            
            # 生成距离精度:0.5-1.0之间的高精度值(第i个为0)
            dist_prec = np.random.uniform(0.5, 1.0, self.n_nodes)
            dist_prec[i] = 0.0
            node_data['distance_precisions'] = dist_prec
            
            self.nodes_data.append(node_data)
            
        print(f"生成了 {self.n_nodes} 个节点")
        return self.nodes_data
    
    def calculate_probabilities(self) -> np.ndarray:
        """计算概率矩阵(基于重构的综合权重公式)"""
        print("计算概率矩阵(重构版)...")
        
        self.probability_matrix = np.zeros((self.n_nodes, self.n_nodes))
        
        # 计算最大距离用于归一化
        max_distance = np.max(self.distance_matrix)
        
        for i in range(self.n_nodes):
            # 计算综合权重S[i,j]
            S = np.zeros(self.n_nodes)
            
            for j in range(self.n_nodes):
                if i == j:
                    S[j] = 0.0
                    continue
                
                # 获取精度数据
                angle_prec = self.nodes_data[i]['angle_precisions'][j]
                dist_prec = self.nodes_data[i]['distance_precisions'][j]
                
                # 距离衰减函数 F_d[i,j] = exp(-α * (D_real[i,j] / max(D_real)))
                distance_factor = np.exp(-self.alpha * (self.distance_matrix[i, j] / max_distance))
                
                # 综合权重 S[i,j] = (w_d * E_d[i,j] + w_a * E_a[i,j]) * F_d[i,j]
                # 使用精度值作为权重(值越小精度越高,所以用1/精度)
                E_d = 1.0 / (dist_prec + 0.01)  # 避免除零
                E_a = 1.0 / (angle_prec + 0.01)
                
                S[j] = (self.w_d * E_d + self.w_a * E_a) * distance_factor
            
            # 归一化概率矩阵 P[i,j] = S[i,j] / Σ_{k ≠ i} S[i,k]
            row_sum = np.sum(S)
            if row_sum > 0:
                self.probability_matrix[i] = S / row_sum
            else:
                self.probability_matrix[i] = np.zeros(self.n_nodes)
                
        return self.probability_matrix
    
    def obs_method_single_root(self) -> List[Tuple[int, int]]:
        """改进的OBS方法:基于概率选择最优父节点,允许多个父节点,确保无环"""
        edges = []
        
        # 步骤1:为每个子节点选择概率最高的前k个父节点
        for child in range(self.n_nodes):
            # 收集所有可能的父节点及其概率
            parent_probs = []
            for parent in range(self.n_nodes):
                if parent != child and self.probability_matrix[parent, child] > self.prob_threshold:
                    parent_probs.append((self.probability_matrix[parent, child], parent, child))
            
            # 按概率排序,选择前k个(k=2或3,避免过多边)
            parent_probs.sort(reverse=True, key=lambda x: x[0])
            max_parents = min(2, len(parent_probs))  # 限制每个节点最多2个父节点
            
            # 步骤2:按概率从高到低添加边,确保不形成环
            for prob, parent, child_node in parent_probs[:max_parents]:
                temp_edges = edges + [(parent, child_node)]
                if not self._has_cycle(temp_edges):
                    edges.append((parent, child_node))
        
        return edges
    
    def greedy_method_with_root(self) -> List[Tuple[int, int]]:
        """改进的贪心方法:允许多个父节点,确保无环,使用概率阈值控制稀疏性"""
        edges = []
        
        prob_edges = []
        for i in range(self.n_nodes):
            for j in range(self.n_nodes):
                if i != j and self.probability_matrix[i, j] > self.prob_threshold:
                    prob_edges.append((self.probability_matrix[i, j], i, j))
        
        prob_edges.sort(reverse=True, key=lambda x: x[0])
        
        # 贪心添加边,允许多个父节点,只检查是否形成环,限制边数以避免过密
        max_edges = min(len(prob_edges), self.n_nodes * 2)  # 限制边数约为节点数的2倍
        for idx, (prob, parent, child) in enumerate(prob_edges[:max_edges]):
            temp_edges = edges + [(parent, child)]
            if not self._has_cycle(temp_edges):
                edges.append((parent, child))
        
        return edges
    
    def _has_cycle(self, edges: List[Tuple[int, int]]) -> bool:
        """检查是否有环"""
        if not edges:
            return False
            
        G = nx.DiGraph()
        G.add_edges_from(edges)
        
        try:
            # 检查是否有环
            nx.find_cycle(G)
            return True
        except nx.NetworkXNoCycle:
            return False
    
    def find_root_nodes(self, edges: List[Tuple[int, int]]) -> List[int]:
        """找出最高级节点(无入度节点)"""
        all_nodes = set(range(self.n_nodes))
        child_nodes = set(child for _, child in edges)
        root_nodes = list(all_nodes - child_nodes)
        return root_nodes
    
    def analyze_graph(self, edges: List[Tuple[int, int]], method_name: str) -> Dict:
        """分析图结构"""
        all_nodes = set(range(self.n_nodes))
        
        # 计算入度和出度
        in_degree = {node: 0 for node in all_nodes}
        out_degree = {node: 0 for node in all_nodes}
        
        for parent, child in edges:
            out_degree[parent] += 1
            in_degree[child] += 1
        
        # 无入度节点(根节点)
        root_nodes = [node for node in all_nodes if in_degree[node] == 0]
        
        # 无出度节点(叶子节点)
        leaf_nodes = [node for node in all_nodes if out_degree[node] == 0]
        
        # 孤立节点
        isolated_nodes = [node for node in all_nodes 
                         if in_degree[node] == 0 and out_degree[node] == 0]
        
        return {
            'root_nodes': root_nodes,
            'leaf_nodes': leaf_nodes,
            'isolated_nodes': isolated_nodes,
            'in_degree': in_degree,
            'out_degree': out_degree,
            'total_edges': len(edges)
        }
    
    def create_colored_edges(self, edges: List[Tuple[int, int]]) -> Dict:
        """为边创建不同颜色"""
        colors = list(mcolors.TABLEAU_COLORS.values()) + list(mcolors.CSS4_COLORS.values())
        edge_colors = {}
        
        for i, (parent, child) in enumerate(edges):
            color = colors[i % len(colors)]
            edge_colors[(parent, child)] = color
            
        return edge_colors
    
    def plot_enhanced_graphs(self, obs_edges: List[Tuple[int, int]], 
                           greedy_edges: List[Tuple[int, int]]):
        """增强版可视化(彩色边 + 最高级节点特殊标注)"""
        fig, axes = plt.subplots(1, 2, figsize=(20, 8))
        
        methods = ['OBS Method (natural DAG)', 'Greedy Method (natural DAG)']
        edges_list = [obs_edges, greedy_edges]
        
        for idx, (method, edges) in enumerate(zip(methods, edges_list)):
            G = nx.DiGraph()
            G.add_nodes_from(range(self.n_nodes))
            G.add_edges_from(edges)
            
            pos = {i: self.coordinates[i] for i in range(self.n_nodes)}
            
            # 创建彩色边
            edge_colors = self.create_colored_edges(edges)
            edge_color_list = [edge_colors[edge] for edge in edges]
            
            # 找出最高级节点(无入度节点)
            root_nodes = self.find_root_nodes(edges)
            regular_nodes = [n for n in range(self.n_nodes) if n not in root_nodes]
            
            # 绘制普通节点
            if regular_nodes:
                nx.draw_networkx_nodes(G, pos, ax=axes[idx], 
                                     nodelist=regular_nodes,
                                     node_color='lightblue', node_size=500)
            
            # 绘制最高级节点(特殊标注:红色大节点)
            if root_nodes:
                nx.draw_networkx_nodes(G, pos, ax=axes[idx], 
                                     nodelist=root_nodes,
                                     node_color='red', node_size=800, 
                                     node_shape='o', linewidths=2,
                                     edgecolors='darkred')
            
            # 绘制边,每条边使用不同颜色
            nx.draw_networkx_edges(G, pos, ax=axes[idx], 
                                 edge_color=edge_color_list, 
                                 arrows=True, arrowsize=20, 
                                 connectionstyle="arc3,rad=0.1")
            
            # 绘制标签
            nx.draw_networkx_labels(G, pos, ax=axes[idx], font_size=10,
                                  font_color='black')
            
            # 添加图例
            legend_elements = [
                plt.Line2D([0], [0], marker='o', color='w', markerfacecolor='red', 
                         markersize=12, label=f'Root Nodes ({len(root_nodes)})'),
                plt.Line2D([0], [0], marker='o', color='w', markerfacecolor='lightblue', 
                         markersize=10, label='Regular Nodes')
            ]
            axes[idx].legend(handles=legend_elements, loc='upper right', 
                           bbox_to_anchor=(1.0, 1.0))
            
            axes[idx].set_title(f'{method}\nEdges: {len(edges)}, Root Nodes: {len(root_nodes)}', 
                              fontsize=14)
            axes[idx].set_xlim(-10, 110)
            axes[idx].set_ylim(-10, 110)
            axes[idx].grid(True, alpha=0.3)
            axes[idx].set_aspect('equal')
        
        plt.tight_layout()
        plt.savefig('enhanced_graphs_with_roots.png', dpi=300, bbox_inches='tight')
        plt.show()
    
    def run_enhanced_analysis(self):
        """运行增强版分析"""
        print("运行增强版图关系分析...")
        
        # 1. 生成数据
        self.generate_data()
        
        # 2. 计算概率
        self.calculate_probabilities()
        
        # 3. 两种方法
        obs_result = self.obs_method_single_root()
        greedy_result = self.greedy_method_with_root()

        print(f"\n增强版分析结果:")
        print(f"OBS: {len(obs_result)} 条边")
        print(f"Greedy: {len(greedy_result)} 条边")
        
        # 4. 分析图结构
        obs_analysis = self.analyze_graph(obs_result, "OBS")
        greedy_analysis = self.analyze_graph(greedy_result, "Greedy")
        
        print(f"\nOBS方法 - 根节点: {obs_analysis['root_nodes']} (共{len(obs_analysis['root_nodes'])}个)")
        print(f"Greedy方法 - 根节点: {greedy_analysis['root_nodes']} (共{len(greedy_analysis['root_nodes'])}个)")
        
        # 5. 可视化
        self.plot_enhanced_graphs(obs_result, greedy_result)
        
        return {
            'obs': obs_result,
            'greedy': greedy_result,
            'obs_analysis': obs_analysis,
            'greedy_analysis': greedy_analysis
        }

if __name__ == "__main__":
    analyzer = EnhancedGraphAnalysisFixed(n_nodes=15)
    results = analyzer.run_enhanced_analysis()
    
    print("\n概率矩阵示例(前5x5):")
    print(np.round(analyzer.probability_matrix[:5, :5], 3))
posted @ 2025-08-18 13:29  IronRoc  阅读(10)  评论(0)    收藏  举报