GetSimplexVolume() public static method

Computes the volume of an n-dimensional simplex. Buffer needs to be array of shape Dimension x Dimension.
public static GetSimplexVolume ( ConvexFaceInternal cell, IList vertices, SimplexVolumeBuffer buffer ) : double
cell ConvexFaceInternal
vertices IList
buffer SimplexVolumeBuffer Helper for the calculation to avoid unnecessary allocations.
return double
Esempio n. 1
0
        /// <summary>
        /// Removes the empty boundary cells that might have been created using PointTranslationType.TranslateInternal.
        /// </summary>
        /// <param name="tolerance"></param>
        void RemoveEmptyBoundaryCells(double tolerance)
        {
            var faces     = ConvexFaces;
            var pool      = FacePool;
            var dimension = Dimension - 1;

            bool[]      visited = new bool[pool.Length];
            bool[]      remove  = new bool[pool.Length];
            IndexBuffer toTest  = new IndexBuffer();

            for (var i = faces.Count - 1; i >= 0; i--)
            {
                var adj = pool[faces[i]].AdjacentFaces;
                for (int j = 0; j < adj.Length; j++)
                {
                    if (adj[j] < 0)
                    {
                        toTest.Push(faces[i]);
                        break;
                    }
                }
            }

            double[][] buffer = new double[dimension][];
            for (int i = 0; i < dimension; i++)
            {
                buffer[i] = new double[dimension];
            }

            var simplexVolumeBuffer = new MathHelper.SimplexVolumeBuffer(dimension);

            while (toTest.Count > 0)
            {
                var top  = toTest.Pop();
                var face = pool[top];
                visited[top] = true;

                if (MathHelper.GetSimplexVolume(face, Vertices, simplexVolumeBuffer) < tolerance)
                {
                    remove[top] = true;

                    var adj = face.AdjacentFaces;
                    for (int j = 0; j < adj.Length; j++)
                    {
                        var n = adj[j];
                        if (n >= 0 && !visited[n])
                        {
                            toTest.Push(n);
                        }
                    }
                }
            }

            for (int i = faces.Count - 1; i >= 0; i--)
            {
                if (remove[faces[i]])
                {
                    var candidateIndex = faces[i];
                    var candidate      = pool[candidateIndex];
                    for (int fi = 0; fi < candidate.AdjacentFaces.Length; fi++)
                    {
                        var af = candidate.AdjacentFaces[fi];
                        if (af >= 0)
                        {
                            var face = pool[af];
                            for (int j = 0; j < face.AdjacentFaces.Length; j++)
                            {
                                if (face.AdjacentFaces[j] == candidateIndex)
                                {
                                    face.AdjacentFaces[j] = -1;
                                }
                            }
                        }
                    }

                    faces[i] = faces[faces.Count - 1];
                    faces.Pop();
                }
            }
        }
        /// <summary>
        /// Finds (dimension + 1) initial points.
        /// </summary>
        /// <param name="extremes"></param>
        /// <returns></returns>
        private List <int> FindInitialPoints()
        {
            var bigNumber = maxima.Sum() * NumOfDimensions * NumberOfVertices;
            // the first two points are taken from the dimension that had the fewest extremes
            // well, in most cases there will only be 2 in all dimensions: one min and one max
            // but a lot of engineering part shapes are nice and square and can have hundreds of
            // parallel vertices at the extremes
            var vertex1 = boundingBoxPoints[indexOfDimensionWithLeastExtremes].First(); // these are min and max vertices along
            var vertex2 = boundingBoxPoints[indexOfDimensionWithLeastExtremes].Last();  // the dimension that had the fewest points

            boundingBoxPoints[indexOfDimensionWithLeastExtremes].RemoveAt(0);
            boundingBoxPoints[indexOfDimensionWithLeastExtremes].RemoveAt(boundingBoxPoints[indexOfDimensionWithLeastExtremes].Count - 1);
            var initialPoints = new List <int> {
                vertex1, vertex2
            };

            VertexVisited[vertex1] = VertexVisited[vertex2] = true;
            CurrentVertex          = vertex1; UpdateCenter();
            CurrentVertex          = vertex2; UpdateCenter();
            var edgeVectors = new double[NumOfDimensions][];

            edgeVectors[0] = MathHelper.VectorBetweenVertices(vertex2, vertex1);
            // now the remaining vertices are just combined in one big list
            var extremes = boundingBoxPoints.SelectMany(x => x).ToList();
            // otherwise find the remaining points by maximizing the initial simplex volume
            var index = 1;

            while (index < NumOfDimensions && extremes.Any())
            {
                var bestVertex     = -1;
                var bestEdgeVector = new double[] { };
                var maxVolume      = 0.0;
                for (var i = extremes.Count - 1; i >= 0; i--)
                {
                    // count backwards in order to remove potential duplicates
                    var vIndex = extremes[i];
                    if (initialPoints.Contains(vIndex))
                    {
                        extremes.RemoveAt(i);
                    }
                    else
                    {
                        edgeVectors[index] = MathHelper.VectorBetweenVertices(vIndex, vertex1);
                        var volume = MathHelper.GetSimplexVolume(edgeVectors, index, bigNumber);
                        if (maxVolume < volume)
                        {
                            maxVolume      = volume;
                            bestVertex     = vIndex;
                            bestEdgeVector = edgeVectors[index];
                        }
                    }
                }
                extremes.Remove(bestVertex);
                if (bestVertex == -1)
                {
                    break;
                }
                initialPoints.Add(bestVertex);
                edgeVectors[index++] = bestEdgeVector;
                CurrentVertex        = bestVertex; UpdateCenter();
            }
            // hmm, there are not enough points on the bounding box to make a simplex. It is rare but entirely possibly.
            // As an extreme, the bounding box can be made in n dimensions from only 2 unique points. When we can't find
            // enough unique points, we start again with ALL the vertices. The following is a near replica of the code
            // above, but instead of extremes, we consider "allVertices".
            if (initialPoints.Count <= NumOfDimensions)
            {
                var allVertices = Enumerable.Range(0, NumberOfVertices).ToList();
                while (index < NumOfDimensions && allVertices.Any())
                {
                    var bestVertex     = -1;
                    var bestEdgeVector = new double[] { };
                    var maxVolume      = 0.0;
                    for (var i = allVertices.Count - 1; i >= 0; i--)
                    {
                        // count backwards in order to remove potential duplicates
                        var vIndex = allVertices[i];
                        if (initialPoints.Contains(vIndex))
                        {
                            allVertices.RemoveAt(i);
                        }
                        else
                        {
                            edgeVectors[index] = MathHelper.VectorBetweenVertices(vIndex, vertex1);
                            var volume = MathHelper.GetSimplexVolume(edgeVectors, index, bigNumber);
                            if (maxVolume < volume)
                            {
                                maxVolume      = volume;
                                bestVertex     = vIndex;
                                bestEdgeVector = edgeVectors[index];
                            }
                        }
                    }
                    allVertices.Remove(bestVertex);
                    if (bestVertex == -1)
                    {
                        break;
                    }
                    initialPoints.Add(bestVertex);
                    edgeVectors[index++] = bestEdgeVector;
                    CurrentVertex        = bestVertex; UpdateCenter();
                }
            }
            if (initialPoints.Count <= NumOfDimensions)
            {
                throw new ArgumentException("The input data is degenerate. It appears to exist in " + NumOfDimensions +
                                            " dimensions, but it is a " + (NumOfDimensions - 1) + " dimensional set (i.e. the point of collinear,"
                                            + " coplanar, or co-hyperplanar.)");
            }
            return(initialPoints);
        }
