/// <summary>
        ///     Solves simultaneous linear equations.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="a"> [<c>a.Rank == 2 &amp;&amp; a.Shape[0] == a.Shape[1]</c>] </param>
        /// <param name="b"> [<c>(b.Rank == 1 || b.Rank == 2) &amp;&amp; b.Shape[0] == a.Shape[0]</c>] </param>
        /// <returns></returns>
        /// <exception cref="ShapeMismatchException">
        ///     <para> When <c>n := a.Shape[0]</c>, </para>
        ///     <para> - If <c>b.Shape == {n}</c>, then <c>$ReturnValue.Shape == {n}</c>. </para>
        ///     <para>
        ///         - If <c>b.Shape == {n, p}</c>, then <c>$ReturnValue.Shape == {n, p}</c>.
        ///         Each column of return value is the solution against corresponding column of b.
        ///     </para>
        /// </exception>
        public static NdArray <T> Solve <T>(this INdArray <T> a, INdArray <T> b)
        {
            Guard.AssertShapeMatch(a.Rank == 2 && a.Shape[0] == a.Shape[1], "a.Rank == 2 && a.Shape[0] == a.Shape[1]");
            if (b.Rank == 1 && b.Shape[0] == a.Shape[0])
            {
                var(l, u, perms) = a.LUWithPermutationsLegacy();
                var x = NdArray.CreateMutable(new T[b.Shape[0]]);
                SolveCore(l, u, perms, b, x);
                return(x.MoveToImmutable());
            }
            if (b.Rank == 2 && b.Shape[0] == a.Shape[0])
            {
                var(l, u, perms) = a.LUWithPermutationsLegacy();
                var x   = NdArray.CreateMutable(new T[b.Shape[0], b.Shape[1]]);
                var col = b.Shape[1];
                for (var j = 0; j < col; ++j)
                {
                    var bj = b[Range.Whole, new Index(j, false)];
                    var xj = x[Range.Whole, new Index(j, false)];
                    SolveCore(l, u, perms, bj, xj);
                }
                return(x.MoveToImmutable());
            }

            Guard.ThrowShapeMismatch("(b.Rank == 1 || b.Rank == 2) && b.Shape[0] == a.Shape[0]");
            throw new NotSupportedException();
        }
        /// <summary>
        ///     Calculates a matrix determinant.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ndArray"></param>
        /// <param name="strategy"></param>
        /// <returns></returns>
        public static T Determinant <T>(this INdArray <T> ndArray, IIterationStrategy?strategy = default)
        {
            Guard.AssertShapeMatch(ndArray.Shape.Length == 2 && ndArray.Shape[0] == ndArray.Shape[1],
                                   "x must be a square matrix.");

            var(_, u, permutations) = ndArray.LUWithPermutationsLegacy(strategy);
            var n = ndArray.Shape[0];
            var x = One <T>();

            for (var i = 0; i < n; ++i)
            {
                x = Multiply(x, u[i, i]);
            }
            if (permutations.Count % 2 == 1)
            {
                x = UnaryNegate(x);
            }
            return(x);
        }