Ejemplo n.º 1
0
        /// <summary>
        /// Gets coordinates of vectors with respect to a new basis
        /// given the coordinates
        /// with respect to another basis.
        /// </summary>
        /// <param name="newBasis">
        /// The basis which the new coordinates must be
        /// referred to.
        /// </param>
        /// <param name="currentCoordinates">
        /// The current coordinates.
        /// </param>
        /// <param name="currentBasis">
        /// The current basis.
        /// </param>
        /// <remarks>
        /// <para>
        /// Each row in <paramref name="currentCoordinates"/> is interpreted as
        /// the coordinates of a point.
        /// Hence, a matrix is returned having the same dimensions of
        /// <paramref name="currentCoordinates"/>, in which the <i>i</i>-th row
        /// represents the
        /// coordinates of the <i>i</i>-th point with respect to the new basis.
        /// </para>
        /// <para>
        /// Let <latex>C</latex> and <latex>N</latex> be the
        /// <see cref="GetBasisMatrix">matrix representations</see>
        /// of <paramref name="currentBasis"/>, and <paramref name="newBasis"/>,
        /// respectively, and let <latex>\bc{C}{X}</latex> be
        /// <paramref name="currentCoordinates"/>, i.e. the
        /// coordinates matrix w.r.t. basis <latex>\basis{C}</latex> of the points
        /// <latex>x_1,\dots,x_n</latex> under study:
        /// <latex mode="display">
        /// \bc{C}{X}=\mx{
        ///    \T{\bc{C}{x_1}} \\
        ///    \vdots  \\
        ///    \T{\bc{C}{x_n}} }.
        /// </latex>
        /// Then
        /// method <see cref="ChangeCoordinates(Basis, DoubleMatrix, Basis)"/>
        /// returns the matrix
        /// <latex mode="display">
        /// \bc{N}{X} = \bc{C}{X}\, \T{C}\, \InvT{N}.
        /// </latex>
        /// </para>
        /// </remarks>
        /// <returns>
        /// A matrix of coordinates in the new basis.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="currentCoordinates"/> is <b>null</b>.<br/>
        /// -or-<br/>
        /// <paramref name="newBasis"/> is <b>null</b>.<br/>
        /// -or-<br/>
        /// <paramref name="currentBasis"/> is <b>null</b>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// The <see cref="Dimension"/> of
        /// <paramref name="currentBasis"/> is
        /// not equal to the dimension of <paramref name="newBasis"/>.<br/>
        /// -or-<br/>
        /// The number of columns of <paramref name="currentCoordinates"/> is
        /// not equal to the <see cref="Dimension"/>
        /// of <paramref name="newBasis"/>.
        /// </exception>
        public static DoubleMatrix ChangeCoordinates(Basis newBasis,
                                                     DoubleMatrix currentCoordinates, Basis currentBasis)
        {
            #region Input validation

            if (newBasis is null)
            {
                throw new ArgumentNullException(nameof(newBasis));
            }

            if (currentCoordinates is null)
            {
                throw new ArgumentNullException(nameof(currentCoordinates));
            }

            if (currentBasis is null)
            {
                throw new ArgumentNullException(nameof(currentBasis));
            }

            int k = newBasis.Dimension;

            if (currentBasis.Dimension != k)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(newBasis),
                          ImplementationServices.GetResourceString(
                              "STR_EXCEPT_PAR_BASES_MUST_SHARE_DIMENSION"));
            }

            if (currentCoordinates.NumberOfColumns != k)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(currentCoordinates),
                          ImplementationServices.GetResourceString(
                              "STR_EXCEPT_PAR_MUST_BE_BASIS_COMPLIANT_MATRIX"));
            }

            #endregion

            return(currentCoordinates *
                   currentBasis.basisMatrixT / newBasis.basisMatrixT);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Cloud"/> class
        /// that contains points having the specified weights and whose
        /// coordinates are taken with respect to the given basis, with
        /// coordinates and weights eventually copied before instantiation.
        /// </summary>
        /// <param name="coordinates">
        /// The coordinates of the cloud points.</param>
        /// <param name="weights">
        /// The weights of the cloud points.</param>
        /// <param name="basis">
        /// The basis which the point coordinates are
        /// referred to.</param>
        /// <param name="copyData">
        /// <c>true</c> if <paramref name="coordinates"/> and <paramref name="weights"/>
        /// must be copied before instantiation; otherwise <c>false</c>.
        /// </param>
        /// <remarks>
        /// <para>
        /// Matrix <paramref name="coordinates"/> has as many rows as the
        /// number of points in the cloud.
        /// The number of columns is the dimension of the space in which
        /// the points lie.
        /// </para>
        /// <para>
        /// Each row represents the coordinates of a given point in the
        /// cloud. Points are thus well ordered, and hence thoroughly
        /// identified, by the index of the row in which its coordinates
        /// are stored.
        /// As a consequence, the same order must be followed
        /// when inserting entries in the vector of weights.
        /// </para>
        /// <para>
        /// The <see cref="Cloud(DoubleMatrix, DoubleMatrix, Basis, bool)"/>
        /// constructor prevents the copy
        /// of the elements in <paramref name="coordinates"/> and
        /// <paramref name="weights"/> before instantiation
        /// if <paramref name="copyData"/> evaluates to <c>false</c>: the
        /// returned <see cref="Cloud"/> instance will instead use a direct
        /// reference to <paramref name="coordinates"/> and <paramref name="weights"/>.
        /// </para>
        /// <para>
        /// <note type="caution">
        /// This constructor is intended for advanced users and must always be used
        /// carefully.
        /// Do not use this constructor if you do not have complete control of
        /// the <paramref name="coordinates"/> and <paramref name="weights"/> instances.
        /// Once such instances are passed to the constructor as arguments, they must be
        /// treated as read-only objects outside the returned <see cref="Cloud"/> instance:
        /// you shouldn't manipulate entries via
        /// a direct reference to <paramref name="coordinates"/> or <paramref name="weights"/>;
        /// otherwise, the
        /// behavior of the returned <see cref="Cloud"/> instance
        /// must be considered as undefined and
        /// almost surely prone to errors.
        /// </note>
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="coordinates"/> is <b>null</b>.<br/>
        /// -or-<br/>
        /// <paramref name="weights"/> is <b>null</b>.<br/>
        /// -or-<br/>
        /// <paramref name="basis"/> is <b>null</b>.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <paramref name="weights"/> is not a column vector.<br/>
        /// -or-<br/>
        /// <paramref name="coordinates"/>
        /// and <paramref name="weights"/> have unequal numbers of rows.<br/>
        /// -or-<br/>
        /// The <see cref="Basis.Dimension"/> of <paramref name="basis"/>
        /// is not equal to the number of columns
        /// of <paramref name="coordinates"/>.
        /// </exception>
        public Cloud(
            DoubleMatrix coordinates,
            DoubleMatrix weights,
            Basis basis,
            bool copyData)
        {
            #region Input validation

            if (coordinates is null)
            {
                throw new ArgumentNullException(nameof(coordinates));
            }

            if (weights is null)
            {
                throw new ArgumentNullException(nameof(weights));
            }

            if (basis is null)
            {
                throw new ArgumentNullException(nameof(basis));
            }

            if (!weights.IsColumnVector)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(weights),
                          ImplementationServices.GetResourceString(
                              "STR_EXCEPT_PAR_MUST_BE_COLUMN_VECTOR"));
            }

            int n = coordinates.NumberOfRows;

            if (weights.NumberOfRows != n)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(weights),
                          string.Format(
                              CultureInfo.InvariantCulture,
                              ImplementationServices.GetResourceString(
                                  "STR_EXCEPT_PAR_MUST_HAVE_SAME_NUM_OF_ROWS"),
                              nameof(coordinates)));
            }

            double sum = 0.0, weight;
            for (int i = 0; i < weights.Count; i++)
            {
                weight = weights[i];
                if (weight < 0)
                {
                    throw new ArgumentOutOfRangeException(
                              nameof(weights),
                              ImplementationServices.GetResourceString(
                                  "STR_EXCEPT_PAR_ENTRIES_MUST_BE_NON_NEGATIVE"));
                }
                sum += weight;
            }

            if (Math.Abs(sum - 1.0) > 1.0e-3)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(weights),
                          ImplementationServices.GetResourceString(
                              "STR_EXCEPT_PAR_ENTRIES_MUST_SUM_TO_1"));
            }

            int k = coordinates.NumberOfColumns;

            if (basis.Dimension != k)
            {
                throw new ArgumentOutOfRangeException(
                          nameof(basis),
                          string.Format(
                              CultureInfo.InvariantCulture,
                              ImplementationServices.GetResourceString(
                                  "STR_EXCEPT_PAR_MUST_HAVE_SAME_NUM_OF_COLUMNS"),
                              nameof(coordinates)));
            }

            #endregion

            if (copyData)
            {
                this.coordinates = coordinates.Clone();
                this.weights     = weights.Clone();
            }
            else
            {
                this.coordinates = coordinates;
                this.weights     = weights;
            }
            this.Basis = basis;

            #region Statistics

            // Mean
            var w_s    = this.weights;
            var x_sa   = this.coordinates;
            var m_sa_t = w_s.Transpose() * x_sa;
            this.Mean = m_sa_t.AsReadOnly();

            // Variance
            var          m_sa     = m_sa_t.Transpose();
            var          q_a      = this.Basis.basisScalarProducts;
            var          variance = 0.0;
            DoubleMatrix coords;
            for (int i = 0; i < w_s.Count; i++)
            {
                coords    = x_sa[i, ":"];
                variance += w_s[i] * (coords * q_a * coords.Transpose())[0];
            }
            variance     -= (m_sa_t * q_a * m_sa)[0];
            this.Variance = variance;

            // Covariance
            var diag_w_s = DoubleMatrix.Diagonal(w_s);
            var x_sa_t   = x_sa.Transpose();
            this.Covariance = ((x_sa_t * diag_w_s * x_sa)
                               - (m_sa * m_sa_t)).AsReadOnly();

            #endregion
        }