Esempio n. 3
0
        private List <int> FindInitialPoints()
        {
            double bigNumber = maxima.Sum() * (double)NumOfDimensions * (double)NumberOfVertices;
            int    num       = boundingBoxPoints[indexOfDimensionWithLeastExtremes].First();
            int    num2      = boundingBoxPoints[indexOfDimensionWithLeastExtremes].Last();

            boundingBoxPoints[indexOfDimensionWithLeastExtremes].RemoveAt(0);
            boundingBoxPoints[indexOfDimensionWithLeastExtremes].RemoveAt(boundingBoxPoints[indexOfDimensionWithLeastExtremes].Count - 1);
            List <int> list = new List <int>();

            list.Add(num);
            list.Add(num2);
            List <int> list2 = list;

            VertexVisited[num] = (VertexVisited[num2] = true);
            CurrentVertex      = num;
            UpdateCenter();
            CurrentVertex = num2;
            UpdateCenter();
            double[][] array = new double[NumOfDimensions][];
            array[0] = mathHelper.VectorBetweenVertices(num2, num);
            List <int> list3 = boundingBoxPoints.SelectMany((List <int> x) => x).ToList();
            int        num3  = 1;

            while (num3 < NumOfDimensions)
            {
                if (!list3.Any())
                {
                    break;
                }
                int      num4   = -1;
                double[] array2 = new double[0];
                double   num5   = 0.0;
                for (int num6 = list3.Count - 1; num6 >= 0; num6--)
                {
                    int num7 = list3[num6];
                    if (list2.Contains(num7))
                    {
                        list3.RemoveAt(num6);
                    }
                    else
                    {
                        array[num3] = mathHelper.VectorBetweenVertices(num7, num);
                        double simplexVolume = mathHelper.GetSimplexVolume(array, num3, bigNumber);
                        if (num5 < simplexVolume)
                        {
                            num5   = simplexVolume;
                            num4   = num7;
                            array2 = array[num3];
                        }
                    }
                }
                list3.Remove(num4);
                if (num4 == -1)
                {
                    break;
                }
                list2.Add(num4);
                array[num3++] = array2;
                CurrentVertex = num4;
                UpdateCenter();
            }
            if (list2.Count <= NumOfDimensions)
            {
                List <int> list4 = Enumerable.Range(0, NumberOfVertices).ToList();
                while (num3 < NumOfDimensions)
                {
                    if (!list4.Any())
                    {
                        break;
                    }
                    int      num9   = -1;
                    double[] array3 = new double[0];
                    double   num10  = 0.0;
                    for (int num11 = list4.Count - 1; num11 >= 0; num11--)
                    {
                        int num12 = list4[num11];
                        if (list2.Contains(num12))
                        {
                            list4.RemoveAt(num11);
                        }
                        else
                        {
                            array[num3] = mathHelper.VectorBetweenVertices(num12, num);
                            double simplexVolume2 = mathHelper.GetSimplexVolume(array, num3, bigNumber);
                            if (num10 < simplexVolume2)
                            {
                                num10  = simplexVolume2;
                                num9   = num12;
                                array3 = array[num3];
                            }
                        }
                    }
                    list4.Remove(num9);
                    if (num9 == -1)
                    {
                        break;
                    }
                    list2.Add(num9);
                    array[num3++] = array3;
                    CurrentVertex = num9;
                    UpdateCenter();
                }
            }
            if (list2.Count <= NumOfDimensions && IsLifted)
            {
                List <int> list5 = Enumerable.Range(0, NumberOfVertices).ToList();
                while (num3 < NumOfDimensions)
                {
                    if (!list5.Any())
                    {
                        break;
                    }
                    int      num14  = -1;
                    double[] array4 = new double[0];
                    double   num15  = 0.0;
                    for (int num16 = list5.Count - 1; num16 >= 0; num16--)
                    {
                        int num17 = list5[num16];
                        if (list2.Contains(num17))
                        {
                            list5.RemoveAt(num16);
                        }
                        else
                        {
                            mathHelper.RandomOffsetToLift(num17);
                            array[num3] = mathHelper.VectorBetweenVertices(num17, num);
                            double simplexVolume3 = mathHelper.GetSimplexVolume(array, num3, bigNumber);
                            if (num15 < simplexVolume3)
                            {
                                num15  = simplexVolume3;
                                num14  = num17;
                                array4 = array[num3];
                            }
                        }
                    }
                    list5.Remove(num14);
                    if (num14 == -1)
                    {
                        break;
                    }
                    list2.Add(num14);
                    array[num3++] = array4;
                    CurrentVertex = num14;
                    UpdateCenter();
                }
            }
            if (list2.Count <= NumOfDimensions && IsLifted)
            {
                throw new ArgumentException("The input data is degenerate. It appears to exist in " + NumOfDimensions + " dimensions, but it is a " + (NumOfDimensions - 1) + " dimensional set (i.e. the point of collinear, coplanar, or co-hyperplanar.)");
            }
            return(list2);
        }