public static QuiverWithPotential <int> GetTriangleQP(int numRows, int firstVertex = DefaultFirstVertex) { if (!TriangleParameterIsValid(numRows)) { throw new ArgumentOutOfRangeException(nameof(numRows)); } if (numRows == 1) { var quiver = UsefulQuivers.GetTriangleQuiver(numRows, firstVertex); return(new QuiverWithPotential <int>(quiver, new Potential <int>())); } var potential = new Potential <int>(); var curRowVertices = new List <int>() { firstVertex }; int nextVertex = firstVertex + 1; for (int rowIndex = 1; rowIndex <= numRows - 1; rowIndex++) // 1-based row index { var nextRowVertices = Enumerable.Range(nextVertex, rowIndex + 1).ToList(); nextVertex += rowIndex + 1; // (2*rowIndex - 1) triangles to add. Draw a small triangle QP to realize that // the cycles below are the ones to add. for (int indexInRow = 0; indexInRow < rowIndex; indexInRow++) { var cycleVertices = new int[] { curRowVertices[indexInRow], nextRowVertices[indexInRow + 1], nextRowVertices[indexInRow], curRowVertices[indexInRow] }; potential = potential.AddCycle(new DetachedCycle <int>(cycleVertices), +1); // Positive for clockwise cycles. } for (int indexInRow = 0; indexInRow < rowIndex - 1; indexInRow++) { var cycleVertices = new int[] { curRowVertices[indexInRow + 1], curRowVertices[indexInRow], nextRowVertices[indexInRow + 1], curRowVertices[indexInRow + 1] }; potential = potential.AddCycle(new DetachedCycle <int>(cycleVertices), -1); // Negative for counterclockwise cycles. } curRowVertices = nextRowVertices; } var qp = new QuiverWithPotential <int>(potential); return(qp); }