精华内容
下载资源
问答
  • var msum = require ( 'convex-minkowski-sum' ) //A is a triangle in 3D var A = [ [ 1 , 0 , 0 ] , [ 0 , 1 , 0 ] , [ 1 , 1 , 0 ] ] //B is a line segment var B = [ [ 0 , - 1 , 0 ] , [ 0 , 1 , 0 ] ] ...
  • minkowski_addition 计算点的两个向量的Minkowski和(集合扩张)
  • Minkowski引擎是一个用于稀疏张量的自动微分库。 它支持所有标准神经网络层,例如对稀疏张量的卷积,池化,解池和广播操作。 有关更多信息,请访问。 新闻 2020-12-24 v0.5现已发布! 新版本为所有坐标管理功能提供...
  • 为了实现一款天线在ISM2.4G(2.4~2.483 5 GHz)、Bluetooth、GPS、WLAN(2.4~2.48 GHz)等多频段同时工作,设计了基于分形理论的类Minkowski分形微带天线,方案中对原有的Minkowski分形结构和接地板进行改进。...
  • 基于Minkowski泛函和K-means聚类算法的岩石类型划分.pdf
  • 具有自旋1/2组成的两体约束系统的Bethe–Salpeter方程可直接在Minkowski空间中求解。 为了实现这一目标,我们使用贝丝–萨尔佩特幅值的纳卡尼西积分表示形式,并利用由精确投影到零平面上表示的形式工具。 这一正式...
  • 我们研究了4D Minkowski时空的Yang-Baxter变形。 Yang-Baxter sigma模型的描述最初是基于修改后的经典Yang-Baxter方程为主要手性模型开发的。 它已被扩展到基于通常的经典Yang-Baxter方程的同组弯曲空间和模型。 另...
  • 研究了瞬时,空间和类似光的形变的κ-Minkowski空间线性实现。 我们构造和分类所有此类线性实现,并根据gl(n)生成器对其进行表达。 对于类似时间的变形和类似空间的变形,存在三个线性的单参数实现,而对于类似光...
  • 利用Minkowski分形边界结构,设计了一款面向全球定位系统应用的宽频带蝶形天线.通过对不同迭代次数的分形天线进行仿真对比,选取2次迭代的分形结构设计了工作于GPS波段的蝶形天线,加工制作出该天线并对其进行测试,测试...
  • Minkowski空间中的介子结构是根据Bethe–Salpeter振幅与欧几里得格子QCD结果的解析模型来描述的。 该模型的物理动机是考虑到运行的夸克质量,该夸克质量适合于莱迪思QCD数据。 pion伪标量顶点与夸克质量函数相关联,...
  • Minkowski引擎是一个用于稀疏张量的自动微分库。 它支持所有标准神经网络层,例如稀疏张量的卷积,池化,解池和广播操作。Minkowski Engine Minkowski Engine是稀疏张量的自动微分库。 它支持所有标准神经网络层,...
  • 我们从不同的角度重新审视了相对论中一维和二维的弹性碰撞问题。 为了在实验室系统中获得碰撞问题的最终... 对于一维情况,我们还给出了一个示例,以说明Minkowski动量空间中粒子的状态,该示例显示了碰撞的整个过程。
  • 计算两个矩阵的列之间具有指数 p 的闵可夫斯基距离。 矩阵在行和列维度上的大小可能不同。 阅读函数标题以获取示例和用户指南。
  • 本文首先证明在三维Minkowski空间L3={R3:dx2+dy2-dz2}中存在无数直纹极小类时曲面,然后对直纹极值混合型曲面进行了分类。
  • 研究了二次曲面绕不同...在三维Minkowski空间中,二次曲面的变换有旋转和平移,旋转又分为在正交标架下绕类空轴、类时轴的旋转和在伪正交标架下绕类光轴的旋转,在不同的旋转变换下有不同的不变量,分类结果也不同。
  • Minkowski-Bouligand-dimension:几何分形,ladimensiónde Minkowski-Bouligand,坦比亚梅特里科
  • 基于Minkowski距离的一致聚类改进算法及应用研究
  • MFD for CDE图像分类,用于静态图像中灵活CDE中的动态参数选择 在源路径中针对每个图像及其GTCount和Img / Mat文件名计算和存储MFD值 第二项 第三项 :play_button: 关于MFD计算结果的讨论 考虑映像编号0002,0003和...
  • 我们重新审视了非交换时空对称性的量子李代数的概念,它的元素被证明是无穷小变换的产生者,并且自然地可以通过物理观测得到。 非交换空间上的波动方程是从量子霍奇星算子推导出来的。
  • 计算 3 个 2D Minkowski 参数
  • 我们将详细介绍[1,2]中出现的Green函数,其中概括了从无质量粒子到块状粒子的软定理和大尺寸对称的Ward恒等式之间的各种等价关系。 我们对这些格林函数进行了详细的分析,表明它们形成了一个函数层次结构,分别描述...
  • 点云中的Minkowski卷积

    千次阅读 2020-11-21 12:12:26
    MinkowskiEngine是在4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural Networks[CVPR 2019]被提出的,主页,源码。目前已更新到v0.5版本,且正处于更新中。 二、Minkowski Convolution的定义 点云数据...

    一、MinkowskiEngine简介

    第一次见到MinkowskiEngine,应该是在两个月之前了,当时也没有去留意这个库。最近读了一些点云的论文,发现还是有不少论文的源码是基于MinkowskiEngine的,包括PointContrast(ECCV 2020),DGR(Deep Global Registration, CVPR 2020),Learning Multiview 3D Point Cloud Registration(CVPR 2020)和FCGF(Fully Convolutional Geometric Features, ICCV 2019)等,所以决定去了解一下这个库。

    MinkowskiEngine是稀疏张量自动微分库,致力于高维空间稀疏数据的操作。它支持所有的神经网络层,如Conv, Pooling, Unpooling和广播操作。基于MinkowskiEngine,可以实现点云的分割、分类、重建、补全、检测等任务。

    MinkowskiEngine是在4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural Networks[CVPR 2019]被提出的,主页源码。目前已更新到v0.5版本,且正处于更新中。

    二、Minkowski Convolution的定义

    • 点云数据的表示

      MinkowskiEngine把点云表示成两部分: 坐标矩阵 C C C和特征矩阵 F F F

      C = [ x 1 y 1 z 1 b 1 : : x N y N z N b N ] C = \left[ \begin{matrix} x_1 & y_1 & z_1 & b_1\\ & : & : & \\ x_N & y_N & z_N & b_N \end{matrix} \right] C=x1xNy1:yNz1:zNb1bN F = [ f 1 T : f N T ] F = \left[ \begin{matrix} f_1^T \\ : \\ f_N^T \end{matrix} \right] F=f1T:fNT

      其中 ( x i , y i , z i ) (x_i, y_i, z_i) (xi,yi,zi)表示点云的坐标, b i b_i bi表示 ( x i , y i , z i ) (x_i, y_i, z_i) (xi,yi,zi)属于batch中的哪个点云(MinkowskiEngine也是把点云组织成batch进行训练), N N N表示1个batch中所有点的数量, f i T f_i^T fiT表示第 i i i个点的特征,可以是1维或者3维或者其它维度的。

      这样的表示,相比于3D卷积(X, Y, Z, D)的表示,可以节省空间。[N << XYZ -> N * 4 + N*D << XYZD, << 表示远小于]

    • 常规3D卷积:

      x u out = Σ i ∈ V ( K ) W i x u + i in , for u ∈ Z 3 \text{x}_u^{\text{out}} = \Sigma_{\text{i} \in V(K)}W_i\text{x}_{u + \text{i}}^{\text{in}}, \quad \text{for} \quad u \in \mathbb Z^3 xuout=ΣiV(K)Wixu+iin,foruZ3

      u ∈ Z 3 u \in \mathbb Z^3 uZ3表示3D坐标, K K K表示卷积中的kernel_size,V(K)是3维空间中的offsets集合, W i ∈ N out × N in W_i \in \mathbb N^{\text {out}} \times \mathbb N^ \text{in} WiNout×Nin

    • Minkowski 卷积

      x u out = Σ i ∈ N ( u , C in ) W i x u + i in , for u ∈ C out \text{x}_u^{\text{out}} = \Sigma_{\text{i} \in N(u, \mathbb C^{\text{in}})}W_i\text{x}_{u + \text{i}}^{\text{in}}, \quad \text{for} \quad u \in \mathbb C^{\text{out}} xuout=ΣiN(u,Cin)Wixu+iin,foruCout

      对于常规3D卷积,可以看到变化的是 u ∈ C out u \in \mathbb C^{\text{out}} uCout i ∈ N ( u , C in ) \text{i} \in N(u, \mathbb C^{\text{in}}) iN(u,Cin) C in \mathbb C^{\text{in}} Cin C out \mathbb C^{\text{out}} Cout是预定义的稀疏张量的输入坐标和输出坐标, N ( u , C in ) = { i ∣ u + i ∈ C in , i ∈ V ( K ) } N(u, \mathbb C^{\text{in}}) = \lbrace \text{i} | u + \text{i} \in \mathbb C^{\text{in}}, i \in V(K) \rbrace N(u,Cin)={iu+iCin,iV(K)}。因此,相比于常规卷积,不是每一个(x, y, z)位置都会有一个卷积的输出,同时并不是每一个offset位置都会参与计算卷积。

    三、从使用的角度看MinkowskiEngine

    卷积中常见的操作包括Conv, BN, Pooling, FC, transposed Conv等,本章节基于两个很简单的分类网络和分割网络在MinkowskiEngine环境实验上述操作。实验的环境是Ubuntu14.4, Cuda10.2, PyTorch 1.5, Python 3.7, MinkowskiEngine v0.5(下面的实验代码对于其它环境或许也同样支持)。

    3.0 网络的输入数据

    为了方便观察数据,设batch size=2,第一个点云P1中具有10个点,第二个点云P2中具有6个点,每个点的特征是3维的。下面代码生成P1和P2点云,并转换成MinkowskiEngine的输入数据格式。

    import numpy as np
    import torch.nn as nn
    import MinkowskiEngine as ME
    
    
    def print_title(s, data):
        print('='*20, s, '='*20)
        print(data)
    
    
    if __name__ == '__main__':
        origin_pc1 = 100 * np.random.uniform(0, 1, (10, 3))
        feat1 = np.ones((10, 3), dtype=np.float32)
        origin_pc2 = 100 * np.random.uniform(0, 1, (6, 3))
        feat2 = np.ones((6, 3), dtype=np.float32)
        print_title('origin_pc1', origin_pc1)
        print_title('origin_pc2', origin_pc2)
    
        coords, feats = ME.utils.sparse_collate([origin_pc1, origin_pc2], [feat1, feat2])
        print_title('coords', coords)
        print_title('feats', feats)
        input = ME.SparseTensor(feats, coordinates=coords)
        print_title('input', input)
    

    上述程序的输出:

    ==================== origin_pc1 ====================
    [[83.28334147 28.87414665 44.48401738]
     [43.04924052 34.66068275 28.201644  ]
     [22.51394645 53.53203799 25.68239097]
     [11.39696393 27.68488056 18.02263419]
     [68.04944494 78.4874799  33.54077384]
     [83.11021987 95.29080943 72.42599245]
     [68.96104764 64.38640545 56.64488121]
     [61.26343854 35.13968286 10.67545387]
     [95.5847873  56.20865881  5.97082126]
     [63.43547357 75.31685552 67.71327187]]
    ==================== origin_pc2 ====================
    [[21.01681082 32.60864402 14.68910937]
     [76.90920828 40.72511594 17.21551445]
     [67.84378491 80.58219012 43.75387818]
     [45.97922404 77.97593435  3.17289328]
     [39.91144138 80.02990713 44.97847053]
     [ 1.55805162 57.33833007 92.04541106]]
    ==================== coords ====================
    tensor([[ 0, 83, 28, 44],
            [ 0, 43, 34, 28],
            [ 0, 22, 53, 25],
            [ 0, 11, 27, 18],
            [ 0, 68, 78, 33],
            [ 0, 83, 95, 72],
            [ 0, 68, 64, 56],
            [ 0, 61, 35, 10],
            [ 0, 95, 56,  5],
            [ 0, 63, 75, 67],
            [ 1, 21, 32, 14],
            [ 1, 76, 40, 17],
            [ 1, 67, 80, 43],
            [ 1, 45, 77,  3],
            [ 1, 39, 80, 44],
            [ 1,  1, 57, 92]], dtype=torch.int32)
    ==================== feats ====================
    tensor([[1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.]])
    ==================== input ====================
    SparseTensor(
      coordinates=tensor([[ 0, 83, 28, 44],
            [ 0, 43, 34, 28],
            [ 0, 22, 53, 25],
            [ 0, 11, 27, 18],
            [ 0, 68, 78, 33],
            [ 0, 83, 95, 72],
            [ 0, 68, 64, 56],
            [ 0, 61, 35, 10],
            [ 0, 95, 56,  5],
            [ 0, 63, 75, 67],
            [ 1, 21, 32, 14],
            [ 1, 76, 40, 17],
            [ 1, 67, 80, 43],
            [ 1, 45, 77,  3],
            [ 1, 39, 80, 44],
            [ 1,  1, 57, 92]], dtype=torch.int32)
      features=tensor([[1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.]])
      coordinate_map_key=coordinate map key:[1, 1, 1]
      coordinate_manager=CoordinateMapManagerCPU(
    	[1, 1, 1]:	CoordinateMapCPU:16x4
    	algorithm=MinkowskiAlgorithm.DEFAULT
      )
      spatial dimension=3)
    

    可以看到:

    • ME.utils.sparse_collate把P1和P2点云数据的坐标进行了量化,并组成了batch的格式, 0表示属于P1点云数据,1表示属于P2点云数据
    • ME.SparseTensor把数据转换成了SparseTensor,MinkowskiEngine需要的数据格式。SparseTensor包括coordinates和features的信息。

    3.1 分类网络

    这里只实现Conv(3, 64) + BN + ReLU + GlobalPooling + FC(64, 32)的简单分类网络。

    import numpy as np
    import torch.nn as nn
    import MinkowskiEngine as ME
    
    
    class ExampleNetwork(ME.MinkowskiNetwork):
        def __init__(self, in_feat, out_feat, D=3):
            super(ExampleNetwork, self).__init__(D)
            self.conv = nn.Sequential(
                    ME.MinkowskiConvolution(
                        in_channels=in_feat,
                        out_channels=64,
                        kernel_size=3,
                        stride=1,
                        dilation=1,
                        bias=False,
                        dimension=D),
                    ME.MinkowskiBatchNorm(64),
                    ME.MinkowskiReLU())
            self.pooling = ME.MinkowskiGlobalPooling(ME.PoolingMode.GLOBAL_AVG_POOLING_KERNEL)
            self.linear = ME.MinkowskiLinear(64, out_feat)
    
        def forward(self, x):
            out = self.conv(x)
            print('conv: ', out.coordinates.size(), out.features.size())
            out = self.pooling(out)
            print('pooling: ', out.coordinates.size(), out.features.size())
            out = self.linear(out)
            print('linear: ', out.coordinates.size(), out.features.size())
            return out
    
    
    if __name__ == '__main__':
        origin_pc1 = 100 * np.random.uniform(0, 1, (10, 3))
        feat1 = np.ones((10, 3), dtype=np.float32)
        origin_pc2 = 100 * np.random.uniform(0, 1, (6, 3))
        feat2 = np.ones((6, 3), dtype=np.float32)
    
        coords, feats = ME.utils.sparse_collate([origin_pc1, origin_pc2], [feat1, feat2])
        input = ME.SparseTensor(feats, coordinates=coords)
    
        net = ExampleNetwork(in_feat=3, out_feat=32)
        output = net(input)
    
        for k, v in net.named_parameters():
            print(k, v.size())
    

    程序运行结果如下:

    conv:  torch.Size([16, 4]) torch.Size([16, 64])
    pooling:  torch.Size([2, 4]) torch.Size([2, 64])
    linear:  torch.Size([2, 4]) torch.Size([2, 32])
    conv.0.kernel torch.Size([27, 3, 64])
    conv.1.bn.weight torch.Size([64])
    conv.1.bn.bias torch.Size([64])
    linear.linear.weight torch.Size([32, 64])
    linear.linear.bias torch.Size([32])
    

    从上面可以看到:

    • 网络中间层的输出和预期是一样的(要注意的是,pooling 之后的size变成(2, 4)和(2, 64),是因为输入的数据的batchsize=2)
    • 查看网络的参数也可以通过PyTorch中named_parameters()进行遍历,卷积层的参数的size略有不同,PyTorch中应该是(3, 3, 3, 3, 64)的格式,MinkowskiEngine直接变成了(27, 3, 64)。

    3.2 分割网络

    输入是两个点云P1, P2,分别具有100个点和6个点,网络的经过Conv(3, 64, stride=2) + BN + ReLU + transposed Conv(64, 4),结构代码如下所示:

    import numpy as np
    import torch
    import torch.nn as nn
    import MinkowskiEngine as ME
    import MinkowskiEngine.MinkowskiFunctional as MEF
    
    
    class ExampleNetwork(ME.MinkowskiNetwork):
        def __init__(self, in_feat, out_feat, D=3):
            super(ExampleNetwork, self).__init__(D)
            self.conv =  ME.MinkowskiConvolution(
                    in_channels=in_feat,
                    out_channels=64,
                    kernel_size=3,
                    stride=2,
                    dilation=1,
                    bias=False,
                    dimension=D)
            self.bn = ME.MinkowskiBatchNorm(64)
            self.conv_tr = ME.MinkowskiConvolutionTranspose(
                    in_channels=64,
                    out_channels=4,
                    kernel_size=3,
                    stride=2,
                    dilation=1,
                    bias=False,
                    dimension=D)
        def forward(self, x):
            print('input: ', x.coordinates.size(), x.features.size())
            out = self.conv(x)
            print('conv: ', out.coordinates.size(), out.features.size())
            out = self.bn(out)
            print('bn: ', out.coordinates.size(), out.features.size())
            out = MEF.relu(out)
            print('relu: ', out.coordinates.size(), out.features.size())
            out = self.conv_tr(out)
            print('conv_tr', out.coordinates.size(), out.features.size())
            return out
    
    
    if __name__ == '__main__':
        origin_pc1 = 5 * np.random.uniform(0, 1, (100, 3))
        feat1 = np.ones((100, 3), dtype=np.float32)
        origin_pc2 = 100 * np.random.uniform(0, 1, (6, 3))
        feat2 = np.ones((6, 3), dtype=np.float32)
    
        coords, feats = ME.utils.sparse_collate([origin_pc1, origin_pc2], [feat1, feat2])
        input = ME.SparseTensor(feats, coordinates=coords)
    
        net = ExampleNetwork(in_feat=3, out_feat=32)
        output = net(input)
    
        print(torch.equal(input.coordinates, output.coordinates))
        print(torch.equal(input.features, output.features))
    

    输出结果为:

    input:  torch.Size([74, 4]) torch.Size([74, 3])
    conv:  torch.Size([31, 4]) torch.Size([31, 64])
    bn:  torch.Size([31, 4]) torch.Size([31, 64])
    relu:  torch.Size([31, 4]) torch.Size([31, 64])
    conv_tr torch.Size([74, 4]) torch.Size([74, 4])
    True
    False
    

    通过实验可以观察得到:

    • 原始的点云数量应该是100 + 6个,经过量化后输出网络的点云数量是74个。
    • stride=2的卷积使得点云的数量从74->31个,可以理解为降低了点云的分辨率(对比图像)
    • transposed Conv把31个点的点云又重新恢复到74个点,倒数第二个True,表示input和output的坐标是一致的,也就是说通过conv + tr_conv,点云的数量和在tensor中的顺序并不会改变。

    四、总结

    • MinkowskiEngine可以以较低显存实现3D卷积的操作
    • MinkowskiEngine使用方便,Conv, BN, ReLU, transposed Conv等的调用方式同PyTorch,个人感觉可以轻松实现分类、分割等网络架构。
    • MinkowskiEngine在把数据输入网络之前,会对数据进行量化,会导致部分点云数据的信息丢失。

    初次接触MinkowskiEngine,理解不对的地方欢迎大家指正

    展开全文
  • using System; using System.Collections; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Web; namespace RT.MvcWeb.Utility ... public class ...

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Web;

    namespace RT.MvcWeb.Utility
    {
        public class MinkowskiSum
        {
            public class Point2D
            {
                public string name { get; set; }
                public double x { get; set; }
                public double y { get; set; }
                public double deg { get; set; }

                public Point2D()
                {
                    name = string.Empty;
                    x = 0;
                    y = 0;
                    deg = 0;
                }

                public Point2D(string strName)
                {
                    name = strName;
                    x = 0;
                    y = 0;
                    deg = 0;
                }

                public Point2D(string strName, double dX, double dY)
                {
                    name = strName;
                    x = dX;
                    y = dY;
                    deg = 0;
                }

                public Point2D(string strName, double dX, double dY, double dDeg)
                {
                    name = strName;
                    x = dX;
                    y = dY;
                    deg = dDeg;
                }

                public bool Equal(Point2D b)
                {
                    return (x == b.x && y == b.y);
                }

                public void Offset(double dX, double dY)
                {
                    x += dX;
                    y += dY;
                }

                public Point ToPoint()
                {
                    return new Point((int)x, (int)y);
                }

                public double Angle()
                {
                    return Math.Atan2(y, x);
                }

                public bool InLine(Line2D line)
                {
                    return InLine(line.pointA, line.pointB);
                }

                public bool InLineX(Line2D line)
                {
                    return InLineX(line.pointA, line.pointB);
                }

                public bool InLineR(Line2D line)
                {
                    return InLineR(line.pointA, line.pointB);
                }

                /// <summary>
                /// 判断点在线段p(1,2)内
                /// </summary>
                /// <param name="p1"></param>
                /// <param name="p2"></param>
                /// <returns></returns>
                public bool InLine(Point2D p1, Point2D p2)
                {
                    if (p1.x == p2.x)
                    {
                        if (this.x == p1.x)
                            return ((this.y - p1.y) * (this.y - p2.y) <= 0);
                        else
                            return false;
                    }
                    else if (p1.y == p2.y)
                    {
                        if (this.y == p1.y)
                            return ((this.x - p1.x) * (this.x - p2.x) <= 0);
                        else
                            return false;
                    }
                    else
                    {
                        double xc = (this.y - p2.y) * (p1.x - p2.x) / (p1.y - p2.y) + p2.x;
                        if (xc == this.x)
                            return ((this.x - p1.x) * (this.x - p2.x) <= 0);
                        else
                            return false;
                    }
                }

                /// <summary>
                /// 判断点在线条经过p1,p2的线上
                /// </summary>
                /// <param name="p1"></param>
                /// <param name="p2"></param>
                /// <returns></returns>
                public bool InLineX(Point2D p1, Point2D p2)
                {
                    if (p1.x == p2.x)
                        return (this.x == p1.x);
                    else if (p1.y == p2.y)
                        return (this.y == p1.y);
                    else
                    {
                        double xc = (this.y - p2.y) * (p1.x - p2.x) / (p1.y - p2.y) + p2.x;
                        return (xc == this.x);
                    }
                }

                /// <summary>
                /// 判断点在线条p(1,2)的右侧延长线上
                /// </summary>
                /// <param name="p1"></param>
                /// <param name="p2"></param>
                /// <returns></returns>
                public bool InLineR(Point2D p1, Point2D p2)
                {
                    if (p1.x == p2.x)
                    {
                        if (this.x == p1.x)
                            return (p2.y > p1.y && y > p2.y || p2.y < p1.y && y < p2.y);
                    }
                    else if (p1.y == p2.y)
                    {
                        if (this.y == p1.y)
                            return (p2.x > p1.x && x > p2.x && p2.x < p1.x && x < p2.x);
                    }
                    else
                    {
                        double xc = (this.y - p2.y) * (p1.x - p2.x) / (p1.y - p2.y) + p2.x;
                        if (xc == this.x)
                            return (p2.x > p1.x && x > p2.x && p2.x < p1.x && x < p2.x);
                    }
                    return false;
                }

                public override string ToString()
                {
                    return string.Format("{0}({1}*{2})+{3}", name, x, y, deg);
                }
            }

            /// <summary>
            /// 有向线段(a->b)
            /// </summary>
            public class Line2D
            {
                /// <summary>
                /// 两线相交的模式
                /// </summary>
                public enum enumCrossWay
                {
                    enumNone ,
                    /// <summary>
                    /// 两线相交第一点
                    /// </summary>
                    enumCross1 ,
                    /// <summary>
                    /// 两线相交于中间自由点
                    /// </summary>
                    enumCrossIn ,
                    /// <summary>
                    /// 两线相交于第二点
                    /// </summary>
                    enumCross2 ,
                    /// <summary>
                    /// 两线平行相交于第一点
                    /// </summary>
                    enumMix1 ,
                    /// <summary>
                    /// 两线平行相交于中间自由点
                    /// </summary>
                    enumMixIn ,
                    /// <summary>
                    /// 两线平行相交于第二点
                    /// </summary>
                    enumMix2 ,
                    /// <summary>
                    /// 两线平行相交于延长线上的任意一点
                    /// </summary>
                    enumMixOut
                }

                public Point2D pointA { get; set; }
                public Point2D pointB { get; set; }
                public double deg { get; set; }

                public Line2D(Point2D a, Point2D b)
                {
                    pointA = a;
                    pointB = b;
                    deg = Math.Atan2(pointB.y - pointA.y, pointB.x - pointA.x);
                }

                public Line2D(Polygon2D p, int nIndex)
                {
                    pointA = p[nIndex % p.Count];
                    pointB = p[(nIndex + 1) % p.Count];
                    deg = Math.Atan2(pointB.y - pointA.y, pointB.x - pointA.x);
                }

                public Line2D(Polygon2D p, int nIndex , Point2D pointStart)
                {
                    pointA = pointStart;
                    pointB = p[(nIndex + 1) % p.Count];
                    deg = Math.Atan2(pointB.y - pointA.y, pointB.x - pointA.x);
                }

                public double GetAngle()
                {
                    return Math.Atan2(pointB.y - pointA.y, pointB.x - pointA.x);
                }

                /// <summary>
                /// 求线段b的拐向
                /// </summary>
                /// <param name="b"></param>
                /// <returns>0~pi:左拐,pi~2pi:右拐</returns>
                public double GetOffCourse(Line2D b)
                {
                    double dAngle2 = b.GetAngle();
                    double dAngle1 = this.GetAngle();
                    return (dAngle2 - dAngle1 + Math.PI * 2) % (Math.PI * 2);
                }

                public override string ToString()
                {
                    return string.Format("{0}->{1}", pointA, pointB);
                }

                #region 两线段相交测试

                /// <summary>
                /// 搜索与多边形相交点所在的线段
                /// </summary>
                /// <param name="p"></param>
                /// <param name="nStartIndex"></param>
                /// <param name="enumWay"></param>
                /// <param name="pointCross"></param>
                /// <returns></returns>
                public int CrossSearch(Polygon2D p, int nStartIndex, out enumCrossWay enumWay, out Point2D pointCross)
                {
                    for (int i = nStartIndex; i < p.Count; i++)
                    {
                        Line2D b = new Line2D(p, i);
                        enumWay = CrossTest(b, out pointCross);
                        if (enumWay != enumCrossWay.enumNone)
                        {
                            if (enumWay == enumCrossWay.enumCross1 ||
                                enumWay == enumCrossWay.enumCrossIn)
                            {
                                if (GetOffCourse(b) < Math.PI)
                                {
                                    enumWay = enumCrossWay.enumNone;
                                    continue;
                                }
                            }
                            if (enumWay == enumCrossWay.enumCross2)
                            {
                                //相交于该线的终点,即相当于下一条线的起点
                                enumWay = enumCrossWay.enumNone;
                            }
                            else if (enumWay == enumCrossWay.enumMixOut)
                            {
                                //Line2D b2 = new Line2D(p, i + 1);
                                //if (GetOffCourse(b2) < Math.PI)
                                //    enumWay = enumCrossWay.enumNone;

                                //相交于该线的终点,即相当于下一条线的起点
                                enumWay = enumCrossWay.enumNone;
                            }
                            else
                                return i;
                        }
                    }
                    enumWay = enumCrossWay.enumNone;
                    pointCross = new Point2D();
                    return -1;
                }

                /// <summary>
                /// 两线段相交测试
                /// </summary>
                /// <param name="b"></param>
                /// <param name="pointCross"></param>
                /// <returns></returns>
                public enumCrossWay CrossTest(Line2D b, out Point2D pointCross)
                {
                    double degSub = Math.Abs(this.deg - b.deg);
                    if (degSub == 0 || degSub == Math.PI)
                    {
                        //平行线
                        if (pointB.InLine(b))
                        {
                            pointCross = new Point2D(pointB.name, pointB.x, pointB.y, pointB.deg);
                            if (pointB.Equal(b.pointB))
                                return enumCrossWay.enumMix2;
                            else if (GetOffCourse(b) == 0)
                            {
                                if (pointB.Equal(b.pointA))
                                    return enumCrossWay.enumMix1;
                                else
                                    return enumCrossWay.enumMixIn;
                            }
                            else
                            {
                                //反向平行(不考虑超越起点)
                                pointCross = new Point2D(b.pointB.name, b.pointB.x, b.pointB.y, b.pointB.deg);
                                return enumCrossWay.enumMixIn;
                            }
                        }
                        else if (pointB.InLineR(b))
                        {
                            pointCross = new Point2D(pointB.name, pointB.x, pointB.y, pointB.deg);
                            return enumCrossWay.enumMixOut;
                        }
                        else
                        {
                            //反向平行(不考虑超越起点)
                            pointCross = new Point2D();
                            return enumCrossWay.enumNone;
                        }
                    }
                    else
                    {
                        //两线相交
                        double yCross = 0;
                        double xCross = 0;
                        if (pointA.x == pointB.x || b.pointA.x == b.pointB.x)
                        {
                            //处理竖线
                            if (pointA.x == pointB.x)
                            {
                                //当前线条为竖线
                                xCross = pointA.x;
                                yCross = (b.pointB.y - b.pointA.y) * (pointB.x - b.pointA.x) / (b.pointB.x - b.pointA.x) + b.pointA.y;
                            }
                            else
                            {
                                //另一线条为竖线
                                xCross = b.pointA.x;
                                yCross = (pointB.y - pointA.y) * (b.pointB.x - pointA.x) / (pointB.x - pointA.x) + pointA.y;
                            }
                        }
                        else
                        {
                            //无竖线相交
                            double ka = (pointB.y - pointA.y) / (pointB.x - pointA.x);
                            double kb = (b.pointB.y - b.pointA.y) / (b.pointB.x - b.pointA.x);
                            xCross = ((ka * pointB.x - kb * b.pointB.x) - (pointB.y - b.pointB.y)) / (ka - kb);
                            yCross = ka * (xCross - pointB.x) + pointB.y;
                        }
                        if ((yCross - b.pointA.y) * (yCross - b.pointB.y) <= 0 &&
                            (yCross - pointA.y) * (yCross - pointB.y) <= 0 &&
                            (xCross - b.pointA.x) * (xCross - b.pointB.x) <= 0 &&
                            (xCross - pointA.x) * (xCross - pointB.x) <= 0)
                        {
                            if (yCross == b.pointB.y && xCross == b.pointB.x)
                            {
                                pointCross = new Point2D(b.pointB.name, b.pointB.x, b.pointB.y, b.pointB.deg);
                                return enumCrossWay.enumCross2;
                            }
                            else if (yCross == b.pointA.y && xCross == b.pointA.x)
                            {
                                pointCross = new Point2D(b.pointA.name, b.pointA.x, b.pointA.y, b.pointA.deg);
                                return enumCrossWay.enumCross1;
                            }
                            else
                            {
                                if (yCross == pointB.y && xCross == pointB.x)
                                {
                                    pointCross = new Point2D(pointB.name, pointB.x, pointB.y, pointB.deg);
                                    return enumCrossWay.enumCrossIn;
                                }
                                else if (yCross == pointA.y && xCross == pointA.x)
                                {
                                    pointCross = new Point2D(pointA.name, pointA.x, pointA.y, pointA.deg);
                                    return enumCrossWay.enumCrossIn;
                                }
                                else
                                {
                                    pointCross = new Point2D("*", xCross, yCross, 0);
                                    return enumCrossWay.enumCrossIn;
                                }
                            }
                        }
                        pointCross = new Point2D();
                        return enumCrossWay.enumNone;
                    }
                }

                #endregion
            }

            /// <summary>
            /// 多边形(点集以逆时针方式提供并存储,线段不得存在交叉)
            /// </summary>
            public class Polygon2D : IEnumerable
            {

                /// <summary>
                /// 逆时针的点序
                /// </summary>
                private List<Point2D> data;

                public Polygon2D(List<Point2D> A)
                {
                    data = Copy(A);
                }

                public Polygon2D(List<Point2D> A, bool bAutoCenter, bool bRename)
                {
                    data = Copy(A, bAutoCenter, bRename);
                }

                public List<Point2D> ToList()
                {
                    return data;
                }

                #region 枚举相关代码

                public void Clear()
                {
                    data.Clear();
                }

                public int Count
                {
                    get
                    {
                        return data.Count;
                    }
                }

                public Point2D this[int nIndex]
                {
                    get
                    {
                        if (nIndex >= 0 && nIndex < data.Count)
                            return data[nIndex] as Point2D;
                        else
                            return null;
                    }
                    set
                    {
                        if (nIndex >= 0 && nIndex < data.Count)
                            data[nIndex] = value;
                    }
                }

                public IEnumerator GetEnumerator()
                {
                    foreach (object obj in data) yield return (Point2D)obj;
                }

                #endregion

                #region 排序

                /// <summary>
                /// 将对象A,以左下角为起点复制至结果集
                /// </summary>
                /// <param name="A"></param>
                /// <returns></returns>
                public List<Point2D> Copy(List<Point2D> A)
                {
                    return Copy(A, true, false);
                }

                public List<Point2D> Copy(List<Point2D> A, bool bAutoCenter, bool bRename)
                {
                    int nMinIndex = GetMinIndex(A);
                    bool bFirst = true;
                    double dDegLast = 0;
                    Point2D pointLast = null;
                    List<Point2D> P = new List<Point2D>();
                    for (int i = nMinIndex; i < nMinIndex + A.Count; i++)
                    {
                        int nIndex = i % A.Count;
                        Point2D p = A[nIndex];
                        if (bFirst)
                        {
                            bFirst = false;
                            pointLast = A[(i - 1 + A.Count) % A.Count];
                        }

                        double dDeg = (Math.Atan2(p.y - pointLast.y, p.x - pointLast.x) + Math.PI * 2) % (Math.PI * 2);
                        P.Add(new Point2D(bRename ? (i + 1 - nMinIndex).ToString() : p.name, p.x, p.y, dDeg));

                        dDegLast = p.Angle();
                        pointLast = p;
                    }

                    if (bAutoCenter)
                        AutoCenter(ref P);
                    return P;
                }

                /// <summary>
                /// 求Y最小,X最小的点(左下解)
                /// </summary>
                /// <param name="p"></param>
                /// <returns></returns>
                public int GetMinIndex(List<Point2D> p)
                {
                    if (p.Count == 0)
                        return -1;
                    else
                    {
                        int nIndex = 0;
                        Point2D minPoint = p[0];

                        for (int i = 1; i < p.Count; i++)
                        {
                            if (p[i].y < minPoint.y || p[i].y == minPoint.y && p[i].x < minPoint.x)
                            {
                                nIndex = i;
                                minPoint = p[i];
                            }
                        }
                        return nIndex;
                    }
                }

                #endregion

                #region 解析

                /// <summary>
                /// 按1,2;3,4...格式解析成坐标序列
                /// </summary>
                /// <param name="strText"></param>
                /// <returns></returns>
                public static List<Point2D> Parse(string strText)
                {
                    List<Point2D> list = new List<Point2D>();
                    string[] strRows = strText.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                    int nIndex = 0;
                    foreach (string strRow in strRows)
                    {
                        string[] strCols = strRow.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                        if (strCols.Length == 2)
                        {
                            nIndex++;
                            Point2D p = new Point2D(nIndex.ToString(), double.Parse(strCols[0]), double.Parse(strCols[1]));
                            list.Add(p);
                        }
                    }
                    return list;
                }

                #endregion

                #region 计算点是否在多边形内

                public bool InPolygon(Point2D p)
                {
                    //相交类型:
                    //0:中间相交
                    //1:上端点相交
                    //2:下端点相交
                    int nCrossFlag = 0;

                    int nCount = 0;
                    for (int i = 0; i < data.Count; i++)
                    {
                        Point2D p1 = data[i];
                        Point2D p2 = data[(i + 1) % data.Count];

                        if (p.InLine(p1, p2))
                            return true;
                        else if (p1.y != p2.y)
                        {
                            //水平线同时与点不相交,该线可以忽略处理
                            if (!(p1.y < p.y && p2.y < p.y || p1.y > p.y && p2.y > p.y))
                            {
                                double x = (p.y - p2.y) * (p1.x - p2.x) / (p1.y - p2.y) + p2.x;
                                if (x >= p.x)
                                {
                                    //处理与线条的端点相交
                                    if (p.y == p1.y || p.y == p2.y)
                                    {
                                        int nCrossFlagCur = 0;
                                        if (p.y == p1.y && p1.y > p2.y || p.y == p2.y && p2.y > p1.y)
                                        {
                                            //上端点相交
                                            nCrossFlagCur = 1;
                                        }
                                        else if (p.y == p1.y && p1.y < p2.y || p.y == p2.y && p2.y < p1.y)
                                        {
                                            //下端点相交
                                            nCrossFlagCur = 2;
                                        }
                                        if (nCrossFlag == 0)
                                            nCrossFlag = nCrossFlagCur;
                                        else
                                        {
                                            if (nCrossFlag != nCrossFlagCur)
                                                nCount++;
                                            nCrossFlag = 0;
                                        }
                                    }
                                    else
                                    {
                                        nCount++;
                                    }
                                }
                            }
                        }
                    }

                    return nCount % 2 == 1;
                }
                #endregion

                #region 计算线的偏离方向

                /// <summary>
                /// 求指定一点,线的偏离方向
                /// </summary>
                /// <param name="nIndex"></param>
                /// <param name="bForward">向前或向后</param>
                /// <returns>0~pi:左拐,pi~2pi:右拐</returns>
                public double GetOffCourse(int nIndex)
                {
                    return GetOffCourse(nIndex, true);
                }

                public double GetOffCourse(int nIndex, bool bForward)
                {
                    Point2D pCur = data[nIndex];
                    int nPreId = (bForward ? (nIndex - 1 + data.Count) : (nIndex + 1)) % data.Count;
                    Point2D pPre = data[nPreId];
                    int nNextId = (bForward ? (nIndex + 1) : (nIndex - 1 + data.Count)) % data.Count;
                    Point2D pNext = data[nNextId];

                    double dAngle1 = Math.Atan2(pCur.y - pPre.y, pCur.x - pPre.x);
                    double dAngle2 = Math.Atan2(pNext.y - pCur.y, pNext.x - pCur.x);

                    return (dAngle2 - dAngle1 + Math.PI * 2) % (Math.PI * 2);
                }

                public double GetOffCourse(Point2D pCur, Point2D pPre, Point2D pNext)
                {
                    double dAngle1 = Math.Atan2(pCur.y - pPre.y, pCur.x - pPre.x);
                    double dAngle2 = Math.Atan2(pNext.y - pCur.y, pNext.x - pCur.x);

                    return (dAngle2 - dAngle1 + Math.PI * 2) % (Math.PI * 2);
                }

                #endregion

                #region 输出一个凸多边形

                public List<Point2D> Pop()
                {
                    List<Point2D> listOut = new List<Point2D>();
                    if (data.Count == 0)
                    {
                        return new List<Point2D>();
                    }
                    int nStartPos = 0;
                    double dOC0 = GetOffCourse(nStartPos);
                    if (dOC0 > Math.PI)
                    {
                        for (int i = nStartPos; i < data.Count - 1; i++)
                        {
                            double dOCi = GetOffCourse(i + 1);
                            if (dOCi < Math.PI)
                                nStartPos = i;
                                break;
                        }
                    }
                    else
                    {
                        for (int i = data.Count - 1; i > 0; i--)
                        {
                            double dOCi = GetOffCourse(i);
                            if (dOCi > Math.PI)
                            {
                                nStartPos = i;
                                break;
                            }
                        }
                    }
                    int nStopPos = nStartPos;
                    for(int i = 1;i < data.Count;i ++)
                    {
                        double dOCi = GetOffCourse(i);
                        if(dOCi > Math.PI)
                        {
                            nStopPos = i;
                            break;
                        }
                    }

                    double dOCs = GetOffCourse(nStopPos);
                    if(nStopPos == nStartPos && dOCs < Math.PI)
                    {
                        foreach (Point2D point in data) listOut.Add(new Point2D(point.name, point.x, point.y, point.deg));
                        data = new List<Point2D>();
                        return listOut;
                    }
                    else
                    {
                        //求(nStopPos - 1 , nStopPos)射线相交的线段,以线段的终点为该闭合线
                        if(nStopPos <= nStartPos)
                            nStopPos += data.Count;

                        Line2D lineRef = new Line2D (data[(nStopPos - 1 + data.Count) % data.Count] , data[nStopPos % data.Count]);

                        while(nStartPos < nStopPos)
                        {
                            if ((nStopPos - nStartPos) % data.Count == 0)
                                nStartPos++;
                            else
                            {
                                Line2D lineMid = new Line2D(data[nStopPos % data.Count], data[nStartPos % data.Count]);
                                if (lineRef.GetOffCourse(lineMid) < Math.PI)
                                    break;
                                else
                                    nStartPos++;
                            }
                        }
                        lineRef = new Line2D(data[nStartPos % data.Count], data[(nStartPos + 1) % data.Count]);
                        while (nStartPos < nStopPos)
                        {
                            Line2D lineMid = new Line2D(data[nStopPos % data.Count], data[nStartPos % data.Count]);
                            if (lineMid.GetOffCourse(lineRef) < Math.PI)
                                break;
                            else
                                nStopPos--;
                        }
                        return Pop(nStartPos, nStopPos);
                    }
                }

                /// <summary>
                /// 将指定区间的点组成一个多边形返回,同时将除首尾两点以外的点移除
                /// </summary>
                /// <param name="nStart"></param>
                /// <param name="nStop"></param>
                /// <returns></returns>
                public List<Point2D> Pop(int nStart, int nStop)
                {
                    List<Point2D> list = new List<Point2D>();
                    Line2D lineRef = new Line2D(data[nStop % data.Count], data[nStart % data.Count]);
                    for (int i = nStart; i <= nStop; i++)
                    {
                        if (i == nStart)
                        {
                            //判断起点位置夹角是还为180度
                            Line2D lineNext = new Line2D(data[nStart % data.Count], data[(nStart + 1) % data.Count]);
                            if (lineRef.GetOffCourse(lineNext) == 0)
                                continue;
                        }
                        else if (i == nStop)
                        {
                            //判断终点位置夹角是还为180度
                            Line2D linePre = new Line2D(data[(nStop - 1 + data.Count) % data.Count], data[nStop % data.Count]);
                            if (linePre.GetOffCourse(lineRef) == 0)
                                continue;
                        }
                        int nIndex = i % data.Count;
                        list.Add(new Point2D(data[nIndex].name, data[nIndex].x, data[nIndex].y, data[nIndex].deg));
                    }

                    Line2D linePre2 = new Line2D(data[(nStop + 1) % data.Count], data[nStop % data.Count]);
                    Line2D lineNext2 = new Line2D(data[nStart % data.Count], data[(nStart - 1 + data.Count) % data.Count]);
                    //判断起点位置夹角是还为180度
                    if (lineRef.GetOffCourse(lineNext2) == 0)
                    {
                        nStart = nStart == 0 ? (nStart - 1 + data.Count) : (nStart - 1);
                    }
                    //判断终点位置夹角是还为180度
                    if (linePre2.GetOffCourse(lineRef) == 0)
                    {
                        nStop++;
                    }

                    int nCount = data.Count;
                    nStart %= data.Count;
                    nStop %= data.Count;
                    if (nStop > nStart)
                    {
                        for (int i = nStop - 1; i > nStart; i--)
                        {
                            int nIndex = i % nCount;
                            data.RemoveAt(nIndex);
                        }
                    }
                    else
                    {
                        for (int i = nCount - 1; i > nStart; i--)
                        {
                            data.RemoveAt(i);
                        }
                        for (int i = nStop - 1; i >= 0; i--)
                        {
                            data.RemoveAt(i);
                        }
                    }
                    return list;
                }

                #endregion

                /// <summary>
                /// 拆分多边形为若干个凸多边形
                /// </summary>
                /// <returns></returns>
                public List<Polygon2D> Split()
                {
                    List<Polygon2D> ps = new List<Polygon2D>();
                    List<Point2D> listResult = Pop();
                    while (listResult.Count > 0)
                    {
                        ps.Add(new Polygon2D(listResult, false, false));
                        listResult = Pop();
                    }
                    if (data.Count > 0)
                    {
                        ps.Add(this);
                        throw new Exception("Polygon Split Error");
                    }
                    return ps;
                }

                #region 居中操作

                /// <summary>
                /// 获取多边形的中心点(求坐标的均值)
                /// </summary>
                /// <param name="p"></param>
                /// <returns></returns>
                public Point2D GetCenter(List<Point2D> p)
                {
                    if (p.Count > 0)
                    {
                        double dXSum = 0;
                        double dYSum = 0;
                        foreach (Point2D point in p)
                        {
                            dXSum += point.x;
                            dYSum += point.y;
                        }

                        return new Point2D("", dXSum / p.Count, dYSum / p.Count);
                    }
                    else
                        return new Point2D("", 0, 0);
                }

                /// <summary>
                /// 自动以中心点为原点
                /// </summary>
                /// <param name="p"></param>
                public void AutoCenter(ref List<Point2D> p)
                {
                    Point2D center = GetCenter(p);
                    Move(ref p, center);
                }

                /// <summary>
                /// 偏移一个坐标(坐标-偏移值)
                /// </summary>
                /// <param name="p"></param>
                /// <param name="offset"></param>
                public void Move(ref List<Point2D> p, Point2D offset)
                {
                    foreach (Point2D point in p)
                    {
                        point.x -= offset.x;
                        point.y -= offset.y;
                    }
                }

                /// <summary>
                /// 获取多边形的中心点(求坐标的均值)
                /// </summary>
                /// <param name="p"></param>
                /// <returns></returns>
                public Point2D GetCenter()
                {
                    if (data.Count > 0)
                    {
                        double dXSum = 0;
                        double dYSum = 0;
                        foreach (Point2D point in data)
                        {
                            dXSum += point.x;
                            dYSum += point.y;
                        }

                        return new Point2D("", dXSum / data.Count, dYSum / data.Count);
                    }
                    else
                        return new Point2D("", 0, 0);
                }

                /// <summary>
                /// 自动以中心点为原点
                /// </summary>
                /// <param name="p"></param>
                public void AutoCenter()
                {
                    Point2D center = GetCenter();
                    Move(center);
                }

                /// <summary>
                /// 偏移一个坐标(坐标-偏移值)
                /// </summary>
                /// <param name="p"></param>
                /// <param name="offset"></param>
                public void Move(Point2D offset)
                {
                    foreach (Point2D point in data)
                    {
                        point.x -= offset.x;
                        point.y -= offset.y;
                    }
                }

                #endregion

                #region 输出多边形

                /// <summary>
                /// 输出Minkowski和
                /// </summary>
                /// <returns></returns>
                public override string ToString()
                {
                    StringBuilder sb = new StringBuilder();
                    bool bFirst = true;
                    foreach (Point2D p in data)
                    {
                        if (bFirst)
                        {
                            bFirst = false;
                            sb.AppendFormat("{0},{1}", p.x, p.y);
                        }
                        else
                            sb.AppendFormat(";{0},{1}", p.x, p.y);
                    }

                    return sb.ToString();
                }

                /// <summary>
                /// 画一个多边形
                /// </summary>
                /// <param name="g"></param>
                /// <param name="org">原点</param>
                /// <param name="pen">画笔</param>
                /// <param name="nTimes">放大倍数</param>
                public void DrawBox(Graphics g, System.Drawing.Point org, Pen pen, int nTimes)
                {
                    DrawBox(g, org, pen, nTimes, false);
                }

                public void DrawBox(Graphics g, System.Drawing.Point org, Pen pen, int nTimes , bool bWithPoint)
                {
                    for (int i = 0; i < data.Count; i++)
                    {
                        System.Drawing.Point ps = new System.Drawing.Point(org.X + (int)(data[i].x * nTimes), org.Y - (int)(data[i].y * nTimes));
                        System.Drawing.Point pe = new System.Drawing.Point(org.X + (int)(data[(i + 1) % data.Count].x * nTimes), org.Y - (int)(data[(i + 1) % data.Count].y * nTimes));
                        g.DrawLine(pen, ps, pe);
                        g.DrawString(data[i].name, SystemFonts.DefaultFont, Brushes.Black, ps);
                        if (bWithPoint)
                        {
                            DrawPointStatus(g, org, data[i], nTimes);
                        }
                    }
                }

                /// <summary>
                /// 画点在多边形的位置状态(绿色在内,红色在外)
                /// </summary>
                /// <param name="g"></param>
                /// <param name="p"></param>
                public void DrawPointStatus(Graphics g, System.Drawing.Point org, Point2D p, int nTimes)
                {
                    Point2D pp = new Point2D("", p.x, p.y);
                    Pen pen = Pens.Black;
                    Brush brush = Brushes.Black;
                    if (!InPolygon(pp))
                    {
                        pen = Pens.Red;
                        brush = Brushes.Red;
                    }
                    int nSize = 6;

                    Point pointStart = new Point((int)(org.X + p.x * nTimes - nSize / 2), (int)(org.Y - p.y * nTimes - nSize / 2));

                    g.DrawArc(pen, new Rectangle(pointStart, new Size(nSize, nSize)), 0, 360);
                    g.FillPie(brush, new Rectangle(pointStart, new Size(nSize, nSize)), 0, 360);
                }

                #endregion
            }

            private Polygon2D P;
            private Polygon2D Q;
            private Polygon2D R;

            public Polygon2D SumResult
            {
                get
                {
                    return R;
                }
            }

            public MinkowskiSum(List<Point2D> A, List<Point2D> B)
            {
                P = new Polygon2D(A,false,true);
                Q = new Polygon2D(B,false,true);
            }

            public MinkowskiSum(List<Point2D> A, List<Point2D> B, bool bBCenter)
            {
                P = new Polygon2D(A, false, true);
                Q = new Polygon2D(B, bBCenter, true);
            }

            /// <summary>
            /// 求Minkowski和
            /// </summary>
            /// <returns></returns>
            public bool MakeSum()
            {
                List<Point2D> r;
                if (SimpleSum(P, Q, out r))
                {
                    R = new Polygon2D (r, false , false);
                    return true;
                }
                else
                    return false;
            }

            /// <summary>
            /// 分解P后再依次与Q求Minkowski和,然后再合并(目前算法不合理,用的是求Minkowski和)
            /// </summary>
            /// <returns></returns>
            public bool MakeSumSplit()
            {
                Polygon2D PCopy = new Polygon2D(P.ToList(), false, false);
                List<Polygon2D> ps = PCopy.Split();

                Polygon2D QCopy = new Polygon2D(Q.ToList(), false, false);
                List<Polygon2D> qs = QCopy.Split();

                Polygon2D pSum = null;
                foreach (Polygon2D p in ps)
                {
                    Polygon2D r;
                    if (SimpleSum(p, Q, out r))
                    {
                        if (pSum == null)
                            pSum = r;
                        else
                        {
                            Polygon2D[] P2 = new Polygon2D[]{
                                pSum ,
                                r
                            };
                            Polygon2D r2;
                            Combine(P2, out r2);
                            pSum = r2;
                        }
                    }
                }
                R = pSum;
                return true;
            }

            /// <summary>
            /// 求两凸变形的Minkowski和
            /// </summary>
            /// <param name="P"></param>
            /// <param name="Q"></param>
            /// <param name="R"></param>
            /// <returns></returns>
            public bool SimpleSum(List<Point2D> P, List<Point2D> Q, out List<Point2D> R)
            {
                return SimpleSum(new Polygon2D(P, false, false), new Polygon2D(Q, false, false), out R);
            }

            public bool SimpleSum(Polygon2D P, Polygon2D Q, out Polygon2D R)
            {
                List<Point2D> r;
                bool bRet = SimpleSum(P, Q, out r);
                R = new Polygon2D(r, false, false);
                return bRet;
            }

            public bool SimpleSum(Polygon2D P, Polygon2D Q, out List<Point2D> R)
            {
                R = new List<Point2D>();
                if (P.Count >= 3 && Q.Count >= 3)
                {
                    int pi = 0;
                    int qi = 0;
                    while (pi < P.Count || qi < Q.Count)
                    {
                        int pii = pi % P.Count;
                        int qii = qi % Q.Count;

                        R.Add(new Point2D(string.Format("{0}-{1}", P[pii].name, Q[qii].name), P[pii].x + Q[qii].x, P[pii].y + Q[qii].y));
                        if (pi == P.Count && qi < Q.Count)
                            qi++;
                        else if (pi < P.Count && qi == Q.Count)
                            pi++;
                        else if (P[(pi + 1)%P.Count].deg < Q[(qi + 1)%Q.Count].deg)
                            pi++;
                        else if (P[(pi + 1)%P.Count].deg > Q[(qi + 1)%Q.Count].deg)
                            qi++;
                        else
                        {
                            pi++;
                            qi++;
                        }
                    }
                    //R.Add(new Point2D(string.Format("{0}-{1}", P[pi].name, Q[qi].name), P[pi].x + Q[qi].x, P[pi].y + Q[qi].y));
                    R = new Polygon2D(R, false, false).ToList();
                    return true;
                }
                else
                    return false;
            }

            public bool Combine(Polygon2D[] P, out Polygon2D R)
            {
                List<Point2D> r;
                bool bRet = Combine(P, out r);
                R = new Polygon2D(r, false, false);
                return bRet;
            }

            /// <summary>
            /// 合同并两多边形
            /// </summary>
            /// <param name="P"></param>
            /// <param name="R"></param>
            /// <returns></returns>
            public bool Combine(Polygon2D[] P, out List<Point2D> R)
            {
                R = new List<Point2D>();
                if (P.Length != 2)
                {
                    return false;
                }
                if (P[0].Count >= 3 && P[1].Count >= 3)
                {
                    //设定开始计算的多边形
                    int pIndex = (P[0][0].y < P[1][0].y || P[0][0].y == P[1][0].y && P[0][0].x <= P[1][0].x) ? 0 : 1;
                    int pIndexCopy = pIndex;
                    int[] nPos = new int[] { 0, 0 };
                    int[] nStartOffset = new int[] { 0, 0 };
                    Point2D pointCross = P[pIndex][nPos[pIndex]];
                    Point2D pointLast = null;
                    bool bFirstCross = true;
                    while (nPos[pIndex] < P[pIndex].Count + nStartOffset[pIndex])
                    {
                        if (pointLast == null || pointLast != null && !pointCross.Equal(pointLast))
                        {
                            R.Add(pointCross);
                        }
                        else
                        {
                            Console.WriteLine(pointCross);
                        }

                        pointLast = pointCross;

                        Line2D.enumCrossWay enumWay;
                        Line2D lineA = new Line2D(pointCross, P[pIndex][(nPos[pIndex] + 1) % P[pIndex].Count]);
                        int nNextIndex = lineA.CrossSearch(P[1 - pIndex], nPos[1 - pIndex], out enumWay, out pointCross);
                        if (nNextIndex < 0)
                        {
                            nPos[pIndex]++;
                            pointCross = P[pIndex][nPos[pIndex] % P[pIndex].Count];
                        }
                        else
                        {
                            if (bFirstCross)
                            {
                                //解决第一次相交的点之前的线段被忽略计算
                                bFirstCross = false;
                                nStartOffset[1 - pIndex] = nNextIndex == 0 ? 0 : (nNextIndex + 1);
                            }
                            if (enumWay == Line2D.enumCrossWay.enumCross1 ||
                            enumWay == Line2D.enumCrossWay.enumCrossIn)
                            {
                                //相交于起点或中间点(左拐的情况已经在CrossSearch中规避了)
                                pIndex = 1 - pIndex;
                                nPos[pIndex] = nNextIndex;
                            }
                            else if (enumWay == Line2D.enumCrossWay.enumCross2)
                            {
                                //相交于终点(相当于下一线段的起点,CrossSearch中规避了)
                            }
                            else if (enumWay == Line2D.enumCrossWay.enumMixIn)
                            {
                                Line2D lineB = new Line2D(P[1 - pIndex], nNextIndex + 1);
                                if (lineA.GetOffCourse(lineB) > Math.PI)
                                {
                                    //另一条线右拐
                                    nPos[pIndex]++;
                                    pIndex = 1 - pIndex;
                                    nPos[pIndex] = nNextIndex + 1;
                                    pointCross = P[pIndex][nPos[pIndex]];
                                }
                                else
                                {
                                    nPos[pIndex]++;
                                }
                            }
                            else if (enumWay == Line2D.enumCrossWay.enumMix1)
                            {
                                Line2D lineB = new Line2D(P[pIndex], (nPos[pIndex] + 1) % P[pIndex].Count);
                                if (lineA.GetOffCourse(lineB) > Math.PI)
                                {
                                    //当前线段右拐
                                    nPos[pIndex]++;
                                }
                                else
                                {
                                    nPos[pIndex]++;
                                    pIndex = 1 - pIndex;
                                    nPos[pIndex] = nNextIndex + 1;
                                    pointCross = P[pIndex][nPos[pIndex]];
                                }
                            }
                            else if (enumWay == Line2D.enumCrossWay.enumMix2)
                            {
                                nPos[pIndex]++;
                                nPos[1 - pIndex] = nNextIndex + 1;
                            }
                            else if (enumWay == Line2D.enumCrossWay.enumMixOut)
                            {
                                //左拐的情况已经在CrossSearch中规避了
                                pIndex = 1 - pIndex;
                                nPos[pIndex] = nNextIndex + 1;
                            }
                        }
                    }
                    return true;

                }
                else if (P[0].Count >= 3)
                {
                    R = P[0].ToList();
                    return true;
                }
                else if (P[1].Count >= 3)
                {
                    R = P[1].ToList();
                    return true;
                }
                else
                {
                    R = new List<Point2D>();
                    return false;
                }
            }

            #region 图形输出

            public Image DrawSplit(System.Drawing.Point org, Size size)
            {
                Bitmap bm = new Bitmap(size.Width, size.Height);
                Graphics g = Graphics.FromImage(bm);
                g.FillRectangle(Brushes.White, new Rectangle(new Point(0, 0), size));
                DrawCoordinate(g, size, org);

                DrawSplit(g, org, size , 100);
                return bm;

            }

            public void DrawSplit(Graphics g, System.Drawing.Point org, Size size, int nTimes)
            {
                Q.DrawBox(g, org, Pens.Blue, nTimes);

                Polygon2D PCopy = new Polygon2D(P.ToList(), false, false);
                List<Polygon2D> ps = PCopy.Split();

                Polygon2D QCopy = new Polygon2D(Q.ToList(), false, false);
                List<Polygon2D> qs = QCopy.Split();

                Polygon2D pSum = null;
                foreach (Polygon2D p in ps)
                {
                    p.DrawBox(g, org, Pens.LightGreen, nTimes);

                    foreach (Polygon2D q in qs)
                    {
                        q.DrawBox(g, org, Pens.Blue, nTimes);
                        Polygon2D r;
                        if (SimpleSum(p, q, out r))
                        {
                            r.DrawBox(g, org, Pens.Red, nTimes);
                            if (pSum == null)
                                pSum = r;
                            else
                            {
                                Polygon2D[] P2 = new Polygon2D[]{
                                        pSum ,
                                        r
                                    };
                                Polygon2D r2;
                                Combine(P2, out r2);
                                pSum = r2;
                            }
                        }
                    }
                }
                pSum.DrawBox(g, org, Pens.Blue, nTimes, true);
            }

            /// <summary>
            /// 将三个多边形画到画面上
            /// </summary>
            /// <param name="org">画布原点</param>
            /// <param name="size">画布尺寸</param>
            /// <returns></returns>
            public Image DrawImage(System.Drawing.Point org, Size size)
            {
                Bitmap bm = new Bitmap(size.Width, size.Height);
                Graphics g = Graphics.FromImage(bm);
                g.FillRectangle(Brushes.White, new Rectangle(new Point(0, 0), size));

                DrawCoordinate(g, size , org);

                int nTimes = 60;
                P.DrawBox(g, org, Pens.LightGreen, nTimes);
                Q.DrawBox(g, org, Pens.Blue, nTimes);
                R.DrawBox(g, org, Pens.Red, nTimes);
                
                DrawSplit(g, org, size, nTimes);
                
                return bm;
            }

            /// <summary>
            /// 画坐标线
            /// </summary>
            /// <param name="g"></param>
            /// <param name="size">画布尺寸</param>
            /// <param name="org">原点</param>
            public void DrawCoordinate(Graphics g, Size size, System.Drawing.Point org)
            {
                g.DrawLine(Pens.DarkSlateGray, new System.Drawing.Point(0, org.Y), new System.Drawing.Point(size.Width, org.Y));
                g.DrawLine(Pens.DarkSlateGray, new System.Drawing.Point(org.X, 0), new System.Drawing.Point(org.X, size.Height));

                Pen pen = new Pen(Color.DarkSlateGray, 3);
                for (int i = 1; i < size.Width / 2 / 10; i++)
                {
                    bool bTen = i % 10 == 0;
                    bool bFive = i % 5 == 0;
                    int nHeight = bTen ? 20 : (bFive ? 10 : 5);
                    g.DrawLine(pen, new System.Drawing.Point(org.X + i * 10, org.Y), new System.Drawing.Point(org.X + i * 10, org.Y - nHeight));
                    g.DrawLine(pen, new System.Drawing.Point(org.X - i * 10, org.Y), new System.Drawing.Point(org.X - i * 10, org.Y - nHeight));
                }
                for (int i = 1; i < size.Height / 2 / 10; i++)
                {
                    bool bTen = i % 10 == 0;
                    bool bFive = i % 5 == 0;
                    int nHeight = bTen ? 20 : (bFive ? 10 : 5);
                    g.DrawLine(pen, new System.Drawing.Point(org.X, org.Y + i * 10), new System.Drawing.Point(org.X + nHeight, org.Y + i * 10));
                    g.DrawLine(pen, new System.Drawing.Point(org.X, org.Y - i * 10), new System.Drawing.Point(org.X + nHeight, org.Y - i * 10));
                }
            }

            #endregion

            #region 调用输出
            /// <summary>
            /// 直接输出图形
            /// </summary>
            /// <param name="p">逆序点集</param>
            /// <param name="q">逆序点集</param>
            /// <returns></returns>
            public static Image MinkImage(string p, string q)
            {
                List<MinkowskiSum.Point2D> pp = new List<MinkowskiSum.Point2D>();

                //string strText1 = "2,2;0,2;-2,1;-2,-2;2,-2";
                string strText1 = "2,2;1,2;1,0;0,0;0,2;-2,1;-3,-3;1,-2;1,-1;2,-1";
                //string strText1 = "2,2;1,2;1,0;0,0;0,2;-2,1;-2,-2;2,-1";
                pp = MinkowskiSum.Polygon2D.Parse(p ?? strText1);

                List<MinkowskiSum.Point2D> qq = new List<MinkowskiSum.Point2D>();

                //string strText2 = "-0.5,1;-0.5,-0.5;0.5,-0.5";
                //string strText2 = "0.5,1;0.5,-0.5;1.5,-0.5";
                string strText2 = "1.5,1;1,0;0.5,1;0.5,-0.5;1.5,-0.5";
                qq = MinkowskiSum.Polygon2D.Parse(q ?? strText2);

                //参数true表示对qq进行中心原点化
                MinkowskiSum mink = new MinkowskiSum(pp, qq, true);

                Size size = new Size(800, 800);
                Point point = new Point(size.Width / 2, size.Height / 2);
                return mink.DrawSplit(point, size);
            }

            /// <summary>
            /// 直接输出结果点集(格式:x1,y1;x2,y2...)
            /// </summary>
            /// <param name="p">逆序点集</param>
            /// <param name="q">逆序点集</param>
            /// <param name="strResult">结果点集(格式:x1,y1;x2,y2...)</param>
            /// <returns></returns>
            public static bool MinkResult(string p, string q, out string strResult)
            {
                //string strText1 = "2,2;0,2;-2,1;-2,-2;2,-2";
                string strText1 = "2,2;1,2;1,0;0,0;0,2;-2,1;-3,-3;1,-2;1,-1;2,-1";
                //string strText1 = "2,2;1,2;1,0;0,0;0,2;-2,1;-2,-2;2,-1";

                List<MinkowskiSum.Point2D> pp = new List<MinkowskiSum.Point2D>();
                pp = MinkowskiSum.Polygon2D.Parse(p ?? strText1);
                
                //string strText2 = "-0.5,1;-0.5,-0.5;0.5,-0.5";
                //string strText2 = "0.5,1;0.5,-0.5;1.5,-0.5";
                string strText2 = "1.5,1;1,0;0.5,1;0.5,-0.5;1.5,-0.5";

                List<MinkowskiSum.Point2D> qq = new List<MinkowskiSum.Point2D>();
                qq = MinkowskiSum.Polygon2D.Parse(q ?? strText2);

                MinkowskiSum mink = new MinkowskiSum(pp, qq);
                bool bRet = mink.MakeSumSplit();
                strResult = bRet ? mink.SumResult.ToString() : "";
                return bRet;
            }
            #endregion
        }
    }

    展开全文
  • Holder不等式 Minkowski不等式

    万次阅读 2019-09-04 11:03:23
    下面的Minkowski不等式证明了 p p p 范数的三角不等式。 首先,我们需要一个小小的等式。如果 1 / p + 1 / q = 1 1/p+1/q=1 1 / p + 1 / q = 1 那么 ( p − 1 ) q = ( p − 1 ) ⋅ 1 1 − 1 / p = p 。 (p-1)q=...

    著名柯西-施瓦茨不等式是证明二范数三角不等式的重要工具。Holder不等式是柯西不等式的推广,它是证明 p p p范数三角不等式的重要工具。

    定义 R n \mathbb{R}^n Rn空间上的 p p p范数 ∣ ⋅ ∣ p |\cdot|_p p定义为
    ∣ x ∣ p = ( ∑ i = 1 n ∣ x i ∣ p ) 1 / p 。 |x|_p=(\sum_{i=1}^n |x_i|^p)^{1/p}。 xp=(i=1nxip)1/p
    这里的 p ≥ 1 p\geq 1 p1是正实数, x = ( x 1 , x 2 , . . . , x n ) ∈ R n x=(x_1,x_2,...,x_n)\in\mathbb{R}^n x=(x1,x2,...,xn)Rn。特别地,对于 p = ∞ p=\infty p=定义
    ∣ x ∣ ∞ = max ⁡ 1 ≤ i ≤ n ∣ x i ∣ 。 |x|_{\infty}=\max_{1\leq i \leq n} |x_i|。 x=1inmaxxi

    p = 2 p=2 p=2时, ∣ ⋅ ∣ 2 |\cdot|_2 2就是我们的二范数。

    为了证明 p p p范数是一个范数,我们需要验证其是否满足三角不等式,也即是否有
    ∣ x + y ∣ p ≤ ∣ x ∣ p + ∣ y ∣ p |x+y|_p\leq |x|_p + |y|_p x+ypxp+yp
    对所有的 x , y ∈ R n x,y\in\mathbb{R}^n x,yRn成立。为了证明这个定理,我们需要Holder不等式。

    首先需要一个引理。

    引理 a λ b 1 − λ ≤ λ a + ( 1 − λ ) b a^{\lambda}b^{1-\lambda}\leq \lambda a + (1-\lambda)b aλb1λλa+(1λ)b这里的 a , b ≥ 0 , 0 ≤ λ ≤ 1 a,b\geq 0, 0\leq \lambda \leq 1 a,b0,0λ1

    证明 a a a b b b为0时显然成立,故只需证 a , b &gt; 0 a,b&gt;0 a,b>0的情况。由于 f ( x ) = ln ⁡ x f(x)=\ln x f(x)=lnx是关于 x x x的上凸函数,故对于任意的 a , b &gt; 0 , 0 ≤ λ ≤ 1 a,b&gt; 0, 0\leq \lambda \leq 1 a,b>0,0λ1
    f ( λ a + ( 1 − λ ) b ) ≥ λ f ( a ) + ( 1 − λ ) f ( b ) , f(\lambda a + (1-\lambda)b)\geq \lambda f(a) + (1-\lambda)f(b), f(λa+(1λ)b)λf(a)+(1λ)f(b)
    也即
    ln ⁡ ( λ a + ( 1 − λ ) b ) ≥ λ ln ⁡ a + ( 1 − λ ) ln ⁡ b 。 \ln (\lambda a + (1-\lambda)b) \geq \lambda \ln a + (1-\lambda)\ln b。 ln(λa+(1λ)b)λlna+(1λ)lnb
    上式两边求指数,便有题设的不等式成立。

    定理(Holder不等式) 对任意的 1 ≤ p , q ≤ ∞ , 1 / p + 1 / q = 1 1\leq p, q \leq \infty, 1/p+1/q=1 1p,q,1/p+1/q=1以及 x , y ∈ R n x,y\in\mathbb{R}^n x,yRn
    ∑ i = 1 n ∣ x i y i ∣ ≤ ∣ x ∣ p ∣ y ∣ q 。 \sum_{i=1}^n |x_iy_i|\leq |x|_p|y|_q。 i=1nxiyixpyq
    p = q = 2 p=q=2 p=q=2时,Holder不等式退化为柯西-施瓦茨不等式。

    证明 由上面的引理
    ∣ x i ∣ ∣ y i ∣ ∣ x ∣ p ∣ y ∣ q = ( ∣ x i ∣ p ∣ x ∣ p p ) 1 / p ( ∣ y i ∣ q ∣ y ∣ q q ) 1 / q ≤ 1 p ∣ x i ∣ p ∣ x ∣ p p + 1 q ∣ y i ∣ q ∣ y ∣ q q \frac{|x_i||y_i|}{|x|_p|y|_q}=(\frac{|x_i|^{p}}{|x|_p^p})^{1/p}(\frac{|y_i|^{q}}{|y|_q^q})^{1/q} \leq \frac{1}{p} \frac{|x_i|^{p}}{|x|_p^p} + \frac{1}{q}\frac{|y_i|^{q}}{|y|_q^q} xpyqxiyi=(xppxip)1/p(yqqyiq)1/qp1xppxip+q1yqqyiq
    不等式左右两边对 i i i求和便有
    1 ∣ x ∣ p ∣ y ∣ q ∑ i = 1 n ∣ x i ∣ ∣ y i ∣ ≤ 1 p ∣ x ∣ p p ∑ i = 1 n ∣ x i ∣ p + 1 q ∣ y ∣ q q ∑ i = 1 n ∣ y i ∣ q = 1 p + 1 q = 1 , \frac{1}{|x|_p|y|_q}\sum_{i=1}^n |x_i||y_i|\leq \frac{1}{p|x|_p^p} \sum_{i=1}^n |x_i|^p + \frac{1}{q|y|_q^q} \sum_{i=1}^n |y_i|^q = \frac{1}{p} + \frac{1}{q}=1, xpyq1i=1nxiyipxpp1i=1nxip+qyqq1i=1nyiq=p1+q1=1
    其中倒数第二个等号成立是因为 ∑ ∣ x i ∣ p = ∣ x ∣ p p \sum |x_i|^p = |x|_p^p xip=xpp ∑ ∣ y i ∣ q = ∣ y ∣ q q \sum |y_i|^q = |y|_q^q yiq=yqq。定理证毕。

    下面的Minkowski不等式证明了 p p p范数的三角不等式。

    首先,我们需要一个小小的等式。如果 1 / p + 1 / q = 1 1/p+1/q=1 1/p+1/q=1那么
    ( p − 1 ) q = ( p − 1 ) ⋅ 1 1 − 1 / p = p 。 (p-1)q=(p-1)\cdot \frac{1}{1-1/p}=p。 (p1)q=(p1)11/p1=p

    定理(Minkowski不等式) 对任意的 p ≥ 1 p\geq 1 p1以及 x , y ∈ R n x,y\in\mathbb{R}^n x,yRn
    ∣ x + y ∣ p ≤ ∣ x ∣ p + ∣ y ∣ p 。 |x+y|_p \leq |x|_p + |y|_p。 x+ypxp+yp
    证明 只需考虑 1 &lt; p &lt; ∞ 1&lt;p&lt;\infty 1<p<的情况, p = 1 p=1 p=1 ∞ \infty 的情形易证。当 1 &lt; p &lt; ∞ 1&lt;p&lt;\infty 1<p<时有
    ∣ x + y ∣ p p = ∑ i = 1 n ∣ x i + y i ∣ p = ∑ i = 1 n ∣ x i + y i ∣ p − 1 ∣ x i + y i ∣ ≤ ∑ i = 1 n ∣ x i + y i ∣ p − 1 ( ∣ x i ∣ + ∣ y i ∣ ) . |x+y|_p^p=\sum_{i=1}^n |x_i+y_i|^p=\sum_{i=1}^n |x_i+y_i|^{p-1}|x_i+y_i|\leq\sum_{i=1}^n |x_i+y_i|^{p-1}(|x_i|+|y_i|). x+ypp=i=1nxi+yip=i=1nxi+yip1xi+yii=1nxi+yip1(xi+yi).
    由Holder不等式
    ∑ i = 1 n ∣ x i + y i ∣ p − 1 ∣ x i ∣ ≤ ( ∑ i = 1 n ∣ x i + y i ∣ ( p − 1 ) q ) 1 / q ( ∑ i = 1 n ∣ x i ∣ p ) 1 / p = ( ∑ i = 1 n ∣ x i + y i ∣ ( p − 1 ) q ) 1 / q ∣ x ∣ p = ( ∑ i = 1 n ∣ x i + y i ∣ p ) 1 / q ∣ x ∣ p = ∣ x + y ∣ p p / q ∣ x ∣ p , \begin{array}{lll} \displaystyle\sum_{i=1}^n|x_i+y_i|^{p-1}|x_i| &amp;\leq&amp; \displaystyle\Big(\sum_{i=1}^n|x_i+y_i|^{(p-1)q}\Big)^{1/q}\Big(\sum_{i=1}^n|x_i|^{p}\Big)^{1/p} \\ &amp;=&amp;\displaystyle\Big(\sum_{i=1}^n|x_i+y_i|^{(p-1)q}\Big)^{1/q} |x|_p\\ &amp;=&amp;\displaystyle\Big(\sum_{i=1}^n|x_i+y_i|^{p}\Big)^{1/q} |x|_p\\ &amp;=&amp; |x+y|_p^{p/q}|x|_p, \end{array} i=1nxi+yip1xi===(i=1nxi+yi(p1)q)1/q(i=1nxip)1/p(i=1nxi+yi(p1)q)1/qxp(i=1nxi+yip)1/qxpx+ypp/qxp
    其中 1 / p + 1 / q = 1 1/p+1/q=1 1/p+1/q=1。同理还有
    ∑ i = 1 n ∣ x i + y i ∣ p − 1 ∣ y i ∣ ≤ ∣ x + y ∣ p p / q ∣ y ∣ p 。 \displaystyle\sum_{i=1}^n|x_i+y_i|^{p-1}|y_i| \leq |x+y|_p^{p/q}|y|_p。 i=1nxi+yip1yix+ypp/qyp

    结合上面的三个不等式有
    ∣ x + y ∣ p p ≤ ∣ x + y ∣ p p / q ( ∣ x ∣ p + ∣ y ∣ p ) 。 |x+y|_p^p \leq |x+y|_p^{p/q}(|x|_p+|y|_p)。 x+yppx+ypp/q(xp+yp)
    不等式两边同时乘 ∣ x + y ∣ p − p / q |x+y|_p^{-p/q} x+ypp/q便有Minkowski不等式成立。

    展开全文
  • 介绍了Hölder不等式和Minkowski不等式,并对其进行了证明。

    Hölder 不等式

      Let 1 < p , q < ∞ ,   1 p + 1 q = 1 1<p,q<\infty,\text{ }\frac{1}{p}+\frac{1}{q}=1 1<p,q<, p1+q1=1.

    Form of Integral
       f ∈ L p [ a , b ] ,   g ∈ L q [ a , b ] f\in {{L}^{p}}\left[ a,b \right],\text{ }g\in {{L}^{q}}\left[ a,b \right] fLp[a,b], gLq[a,b], then:

    • f ( x ) g ( x ) ∈ L 1 [ a , b ] f\left( x \right)g\left( x \right)\in {{L}^{1}}\left[ a,b \right] f(x)g(x)L1[a,b]
    • ∫ a b ∣ f ( x ) g ( x ) ∣ d x ≤ ( ∫ a b ∣ f ( x ) ∣ p d x ) 1 p ( ∫ a b ∣ g ( x ) ∣ q d x ) 1 q \int_{a}^{b}{\left| f\left( x \right)g\left( x \right) \right|dx}\le {{\left( \int_{a}^{b}{{{\left| f\left( x \right) \right|}^{p}}dx} \right)}^{\frac{1}{p}}}{{\left( \int_{a}^{b}{{{\left| g\left( x \right) \right|}^{q}}dx} \right)}^{\frac{1}{q}}} abf(x)g(x)dx(abf(x)pdx)p1(abg(x)qdx)q1
      or ∥ f g ∥ 1 ≤ ∥ f ∥ p ∥ g ∥ q {{\left\| fg \right\|}_{1}}\le {{\left\| f \right\|}_{p}}{{\left\| g \right\|}_{q}} fg1fpgq

    Form of Series
       x = { x k } ∈ l p ,   y = { y k } ∈ l q x=\left\{ {{x}_{k}} \right\}\in {{l}^{p}},\text{ }y=\left\{ {{y}_{k}} \right\}\in {{l}^{q}} x={xk}lp, y={yk}lq, then

    • z = { x k y k } ∈ l 1 z=\left\{ {{x}_{k}}{{y}_{k}} \right\}\in {{l}^{1}} z={xkyk}l1
    • ∑ k = 1 ∞ ∣ x k y k ∣ ≤ ( ∑ k = 1 ∞ ∣ x k ∣ p ) 1 p ( ∑ k = 1 ∞ ∣ y k ∣ q ) 1 q \sum\limits_{k=1}^{\infty }{\left| {{x}_{k}}{{y}_{k}} \right|}\le {{\left( \sum\limits_{k=1}^{\infty }{{{\left| {{x}_{k}} \right|}^{p}}} \right)}^{\frac{1}{p}}}{{\left( \sum\limits_{k=1}^{\infty }{{{\left| {{y}_{k}} \right|}^{q}}} \right)}^{\frac{1}{q}}} k=1xkyk(k=1xkp)p1(k=1ykq)q1
      or ∥ x y ∥ 1 ≤ ∥ x ∥ p ∥ y ∥ q {{\left\| xy \right\|}_{1}}\le {{\left\| x \right\|}_{p}}{{\left\| y \right\|}_{q}} xy1xpyq

    Proof (Use Integral Form of an example)

    1. If ∥ f ∥ p = 0   ∨   ∥ g ∥ q = 0 {{\left\| f \right\|}_{p}}=0\text{ }\vee \text{ }{{\left\| g \right\|}_{q}}=0 fp=0  gq=0 is true, the conclusion is obvious.
    2. Suppose ∥ f ∥ p > 0   &   ∥ g ∥ q > 0 {{\left\| f \right\|}_{p}}>0\text{ }\And \text{ }{{\left\| g \right\|}_{q}}>0 fp>0 & gq>0. Let ϕ ( t ) = t 1 p ( t > 0 ) \phi \left( t \right)={{t}^{\frac{1}{p}}}\left( t>0 \right) ϕ(t)=tp1(t>0).
      ϕ ′ ′ ( t ) = 1 p ( 1 p − 1 ) t 1 p − 2 < 0 ,   ∀ t > 0 \phi ''\left( t \right)=\frac{1}{p}\left( \frac{1}{p}-1 \right){{t}^{\frac{1}{p}-2}}<0,\text{ }\forall t>0 ϕ(t)=p1(p11)tp12<0, t>0
      Hence ϕ \phi ϕ is concave and we have
        ϕ ( t 1 ) ≤ ϕ ( t 2 ) + ϕ ′ ( t 2 ) ( t 2 − t 1 ) ,   ∀ t 1 , t 2 > 0 ⇒ ϕ ( t ) ≤ ϕ ( 1 ) + ϕ ′ ( 1 ) ( t − 1 )   ( L e t   t = t 1 ,   t 2 = 1 ) ⇒ t 1 p ≤ 1 + t − 1 p = t p + 1 q   ( 1 ) \begin{aligned} & \text{ }\phi \left( {{t}_{1}} \right)\le \phi \left( {{t}_{2}} \right)+\phi '\left( {{t}_{2}} \right)\left( {{t}_{2}}-{{t}_{1}} \right),\text{ }\forall {{t}_{1}},{{t}_{2}}>0 \\ & \Rightarrow \phi \left( t \right)\le \phi \left( 1 \right)+\phi '\left( 1 \right)\left( t-1 \right)\text{ }\left( Let\text{ }t={{t}_{1}},\text{ }{{t}_{2}}=1 \right) \\ & \Rightarrow {{t}^{\frac{1}{p}}}\le 1+\frac{t-1}{p}=\frac{t}{p}+\frac{1}{q}\text{ }\left( 1 \right) \\ \end{aligned}  ϕ(t1)ϕ(t2)+ϕ(t2)(t2t1), t1,t2>0ϕ(t)ϕ(1)+ϕ(1)(t1) (Let t=t1, t2=1)tp11+pt1=pt+q1 (1)
      Let u ≥ 0 ,   v > 0 u\ge 0,\text{ }v>0 u0, v>0, then we can set t = u p v − q > 0 t={{u}^{p}}{{v}^{-q}}>0 t=upvq>0.
      ( 1 ) ⇒ ( u p v − q ) 1 p ≤ 1 p ( u p v − q ) + 1 q ⇒ u v − q p ≤ 1 p u p v − q + 1 q ⇒ u v ≤ 1 p u p v − q ( v q p + 1 ) + 1 q ( v q p + 1 ) ⇒ u v ≤ 1 p u p v q p + 1 − q + 1 q v q p + 1 = u p p + v q q   ( ∵ 1 p + 1 q = 1   ⇒   q p + 1 = q ) \begin{aligned} & \left( 1 \right)\Rightarrow {{\left( {{u}^{p}}{{v}^{-q}} \right)}^{\frac{1}{p}}}\le \frac{1}{p}\left( {{u}^{p}}{{v}^{-q}} \right)+\frac{1}{q} \\ & \Rightarrow u{{v}^{-\frac{q}{p}}}\le \frac{1}{p}{{u}^{p}}{{v}^{-q}}+\frac{1}{q} \\ & \Rightarrow uv\le \frac{1}{p}{{u}^{p}}{{v}^{-q}}\left( {{v}^{\frac{q}{p}+1}} \right)+\frac{1}{q}\left( {{v}^{\frac{q}{p}+1}} \right) \\ & \Rightarrow uv\le \frac{1}{p}{{u}^{p}}{{v}^{\frac{q}{p}+1-q}}+\frac{1}{q}{{v}^{\frac{q}{p}+1}}=\frac{{{u}^{p}}}{p}+\frac{{{v}^{q}}}{q}\text{ }\left( \because \frac{1}{p}+\frac{1}{q}=1\text{ }\Rightarrow \text{ }\frac{q}{p}+1=q \right) \\ \end{aligned} (1)(upvq)p1p1(upvq)+q1uvpqp1upvq+q1uvp1upvq(vpq+1)+q1(vpq+1)uvp1upvpq+1q+q1vpq+1=pup+qvq (p1+q1=1  pq+1=q)
      Let f 1 = ∥ f ∥ p − 1 f ,   g 1 = ∥ g ∥ q − 1 g {{f}_{1}}={{\left\| f \right\|}_{p}}^{-1}f,\text{ }{{g}_{1}}={{\left\| g \right\|}_{q}}^{-1}g f1=fp1f, g1=gq1g. Then ∥ f 1 ∥ p = ∥ g 1 ∥ q = 1 {{\left\| {{f}_{1}} \right\|}_{p}}={{\left\| {{g}_{1}} \right\|}_{q}}=1 f1p=g1q=1, and we have
        ∥ f 1 g 1 ∥ 1 = ∥   ∥ f ∥ p − 1 ∥ g ∥ q − 1 f g   ∥ 1 = ∥ f g ∥ 1 ∥ f ∥ p ∥ g ∥ q   ( 2 ) \begin{aligned} & \text{ }{{\left\| {{f}_{1}}{{g}_{1}} \right\|}_{1}} \\ & ={{\left\| \text{ }{{\left\| f \right\|}_{p}}^{-1}{{\left\| g \right\|}_{q}}^{-1}fg\text{ } \right\|}_{1}} \\ & =\frac{{{\left\| fg \right\|}_{1}}}{{{\left\| f \right\|}_{p}}{{\left\| g \right\|}_{q}}}\text{ }\left( 2 \right) \\ \end{aligned}  f1g11= fp1gq1fg 1=fpgqfg1 (2)
      Set u = ∣ f 1 ∣   &   v = ∣ g 1 ∣ u=\left| {{f}_{1}} \right|\text{ }\And \text{ }v=\left| {{g}_{1}} \right| u=f1 & v=g1, and we have
      ∣ f 1 ( x ) g 1 ( x ) ∣ ≤ ∣ f 1 ( x ) ∣ p p + ∣ g 1 ( x ) ∣ q q \left| {{f}_{1}}\left( x \right){{g}_{1}}\left( x \right) \right|\le \frac{{{\left| {{f}_{1}}\left( x \right) \right|}^{p}}}{p}+\frac{{{\left| {{g}_{1}}\left( x \right) \right|}^{q}}}{q} f1(x)g1(x)pf1(x)p+qg1(x)q
      Therefore, we have
        ∥ f 1 g 1 ∥ 1 = ( ∫ a b ∣ f 1 ( x ) g 1 ( x ) ∣ 1 d x ) 1 1 ≤ ∫ a b [ ( ∣ f 1 ( x ) ∣ p p ) + ( ∣ g 1 ( x ) ∣ q q ) ] d x = 1 p ∫ a b ∣ f 1 ( x ) ∣ p d x + 1 q ∫ a b ∣ g 1 ( x ) ∣ q d x = 1 p ∥ f 1 ∥ p 1 p + 1 q ∥ g 1 ∥ q 1 q = 1 p + 1 q = 1   ( 3 ) \begin{aligned} & \text{ }{{\left\| {{f}_{1}}{{g}_{1}} \right\|}_{1}} \\ & ={{\left( \int_{a}^{b}{{{\left| {{f}_{1}}\left( x \right){{g}_{1}}\left( x \right) \right|}^{1}}dx} \right)}^{\frac{1}{1}}} \\ & \le \int_{a}^{b}{\left[ \left( \frac{{{\left| {{f}_{1}}\left( x \right) \right|}^{p}}}{p} \right)+\left( \frac{{{\left| {{g}_{1}}\left( x \right) \right|}^{q}}}{q} \right) \right]dx} \\ & \text{=}\frac{1}{p}\int_{a}^{b}{{{\left| {{f}_{1}}\left( x \right) \right|}^{p}}dx}+\frac{1}{q}\int_{a}^{b}{{{\left| {{g}_{1}}\left( x \right) \right|}^{q}}dx} \\ & =\frac{1}{p}{{\left\| {{f}_{1}} \right\|}_{p}}^{\frac{1}{p}}+\frac{1}{q}{{\left\| {{g}_{1}} \right\|}_{q}}^{\frac{1}{q}} \\ & =\frac{1}{p}+\frac{1}{q}=1\text{ }\left( 3 \right) \\ \end{aligned}  f1g11=(abf1(x)g1(x)1dx)11ab[(pf1(x)p)+(qg1(x)q)]dx=p1abf1(x)pdx+q1abg1(x)qdx=p1f1pp1+q1g1qq1=p1+q1=1 (3)
      ( 2 ) & ( 3 )   ⇒   ∥ f g ∥ 1 ≤ ∥ f ∥ p ∥ g ∥ q \left( 2 \right)\And \left( 3 \right)\text{ }\Rightarrow \text{ }{{\left\| fg \right\|}_{1}}\le {{\left\| f \right\|}_{p}}{{\left\| g \right\|}_{q}} (2)&(3)  fg1fpgq

    Minkowski 不等式

      Let 1 ≤ p < ∞ 1\le p<\infty 1p<

    Form of Integral
    f , g ∈ L p [ a , b ] f,g\in {{L}^{p}}\left[ a,b \right] f,gLp[a,b], then we have

    • f + g ∈ L p [ a , b ] f+g\in {{L}^{p}}\left[ a,b \right] f+gLp[a,b]
    • ( ∫ a b ∣ f ( x ) + g ( x ) ∣ p d x ) 1 p ≤ ( ∫ a b ∣ f ( x ) ∣ p d x ) 1 p + ( ∫ a b ∣ g ( x ) ∣ p d x ) 1 p {{\left( \int_{a}^{b}{{{\left| f\left( x \right)+g\left( x \right) \right|}^{p}}dx} \right)}^{\frac{1}{p}}}\le {{\left( \int_{a}^{b}{{{\left| f\left( x \right) \right|}^{p}}dx} \right)}^{\frac{1}{p}}}+{{\left( \int_{a}^{b}{{{\left| g\left( x \right) \right|}^{p}}dx} \right)}^{\frac{1}{p}}} (abf(x)+g(x)pdx)p1(abf(x)pdx)p1+(abg(x)pdx)p1
      or
      ∥ f + g ∥ p ≤ ∥ f ∥ p + ∥ g ∥ p {{\left\| f+g \right\|}_{p}}\le {{\left\| f \right\|}_{p}}+{{\left\| g \right\|}_{p}} f+gpfp+gp

    Form of Series
    x = { x k } ,   y = { y k } ∈ l p x=\left\{ {{x}_{k}} \right\},\text{ }y=\left\{ {{y}_{k}} \right\}\in {{l}^{p}} x={xk}, y={yk}lp, then we have

    • z = { x k + y k } ∈ l p z=\left\{ {{x}_{k}}+{{y}_{k}} \right\}\in {{l}^{p}} z={xk+yk}lp
    • ( ∑ k = 1 ∞ ∣ x k + y k ∣ p ) 1 p ≤ ( ∑ k = 1 ∞ ∣ x k ∣ p ) 1 p + ( ∑ k = 1 ∞ ∣ y k ∣ p ) 1 p {{\left( \sum\limits_{k=1}^{\infty }{{{\left| {{x}_{k}}+{{y}_{k}} \right|}^{p}}} \right)}^{\frac{1}{p}}}\le {{\left( \sum\limits_{k=1}^{\infty }{{{\left| {{x}_{k}} \right|}^{p}}} \right)}^{\frac{1}{p}}}+{{\left( \sum\limits_{k=1}^{\infty }{{{\left| {{y}_{k}} \right|}^{p}}} \right)}^{\frac{1}{p}}} (k=1xk+ykp)p1(k=1xkp)p1+(k=1ykp)p1
      or
      ∥ x + y ∥ p ≤ ∥ x ∥ p + ∥ y ∥ p {{\left\| x+y \right\|}_{p}}\le {{\left\| x \right\|}_{p}}+{{\left\| y \right\|}_{p}} x+ypxp+yp

    Proof (Use Form of Integral as an example)
    Note that
      ∫ a b ∣ f + g ∣ p d x = ∫ a b ∣ f + g ∣ ⋅ ∣ f + g ∣ p − 1 d x ≤ ∫ a b ( ∣ f ∣ + ∣ g ∣ ) ∣ f + g ∣ p − 1 d x = ∫ a b ∣ f ∣ ∣ f + g ∣ p − 1 d x + ∫ a b ∣ g ∣ ∣ f + g ∣ p − 1 d x \begin{aligned} & \text{ }\int_{a}^{b}{{{\left| f+g \right|}^{p}}dx} \\ & =\int_{a}^{b}{\left| f+g \right|\centerdot {{\left| f+g \right|}^{p-1}}}dx \\ & \le \int_{a}^{b}{\left( \left| f \right|+\left| g \right| \right){{\left| f+g \right|}^{p-1}}dx} \\ & =\int_{a}^{b}{\left| f \right|{{\left| f+g \right|}^{p-1}}dx}+\int_{a}^{b}{\left| g \right|{{\left| f+g \right|}^{p-1}}dx} \\ \end{aligned}  abf+gpdx=abf+gf+gp1dxab(f+g)f+gp1dx=abff+gp1dx+abgf+gp1dx
    By Hölder’s Inequalty, we have
    ∫ a b ∣ f ∣ ∣ f + g ∣ p − 1 d x ≤ ( ∫ a b ∣ f ∣ p d x ) 1 p ( ∫ a b ∣ f + g ∣ ( p − 1 ) q d x ) 1 q ∫ a b ∣ g ∣ ∣ f + g ∣ p − 1 d x ≤ ( ∫ a b ∣ g ∣ p d x ) 1 p ( ∫ a b ∣ f + g ∣ ( p − 1 ) q d x ) 1 q \begin{aligned} & \int_{a}^{b}{\left| f \right|{{\left| f+g \right|}^{p-1}}dx}\le {{\left( \int_{a}^{b}{{{\left| f \right|}^{p}}dx} \right)}^{\frac{1}{p}}}{{\left( \int_{a}^{b}{{{\left| f+g \right|}^{\left( p-1 \right)q}}}dx \right)}^{\frac{1}{q}}} \\ & \int_{a}^{b}{\left| g \right|{{\left| f+g \right|}^{p-1}}dx}\le {{\left( \int_{a}^{b}{{{\left| g \right|}^{p}}dx} \right)}^{\frac{1}{p}}}{{\left( \int_{a}^{b}{{{\left| f+g \right|}^{\left( p-1 \right)q}}}dx \right)}^{\frac{1}{q}}} \\ \end{aligned} abff+gp1dx(abfpdx)p1(abf+g(p1)qdx)q1abgf+gp1dx(abgpdx)p1(abf+g(p1)qdx)q1
    Thus we have
    ∫ a b ∣ f + g ∣ p d x ≤ ( ∥ f ∥ p + ∥ g ∥ p ) ( ∫ a b ∣ f + g ∣ ( p − 1 ) q d x ) 1 q = ( ∥ f ∥ p + ∥ g ∥ p ) ( ∫ a b ∣ f + g ∣ p d x ) 1 q ( ∵ 1 p + 1 q = 1   ⇒   q + p = p q   ⇒   q ( p − 1 ) = p ) \begin{aligned} & \int_{a}^{b}{{{\left| f+g \right|}^{p}}dx}\le \left( {{\left\| f \right\|}_{p}}+{{\left\| g \right\|}_{p}} \right){{\left( \int_{a}^{b}{{{\left| f+g \right|}^{\left( p-1 \right)q}}dx} \right)}^{\frac{1}{q}}} \\ & =\left( {{\left\| f \right\|}_{p}}+{{\left\| g \right\|}_{p}} \right){{\left( \int_{a}^{b}{{{\left| f+g \right|}^{p}}dx} \right)}^{\frac{1}{q}}} \\ & \left( \because \frac{1}{p}+\frac{1}{q}=1\text{ }\Rightarrow \text{ }q+p=pq\text{ }\Rightarrow \text{ }q\left( p-1 \right)=p \right) \\ \end{aligned} abf+gpdx(fp+gp)(abf+g(p1)qdx)q1=(fp+gp)(abf+gpdx)q1(p1+q1=1  q+p=pq  q(p1)=p)

    1. If ∥ f + g ∥ p = ( ∫ a b ∣ f + g ∣ p d x ) 1 p = 0 {{\left\| f+g \right\|}_{p}}={{\left( \int_{a}^{b}{{{\left| f+g \right|}^{p}}dx} \right)}^{\frac{1}{p}}}=0 f+gp=(abf+gpdx)p1=0, then ∫ a b ∣ f + g ∣ p d x = 0 \int_{a}^{b}{{{\left| f+g \right|}^{p}}dx}=0 abf+gpdx=0, both sides are 0, and we have
      ∥ f ∥ p + ∥ g ∥ p = ( ∫ a b ∣ f ( x ) ∣ p d x ) 1 p + ( ∫ a b ∣ g ( x ) ∣ p d x ) 1 p ≥ 0 + 0 = 0 = ∥ f + g ∥ p \begin{aligned} & {{\left\| f \right\|}_{p}}+{{\left\| g \right\|}_{p}} \\ & ={{\left( \int_{a}^{b}{{{\left| f\left( x \right) \right|}^{p}}dx} \right)}^{\frac{1}{p}}}+{{\left( \int_{a}^{b}{{{\left| g\left( x \right) \right|}^{p}}dx} \right)}^{\frac{1}{p}}} \\ & \ge 0+0 \\ & =0 \\ & ={{\left\| f+g \right\|}_{p}} \\ \end{aligned} fp+gp=(abf(x)pdx)p1+(abg(x)pdx)p10+0=0=f+gp

    2. Otherwise, one divides both sides by ( ∫ a b ∣ f + g ∣ p d x ) 1 q {{\left( \int_{a}^{b}{{{\left| f+g \right|}^{p}}}dx \right)}^{\frac{1}{q}}} (abf+gpdx)q1, we have
        ( ∫ a b ∣ f + g ∣ p d x ) 1 − 1 q ≤ ∥ f ∥ p + ∥ g ∥ p ⇒ ( ∫ a b ∣ f + g ∣ p d x ) 1 p = ∥ f + g ∥ p ≤ ∥ f ∥ p + ∥ g ∥ p \begin{aligned} & \text{ }{{\left( \int_{a}^{b}{{{\left| f+g \right|}^{p}}dx} \right)}^{1-\frac{1}{q}}}\le {{\left\| f \right\|}_{p}}+{{\left\| g \right\|}_{p}} \\ & \Rightarrow {{\left( \int_{a}^{b}{{{\left| f+g \right|}^{p}}dx} \right)}^{\frac{1}{p}}}={{\left\| f+g \right\|}_{p}}\le {{\left\| f \right\|}_{p}}+{{\left\| g \right\|}_{p}} \\ \end{aligned}  (abf+gpdx)1q1fp+gp(abf+gpdx)p1=f+gpfp+gp

    展开全文
  • Minkowski不等式

    千次阅读 2020-05-19 22:33:33
    假设p≥1p\ge1p≥1, 而且g1g_1g1​和g2g_2g2​是测度空间(X,μ)(X,\mu)(X,μ)上p-方可积函数,则 ∥g1+g2∥p≤∥g1∥p+∥g2∥p \|g_1+g_2\|_p\le\|g_1\|_p+\|g_2\|_p ∥g1​+g2​∥p​≤∥g1​∥p​+∥g2​∥p​ ...
  • Hermite定理的证明使用了Blichfeld定理和Minkowski定理的一个结果,下面对Minkowski定理进行介绍。 Minkowski’s Theorem: 设 L ⊂ R n L⊂R^n L⊂Rn是维数为n的格,设 S ⊂ R n S⊂R^n S⊂Rn是一个对称凸集,其...
  • 闵可夫斯基引擎Minkowski Engine Minkowski引擎是一个用于稀疏张量的自动微分库。它支持所有标准神经网络层,例如对稀疏张量的卷积,池化,解池和广播操作。有关更多信息,请访问文档页面。闵可夫斯基引擎Minkowski ...
  • var minkowski = require ( 'compute-minkowski-distance' ) ; minkowski( x, y, [opts] ) 计算两个arrays之间的。 var x = [ 2 , 4 , 5 , 3 , 8 , 2 ] , y = [ 3 , 1 , 5 , - 3 , 7 , 2 ] ; var d = minkowski...
  • 我们显示,Q,U的Minkowski泛函(MF)在沿视线的局部旋转下是不变的,即使Q,U是自旋2变量,也可以进行全天空分析。 对于不完整的天空,不变性不成立。 对于局部类型的原始非高斯性,当我们将Q,U的MF的非高斯偏差...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,671
精华内容 2,268
关键字:

minkowski