public void CreateFromRowCollectionTest()
        {
            // elements is null
            {
                ArgumentExceptionAssert.Throw(
                    () =>
                {
                    var partition = IndexPartition.Create((DoubleMatrixRowCollection)null);
                },
                    expectedType: typeof(ArgumentNullException),
                    expectedPartialMessage: ArgumentExceptionAssert.NullPartialMessage,
                    expectedParameterName: "elements");
            }

            // elements is not null
            {
                // Create a matrix.
                var data = new double[18] {
                    0, 0, 1,
                    0, 0, 1,
                    0, 1, 0,
                    0, 1, 0,
                    1, 0, 0,
                    1, 0, 0
                };
                var matrix = DoubleMatrix.Dense(6, 3, data, StorageOrder.RowMajor);

                // Partition the matrix row indexes by the contents of each row:
                // a part is created for each distinct row.
                var elements = matrix.AsRowCollection();
                var actual   = IndexPartition.Create(elements);

                // Each part is identified by its corresponding row and contains
                // the indexes of the rows which are equal to the identifier.

                // Expected:
                //
                // Part identifier: 0                0                1
                //
                //      indexes: 0, 1
                //
                // Part identifier: 0                1                0
                //
                //      indexes: 2, 3
                //
                // Part identifier: 1                0                0
                //
                //      indexes: 4, 5
                //

                var expected = new IndexPartition <DoubleMatrixRow>
                {
                    partIndetifiers = new List <DoubleMatrixRow>(3)
                    {
                        elements[0],
                        elements[2],
                        elements[4]
                    },

                    parts = new Dictionary <DoubleMatrixRow, IndexCollection>(3)
                    {
                        { elements[0], IndexCollection.Default(1) },
                        { elements[2], IndexCollection.Range(2, 3) },
                        { elements[4], IndexCollection.Range(4, 5) }
                    }
                };

                IndexPartitionAssert.AreEqual(expected, actual);
            }
        }
        public void CreateFromEnumerableTest()
        {
            // elements is null
            {
                ArgumentExceptionAssert.Throw(
                    () =>
                {
                    var partition = IndexPartition.Create((string[])null);
                },
                    expectedType: typeof(ArgumentNullException),
                    expectedPartialMessage: ArgumentExceptionAssert.NullPartialMessage,
                    expectedParameterName: "elements");
            }

            // elements is not null
            {
                // Create an array of strings.
                var elements = new string[6] {
                    "one",
                    "two",
                    "one",
                    "one",
                    "three",
                    "three"
                };

                // Partition the array positions by their contents.
                var actual = IndexPartition.Create(elements);

                // The partition contains three parts, identified, respectively,
                // by the strings "one", "two", and "three".

                // Expected:
                //
                // Part identifier: one
                //      indexes: 0, 2, 3
                //
                // Part identifier: three
                //      indexes: 4, 5
                //
                // Part identifier: two
                //      indexes: 1

                var expected = new IndexPartition <string>
                {
                    partIndetifiers = new List <string>(3)
                    {
                        "one",
                        "three",
                        "two"
                    },

                    parts = new Dictionary <string, IndexCollection>(3)
                    {
                        { "one", IndexCollection.FromArray(new int[] { 0, 2, 3 }) },
                        { "three", IndexCollection.Range(4, 5) },
                        { "two", IndexCollection.FromArray(new int[] { 1 }) }
                    }
                };

                IndexPartitionAssert.AreEqual(expected, actual);
            }
        }
        public void CreateFromIndexCollectionTest()
        {
            // elements is null
            {
                bool partitioner(int linearIndex)
                {
                    return(linearIndex < 3);
                }

                ArgumentExceptionAssert.Throw(
                    () =>
                {
                    var partition = IndexPartition.Create(
                        (IndexCollection)null,
                        partitioner);
                },
                    expectedType: typeof(ArgumentNullException),
                    expectedPartialMessage: ArgumentExceptionAssert.NullPartialMessage,
                    expectedParameterName: "elements");
            }

            // partitioner is null
            {
                Func <int, bool> partitioner = null;

                ArgumentExceptionAssert.Throw(
                    () =>
                {
                    var partition = IndexPartition.Create(
                        IndexCollection.Default(3),
                        partitioner);
                },
                    expectedType: typeof(ArgumentNullException),
                    expectedPartialMessage: ArgumentExceptionAssert.NullPartialMessage,
                    expectedParameterName: "partitioner");
            }

            // Valid parameters
            {
                // Create a matrix.
                var data = new double[16] {
                    -3, 3, 3, -1,
                    0, 2, -2, 2,
                    2, 1, -4, -5,
                    -8, 2, 7, -1
                };
                var matrix = DoubleMatrix.Dense(4, 4, data, StorageOrder.RowMajor);

                // Create the collection of linear indexes corresponding
                // to entries on the matrix main diagonal.
                var elements =
                    IndexCollection.Sequence(0, 1 + matrix.NumberOfRows, matrix.Count);

                // Create a partitioner which returns true if
                // the absolute value in a entry having the specified linear
                // index is less than 3, otherwise false.
                bool partitioner(int linearIndex)
                {
                    return(Math.Abs(matrix[linearIndex]) < 3.0);
                }

                // Partition the diagonal linear indexes through the
                // specified partitioner.
                var actual = IndexPartition.Create(elements, partitioner);

                // Two parts are created, one for diagonal
                // entries less than 3 in absolute value, the other for
                // entries not satisfying that condition.

                // Expected:
                //
                // Part identifier: False
                //      indexes: 0, 10
                //
                // Part identifier: True
                //      indexes: 5, 15
                //
                var expected = new IndexPartition <bool>
                {
                    partIndetifiers = new List <bool>(2)
                    {
                        false,
                        true
                    },

                    parts = new Dictionary <bool, IndexCollection>(2)
                    {
                        { false, IndexCollection.FromArray(new int[2] {
                                0, 10
                            }) },
                        { true, IndexCollection.FromArray(new int[2] {
                                5, 15
                            }) }
                    }
                };

                IndexPartitionAssert.AreEqual(expected, actual);
            }
        }
        public void CreateFromDoubleMatrixTest()
        {
            // elements is null
            {
                ArgumentExceptionAssert.Throw(
                    () =>
                {
                    var partition = IndexPartition.Create((DoubleMatrix)null);
                },
                    expectedType: typeof(ArgumentNullException),
                    expectedPartialMessage: ArgumentExceptionAssert.NullPartialMessage,
                    expectedParameterName: "elements");
            }

            // elements is a vector
            {
                // Create a matrix
                var data = new double[18] {
                    0, 0, 1,
                    0, 0, 1,
                    0, 1, 0,
                    0, 1, 0,
                    1, 0, 0,
                    1, 0, 0
                };
                var matrix = DoubleMatrix.Dense(6, 3, data, StorageOrder.RowMajor);

                // Partition the matrix row indexes by the contents of column 0:
                // a part is created for each distinct value in column 0
                var elements = matrix[":", 0];
                var actual   = IndexPartition.Create(elements);

                // Each part is identified by its corresponding value and contains
                // the indexes of the rows in which the identifier
                // is positioned in column 0

                // Expected:
                //
                // Part identifier: 0
                //      indexes: 0, 1, 2, 3
                //
                // Part identifier: 1
                //      indexes: 4, 5

                IndexPartition <double> expected = new()
                {
                    partIndetifiers = new List <double>(2)
                    {
                        0.0,
                        1.0
                    },

                    parts = new Dictionary <double, IndexCollection>(2)
                    {
                        { 0.0, IndexCollection.Default(3) },
                        { 1.0, IndexCollection.Range(4, 5) }
                    }
                };

                IndexPartitionAssert.AreEqual(expected, actual);
            }

            // elements is a matrix of signs
            {
                // Create a matrix.
                var data = new double[8] {
                    0, 1, -2, -3,
                    0, -1, 2, 3
                };
                var matrix = DoubleMatrix.Dense(2, 4, data, StorageOrder.RowMajor);

                // Check the sign of its entries
                var signs = DoubleMatrix.Dense(matrix.NumberOfRows, matrix.NumberOfColumns);
                for (int i = 0; i < matrix.Count; i++)
                {
                    signs[i] = Math.Sign(matrix[i]);
                }

                // Partition the matrix linear indexes by the sign of each entry
                var actual = IndexPartition.Create(signs);

                // The partition contains three parts, the zero part, identified by 0,
                // the negative part (identified by -1), and the positive one
                // (identified by 1).

                // Expected:
                //
                // Part identifier: -1
                //      indexes: 3, 4, 6
                //
                // Part identifier: 0
                //      indexes: 0, 1
                //
                // Part identifier: 1
                //      indexes: 2, 5, 7
                //

                IndexPartition <double> expected = new()
                {
                    partIndetifiers = new List <double>(3)
                    {
                        -1.0,
                        0.0,
                        1.0
                    },

                    parts = new Dictionary <double, IndexCollection>(3)
                    {
                        { -1.0, IndexCollection.FromArray(new int[] { 3, 4, 6 }) },
                        { 0.0, IndexCollection.Default(1) },
                        { 1.0, IndexCollection.FromArray(new int[] { 2, 5, 7 }) }
                    }
                };

                IndexPartitionAssert.AreEqual(expected, actual);
            }

            // elements is a matrix of data
            {
                // Create a matrix
                var data = new double[6] {
                    1, 3,
                    0, 2,
                    2, 1
                };
                var elements = DoubleMatrix.Dense(3, 2, data, StorageOrder.RowMajor);

                // Partition the matrix linear indexes by the content of
                // matrix entries: a part is created for each distinct matrix value
                var actual = IndexPartition.Create(elements);

                // Each part is identified by its corresponding value and contains
                // the linear indexes of the entries in which the identifier
                // is positioned.

                // This code example produces the following output:
                //
                //
                // Part identifier: 0
                //      indexes: 1
                //
                // Part identifier: 1
                //      indexes: 0, 5
                //
                // Part identifier: 2
                //      indexes: 2, 4
                //
                // Part identifier: 3
                //      indexes: 3
                //

                var expected = new IndexPartition <double>
                {
                    partIndetifiers = new List <double>(3)
                    {
                        0.0,
                        1.0,
                        2.0,
                        3.0
                    },

                    parts = new Dictionary <double, IndexCollection>(3)
                    {
                        { 0.0, IndexCollection.FromArray(new int[] { 1 }) },
                        { 1.0, IndexCollection.FromArray(new int[] { 0, 5 }) },
                        { 2.0, IndexCollection.FromArray(new int[] { 2, 4 }) },
                        { 3.0, IndexCollection.FromArray(new int[] { 3 }) }
                    }
                };

                IndexPartitionAssert.AreEqual(expected, actual);
            }
        }