Exemplo n.º 1
0
//		public static double ClosestIndexFromLine(DoubleVector3 point, DoubleVector3 LinePt0, DoubleVector3 LinePt1)
//		{
//			//     Q (query)
//			//    /|\
//			//   / | \
//			//  /  |  \
//			// /---+---\
//			// A   T   B
//			//
//			// AQ . AB = |AQ| * |AB| * cos(QAB)
//			// cos(QAB) = |AT| / |AQ|
//			// |AT| / |AB| = AQ . AB / |AB|^2
//			DoubleVector3 P = point;
//			DoubleVector3 A = LinePt0;
//			DoubleVector3 B = LinePt1;
//
//			DoubleVector3 AP = P - A;
//			DoubleVector3 AB = B - A;
//			double ab2   = AB.Length2;
//			if(ab2 == 0)
//				return 0;
//			double ap_ab = DoubleVector3.InnerProduct(AP, AB);
//			double t = ap_ab / ab2;
//			return t;
//		}
//		public static double IndexSegmentClosestToLine(Segment segment, Line line)
//		{
//			// 1. find the plane containing line and point which is the closest on the segment
//			DoubleVector3 orthogonal_line_segment = DoubleVector3.CrossProduct(segment.Direct, line.Normal);
//			DoubleVector3 normal_plane = DoubleVector3.CrossProduct(orthogonal_line_segment, line.Normal).UnitVector;
//			Plane plane = new Plane(line.Base, normal_plane);
//			// 2. fine index of segment intersecting the plane
//			double index = IndexSegmentIntersectingPlane(segment, plane);
//			//Debug.Assert(DoubleVector3.InnerProduct(segment[index]-))
//			if(Debug.IsDebuggerAttached)
//			{
//				double dist_pt2line = DistancePointLine(segment[index],line);
//				double dist_line2line = DistanceLineLine(line, segment.ToLine());
//				Debug.AssertSimilar(dist_pt2line, dist_line2line, 0.000000001);
//			}
//			return index;
//		}
//		public static double[] IndexSegmentToLineByDistance(Segment segment, Line line, double distance)
//		{
//			double dist_lineline = DistanceLineLine(line, segment.ToLine());
//			if(dist_lineline > distance)
//				return null;
//			double index = IndexSegmentClosestToLine(segment, line);
//			if(dist_lineline == distance)
//				return new double[1] { index };
//			double dist_more = Math.Sqrt(distance*distance + dist_lineline*dist_lineline);
//			double angle_segment_line = DoubleVector3.AngleBetween(segment.Direct, line.Normal).Radian;
//			double index_dist = (dist_more / Math.Atan(angle_segment_line)) / segment.Direct.Length;
//			Debug.Assert(DistancePointLine(segment[index+index_dist], line) > distance);
//			Func<double,double> funcdist = delegate(double t) { return DistancePointLine(segment[t], line); };
//			Pair<bool,double> index_dist2 = RootsBisection.Root(funcdist, index, index+index_dist);
//			Debug.Assert(index_dist2.first == true);
//			double[] indexes = new double[2] { index-index_dist2.second, index+index_dist2.second };
//			if(Debug.IsDebuggerAttached)
//			{
//				DoubleVector3 pt1 = segment[indexes[0]];
//				DoubleVector3 pt2 = segment[indexes[1]];
//				Debug.AssertSimilar(distance, DistancePointLine(pt1, line), 0.00000001);
//				Debug.AssertSimilar(distance, DistancePointLine(pt2, line), 0.00000001);
//			}
//			return indexes;
//		}
//		public static double IndexSegmentIntersectingPlane(Segment segment, Plane plane)
//		{
//			// http://softsurfer.com/Archive/algorithm_0104/algorithm_0104B.htm
//			// s = -n.w / n.u
//			double dist = -1 * DoubleVector3.InnerProduct(plane.Normal, segment.Base-plane.Base)
//							 / DoubleVector3.InnerProduct(plane.Normal, segment.Direct);
//			Debug.Assert(plane.DistanceFrom(segment[dist]) < 0.00000001);
//			return dist;
//			//// index of segment which intersecting plane
//			//// if index is in [0,1], the segment intersects plane
//			//// otherwise, it is outside of plane
//			//if(DoubleVector3.InnerProduct(segment.Direct, plane.Normal) == 0)
//			//    return double.NaN;
//			//double dist = DistancePointPlane(segment.Base, plane);
//			//DoubleVector3 point2plane = -1*Math.Sign(dist)*plane.Normal;
//			//double sin = DoubleVector3.CrossProduct(point2plane, segment.Direct.UnitVector).Length;
//			//double cos = DoubleVector3.InnerProduct(point2plane, segment.Direct.UnitVector);
//			//double sign = (cos >=0) ? 1 : -1;
//			//double unitlength = sign * sin * segment.Direct.Length;
//			//return dist/unitlength;
//		}
//		public static double IndexSegmentIntersectingTriangle(Segment segment, DoubleVector3 tri0, DoubleVector3 tri1, DoubleVector3 tri2)
//		{
//			// return [0,1] if the segement intersects triangle
//			// return (-inf,0) or (1,inf) if the line of segment intersects the triangle
//			// return double.NegativeInfinity or double.PositiveInfinity if line does not intersects the triangle
//			double index = IndexSegmentIntersectingPlane(segment, ToPlane(tri0, tri1, tri2));
//			bool ptInTriangle = CheckPointInTriangle(segment[index], tri0, tri1, tri2);
//			if(ptInTriangle == true)
//				return index;
//			if(index >= 0)
//				return double.PositiveInfinity;
//			if(index < 0)
//				return double.NegativeInfinity;
//			return double.NaN;
//		}

        public static double IndexSegmentClosestPoint(Segment segment, Vector point)
        {
            // http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
            // t = - (x1 - x0) . (x2 - x1 ) / |x2-x1|^2
            Vector x1    = segment.PtFrom;
            Vector x2    = segment.PtTo;
            Vector x0    = point;
            double index = -1 * LinAlg.DotProd(x1 - x0, x2 - x1) / (x2 - x1).Dist2;

            if (HDebug.IsDebuggerAttached)
            {
                // check orthogonal
                Vector ortho = (point - segment[index]);
                HDebug.Assert(LinAlg.DotProd(ortho, segment.Direct) < 0.00000001);
                // check closestness
                double dist  = (point - segment[index]).Dist;
                double dist1 = (point - segment[index - 0.001]).Dist;
                double dist2 = (point - segment[index + 0.001]).Dist;
                HDebug.Assert(dist <= dist1);
                HDebug.Assert(dist <= dist2);
            }
            return(index);
        }
Exemplo n.º 2
0
        public static double DistancePointLine(Vector point, Vector line1, Vector line2)
        {
            // http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
            if (DistancePointLine_selftest)
            {
                DistancePointLine_selftest = false;
                Vector tp     = new Vector(2, 2, 0);
                Vector tl1    = new Vector(0, 0, -20);
                Vector tl2    = new Vector(0, 0, -10);
                double tdist0 = tp.Dist;
                double tdist1 = DistancePointLine(tp, tl1, tl2);
                double tdist2 = (ClosestPointOnLine(tl1, tl2, tp, false) - tp).Dist;
                HDebug.AssertTolerance(0.00000001, tdist0 - tdist1);
                HDebug.AssertTolerance(0.00000001, tdist0 - tdist2);
            }
            Vector x21 = line2 - line1;
            Vector x10 = line1 - point;
            double dist
                = LinAlg.CrossProd(x21, x10).Dist
                  / x21.Dist;

            return(dist);
        }
Exemplo n.º 3
0
        public static MatrixByArr InvSymm(MatrixByArr A)
        {
            if (HDebug.Selftest())
            {
                MatrixByArr tA = new double[, ] {
                    { 1, 2, 3 },
                    { 2, 9, 5 },
                    { 3, 5, 6 }
                };
                MatrixByArr tB0 = new double[, ] {
                    { -1.8125, -0.1875, 1.0625 },
                    { -0.1875, 0.1875, -0.0625 },
                    { 1.0625, -0.0625, -0.3125 }
                };
                MatrixByArr tI = LinAlg.Eye(3);

                MatrixByArr tB1 = InvSymm(tA);

                HDebug.AssertTolerance(0.0001, tB0 - tB1);
                HDebug.AssertTolerance(0.0001, tI - tA * tB1);
                HDebug.AssertTolerance(0.0001, tI - tB1 * tA);
            }

            HDebug.Assert(A.ColSize == A.RowSize);
            //double[] eigval;
            //double[,] eigvec;

            bool success = false;//alglib.smatrixevd(A, A.ColSize, 1, false, out eigval, out eigvec);

            if (success == false)
            {
                HDebug.Assert(false);
                return(null);
            }
            HDebug.Assert(false);
            return(null);
        }
Exemplo n.º 4
0
        static double Dist2PointLine(Vector point, Vector line0, Vector line1)
        {
            /// Squared distance from a point
            /// http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
            ///
            /// (line0) x1-----+--------x2 (line1)
            ///                |
            ///                | d
            ///                x0 (point)
            Vector x1    = line0;
            Vector x2    = line1;
            Vector x0    = point;
            double d21   = (x2 - x1).Dist; HDebug.Assert(d21 != 0);
            double d10   = (x1 - x0).Dist;
            double d1021 = LinAlg.DotProd(x1 - x0, x2 - x1);
            double dist2 = ((d10 * d10 * d21 * d21) - d1021 * d1021) / (d21 * d21);

            if ((0 > dist2) && (dist2 > -0.0000000001))
            {
                // consider this as the precision problem by numerical error
                dist2 = 0;
            }
            return(dist2);
        }
        public static Vector Point4IntersectSegmentPlane(Vector plane1, Vector plane2, Vector plane3, Vector segment1, Vector segment2, double tolerance = 0.00001)
        {
            /// return intersection point between plane (by p1, p2, p3) and line semgnet (seg1, seg2).
            /// If the line segment does not pass through the plane, return null

            Vector point = Point4LinePlaneIntersect(plane1, plane2, plane3, segment1, segment2);

            Vector vec12  = (segment2 - segment1);
            Vector uvec12 = vec12.UnitVector();
            double leng12 = vec12.Dist;
            Vector vec1p  = (point - segment1);
            double t      = LinAlg.VtV(uvec12, vec1p);

            tolerance = Math.Abs(tolerance);
            if (t < -tolerance)
            {
                point = null;                      // smaller than 0
            }
            if (t > leng12 + tolerance)
            {
                point = null;                      // larger  than leng12
            }
            return(point);
        }
        public static Tuple <double, Vector> MaxSphereBetweenSpheres(Vector pt1, double rad1,
                                                                     Vector pt2, double rad2,
                                                                     Vector pt3, double rad3,
                                                                     Vector pt4, double rad4)
        {
            if (MaxSphereBetweenSpheres_SelfTest)
            {
                MaxSphereBetweenSpheres_SelfTest = false;
                Vector tpo = new double[] { 0 + 1, 0 + 2, 0 + 3 }; double tro = 0.10;
                Vector tpa = new double[] { 1 + 1, 2 + 2, 3 + 3 }; double tra = 0.20;
                Vector tpb = new double[] { 5 + 1, 3 + 2, 2 + 3 }; double trb = 0.30;
                Vector tpc = new double[] { 3 + 1, 3 + 2, 3 + 3 }; double trc = 0.15;

                var test_rad_cent = MaxSphereBetweenSpheres(tpo, tro,
                                                            tpa, tra,
                                                            tpb, trb,
                                                            tpc, trc
                                                            );
                double radius = test_rad_cent.Item1;
                Vector center = test_rad_cent.Item2;
                HDebug.AssertTolerance(0.00000001, radius - ((center - tpo).Dist - tro));
                HDebug.AssertTolerance(0.00000001, radius - ((center - tpa).Dist - tra));
                HDebug.AssertTolerance(0.00000001, radius - ((center - tpb).Dist - trb));
                HDebug.AssertTolerance(0.00000001, radius - ((center - tpc).Dist - trc));
            }

            Vector po = pt1 - pt1; double po2 = po.Dist2; double ro = rad1; double ro2 = ro * ro;
            Vector pa = pt2 - pt1; double pa2 = pa.Dist2; double ra = rad2; double ra2 = ra * ra;
            Vector pb = pt3 - pt1; double pb2 = pb.Dist2; double rb = rad3; double rb2 = rb * rb;
            Vector pc = pt4 - pt1; double pc2 = pc.Dist2; double rc = rad4; double rc2 = rc * rc;

            double alpah_ab = (ro2 - ra2 + pa2) * (rb - ro) - (ro2 - rb2 + pb2) * (ra - ro);
            double alpah_bc = (ro2 - rb2 + pb2) * (rc - ro) - (ro2 - rc2 + pc2) * (rb - ro);
            Vector beta_ab  = (pa2 - (ro - ra) * (ro - ra)) * pb - (pb2 - (ro - rb) * (ro - rb)) * pa;
            Vector beta_bc  = (pb2 - (ro - rb) * (ro - rb)) * pc - (pc2 - (ro - rc) * (ro - rc)) * pb;

            double n_alpah_ab = alpah_ab / beta_ab.Dist; Vector n_beta_ab = beta_ab.UnitVector();
            double n_alpah_bc = alpah_bc / beta_bc.Dist; Vector n_beta_bc = beta_bc.UnitVector();

            var line_pt_vec = Geometry.LineOnTwoPlanes(n_beta_ab, n_alpah_ab,
                                                       n_beta_bc, n_alpah_bc);
            Vector gamma = line_pt_vec.Item1;
            Vector delta = line_pt_vec.Item2;

            double a = delta.Dist2;
            double b = 2 * LinAlg.VtV(gamma, delta);
            double c = gamma.Dist2 - 1;

            double[] roots = HRoots.GetRootsClosedFormDegree2(a, b, c);

            foreach (double root in roots)
            {
                Vector q      = gamma + root * delta;
                double pa_q   = LinAlg.VtV(pa, q);
                double radius = (ro2 - ra2 + pa2 - 2 * ro * pa_q) / (2 * (ra - ro + pa_q));
                if (radius < 0)
                {
                    continue;
                }
                Vector center = (ro + radius) * q;

                HDebug.AssertTolerance(0.00000001, radius - ((center - po).Dist - ro));
                HDebug.AssertTolerance(0.00000001, radius - ((center - pa).Dist - ra));
                HDebug.AssertTolerance(0.00000001, radius - ((center - pb).Dist - rb));
                HDebug.AssertTolerance(0.00000001, radius - ((center - pc).Dist - rc));

                HDebug.AssertTolerance(0.00000001, radius - ((center + pt1 - pt1).Dist - rad1));
                HDebug.AssertTolerance(0.00000001, radius - ((center + pt1 - pt2).Dist - rad2));
                HDebug.AssertTolerance(0.00000001, radius - ((center + pt1 - pt3).Dist - rad3));
                HDebug.AssertTolerance(0.00000001, radius - ((center + pt1 - pt4).Dist - rad4));

                return(new Tuple <double, Vector>(radius, center + pt1));
            }
            HDebug.Assert(roots == null);
            return(null);
        }
        public static Tuple <double, Vector, bool> MaxCircleBetweenCircles(Vector pt1, double rad1,
                                                                           Vector pt2, double rad2,
                                                                           Vector pt3, double rad3)
        {
            ///        b:pt3
            ///        /   \
            ///      /      \
            ///    /         \
            /// o:pt1 ------ a:pt2
            ///
            /// o : (0  ,   0), radii ro
            /// a : (pax,   0), radii ra
            /// b : (pbx, pby), radii rb

            Vector uvec12 = (pt2 - pt1).UnitVector();
            Vector uvec23 = (pt3 - pt2).UnitVector();
            Vector uvec31 = (pt1 - pt3).UnitVector();
            double cos123 = LinAlg.VtV(-uvec12, uvec23);
            double cos231 = LinAlg.VtV(-uvec23, uvec31);
            double cos312 = LinAlg.VtV(-uvec31, uvec12);

            double cos_aob;
            double ro, ra, rb;
            Vector po, pa, pb;

            if (cos123 > 0)
            {
                pa = pt1; ra = rad1; po = pt2; ro = rad2; pb = pt3; rb = rad3; cos_aob = cos123;
            }
            else if (cos231 > 0)
            {
                pa = pt2; ra = rad2; po = pt3; ro = rad3; pb = pt1; rb = rad1; cos_aob = cos231;
            }
            else if (cos312 > 0)
            {
                pa = pt2; ra = rad2; po = pt1; ro = rad1; pb = pt3; rb = rad3; cos_aob = cos312;
            }
            else
            {
                throw new Exception("cos123>0 and cos231>0");
            }

            Vector uvec_oa = (pa - po).UnitVector();
            Vector uvec_ob = (pb - po).UnitVector();
            Vector normal  = LinAlg.CrossProd(uvec_oa, uvec_ob);
            double sin_aob = normal.Dist;

            double pax = (pa - po).Dist;
            double pbx = (pb - po).Dist * cos_aob;
            double pby = (pb - po).Dist * sin_aob;
            Trans3 trans;
            {
                Vector npo = new double[] { 0, 0, 0 };
                Vector npa = new double[] { 0, pax, 0 };
                Vector npb = new double[] { 0, pbx, pby };
                trans = Trans3.GetTransformNoScale(npo, npa, npb, po, pa, pb);
                if (HDebug.IsDebuggerAttached)
                {
                    Vector pox = trans.DoTransform(npo);
                    HDebug.AssertTolerance(0.0000001, po - trans.DoTransform(npo));
                    HDebug.AssertTolerance(0.0000001, pa - trans.DoTransform(npa));
                    HDebug.AssertTolerance(0.0000001, pb - trans.DoTransform(npb));
                }
            }

            Tuple <double, Vector, bool> rad_cent_in = MaxCircleBetweenCircles(ro, ra, rb, pax, pbx, pby);

            if (rad_cent_in == null)
            {
                return(null);
            }
            double radius          = rad_cent_in.Item1;
            bool   cenerInTriangle = rad_cent_in.Item3;

            Vector center;

            {
                HDebug.Assert(rad_cent_in.Item2.Size == 2);
                center = new double[] { 0, rad_cent_in.Item2[0], rad_cent_in.Item2[1] };
                center = trans.DoTransform(center);
            }
            if (HDebug.IsDebuggerAttached)
            {
                double radx_1 = (center - pt1).Dist - rad1;
                double radx_2 = (center - pt2).Dist - rad2;
                double radx_3 = (center - pt3).Dist - rad3;
                HDebug.AssertTolerance(0.000001, radx_1 - radx_2, radx_2 - radx_3, radx_3 - radx_1);
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt1 - pt2));
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt2 - pt3));
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt3 - pt1));
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt1 - center));
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt2 - center));
                HDebug.AssertTolerance(0.00000001, LinAlg.VtV(normal, pt3 - center));
            }

            return(new Tuple <double, Vector, bool>(radius, center, cenerInTriangle));
        }
Exemplo n.º 8
0
        static public MatrixByArr Inv3x3(MatrixByArr _this)
        {
            if (HDebug.Selftest())
            {
                MatrixByArr tA = new double[, ] {
                    { 1, 2, 3 },
                    { 2, 9, 5 },
                    { 3, 5, 6 }
                };
                MatrixByArr tB0 = new double[, ] {
                    { -1.8125, -0.1875, 1.0625 },
                    { -0.1875, 0.1875, -0.0625 },
                    { 1.0625, -0.0625, -0.3125 }
                };
                MatrixByArr tI = LinAlg.Eye(3);

                MatrixByArr tB1 = Inv3x3(tA);

                HDebug.AssertTolerance(0.0001, tB0 - tB1);
                HDebug.AssertTolerance(0.0001, tI - tA * tB1);
                HDebug.AssertTolerance(0.0001, tI - tB1 * tA);
            }

            // http://www.cvl.iis.u-tokyo.ac.jp/~miyazaki/tech/teche23.html
            if (_this.RowSize != 3 || _this.ColSize != 3)
            {
                return(null);
            }

            double a11  = _this[0, 0];
            double a12  = _this[0, 1];
            double a13  = _this[0, 2];
            double a21  = _this[1, 0];
            double a22  = _this[1, 1];
            double a23  = _this[1, 2];
            double a31  = _this[2, 0];
            double a32  = _this[2, 1];
            double a33  = _this[2, 2];
            double detA = a11 * a22 * a33 + a21 * a32 * a13 + a31 * a12 * a23
                          - a11 * a32 * a23 - a31 * a22 * a13 - a21 * a12 * a33;

            MatrixByArr inv = new MatrixByArr(3, 3);

            inv[0, 0] = a22 * a33 - a23 * a32;
            inv[0, 1] = a13 * a32 - a12 * a33;
            inv[0, 2] = a12 * a23 - a13 * a22;
            inv[1, 0] = a23 * a31 - a21 * a33;
            inv[1, 1] = a11 * a33 - a13 * a31;
            inv[1, 2] = a13 * a21 - a11 * a23;
            inv[2, 0] = a21 * a32 - a22 * a31;
            inv[2, 1] = a12 * a31 - a11 * a32;
            inv[2, 2] = a11 * a22 - a12 * a21;
            inv      /= detA;

            if (HDebug.IsDebuggerAttached)
            {
                MatrixByArr I33 = _this * inv;
                for (int r = 0; r < 3; r++)
                {
                    for (int c = 0; c < 3; c++)
                    {
                        if (r == c)
                        {
                            Debug.Assert(Math.Abs(I33[r, c] - 1) < 0.00001);
                        }
                        else
                        {
                            Debug.Assert(Math.Abs(I33[r, c] - 0) < 0.00001);
                        }
                    }
                }
                I33 = inv * _this;
                for (int r = 0; r < 3; r++)
                {
                    for (int c = 0; c < 3; c++)
                    {
                        if (r == c)
                        {
                            Debug.Assert(Math.Abs(I33[r, c] - 1) < 0.00001);
                        }
                        else
                        {
                            Debug.Assert(Math.Abs(I33[r, c] - 0) < 0.00001);
                        }
                    }
                }
            }
            return(inv);
        }
Exemplo n.º 9
0
        static public MatrixByArr Inv4x4(MatrixByArr _this)
        {
            if (HDebug.Selftest())
            {
                /// >> A=[ 1,2,3,4 ; 5,7,9,10 ; 13,24,52,14 ; 12,43,73,28 ]
                /// >> invA = inv(A)
                ///    -0.5599    0.2942    0.0557   -0.0529
                ///    -0.8416    0.2638   -0.1128    0.0824
                ///     0.3886   -0.1754    0.0576   -0.0216
                ///     0.5193   -0.0739   -0.0007   -0.0117
                /// >> A*invA
                ///     1.0000    0.0000         0   -0.0000
                ///    -0.0000    1.0000   -0.0000    0.0000
                ///          0    0.0000    1.0000    0.0000
                ///          0    0.0000    0.0000    1.0000
                MatrixByArr _A = new double[4, 4] {
                    { 1, 2, 3, 4 }, { 5, 7, 9, 10 }, { 13, 24, 52, 14 }, { 12, 43, 73, 28 }
                };
                MatrixByArr _invA_sol = new double[4, 4]
                {
                    { -0.5599, 0.2942, 0.0557, -0.0529 }
                    , { -0.8416, 0.2638, -0.1128, 0.0824 }
                    , { 0.3886, -0.1754, 0.0576, -0.0216 }
                    , { 0.5193, -0.0739, -0.0007, -0.0117 }
                };
                MatrixByArr _invA = Inv4x4(_A);

                double err1 = (_invA - _invA_sol).HAbsMax();
                HDebug.Assert(err1 < 0.0001);

                MatrixByArr _I     = LinAlg.Eye(4);
                MatrixByArr _AinvA = _A * _invA;
                double      err2   = (_I - _AinvA).HAbsMax();
                HDebug.Assert(err2 < 0.000000001);

                MatrixByArr _invAA = _invA * _A;
                double      err3   = (_I - _invAA).HAbsMax();
                HDebug.Assert(err3 < 0.000000001);
            }

            //////////////////////////////////////////////////////////////////////////
            // http://www.koders.com/cpp/fidFB7C4F93FDDB86E33EB66D177335BA81D86E58B5.aspx
            // Matrix.cpp
            // bool idMat4::InverseFastSelf( void )
            //////////////////////////////////////////////////////////////////////////
            //  //	6*8+2*6 = 60 multiplications
            //  //		2*1 =  2 divisions
            //  idMat2 r0, r1, r2, r3;
            //  float a, det, invDet;
            //  float *mat = reinterpret_cast<float *>(this);
            //
            //  // r0 = m0.Inverse();
            //  det = mat[0*4+0] * mat[1*4+1] - mat[0*4+1] * mat[1*4+0];
            //
            //  if ( idMath::Fabs( det ) < MATRIX_INVERSE_EPSILON ) {
            //      return false;
            //  }
            //
            //  invDet = 1.0f / det;
            //
            //  r0[0][0] =   mat[1*4+1] * invDet;
            //  r0[0][1] = - mat[0*4+1] * invDet;
            //  r0[1][0] = - mat[1*4+0] * invDet;
            //  r0[1][1] =   mat[0*4+0] * invDet;
            //
            //  // r1 = r0 * m1;
            //  r1[0][0] = r0[0][0] * mat[0*4+2] + r0[0][1] * mat[1*4+2];
            //  r1[0][1] = r0[0][0] * mat[0*4+3] + r0[0][1] * mat[1*4+3];
            //  r1[1][0] = r0[1][0] * mat[0*4+2] + r0[1][1] * mat[1*4+2];
            //  r1[1][1] = r0[1][0] * mat[0*4+3] + r0[1][1] * mat[1*4+3];
            //
            //  // r2 = m2 * r1;
            //  r2[0][0] = mat[2*4+0] * r1[0][0] + mat[2*4+1] * r1[1][0];
            //  r2[0][1] = mat[2*4+0] * r1[0][1] + mat[2*4+1] * r1[1][1];
            //  r2[1][0] = mat[3*4+0] * r1[0][0] + mat[3*4+1] * r1[1][0];
            //  r2[1][1] = mat[3*4+0] * r1[0][1] + mat[3*4+1] * r1[1][1];
            //
            //  // r3 = r2 - m3;
            //  r3[0][0] = r2[0][0] - mat[2*4+2];
            //  r3[0][1] = r2[0][1] - mat[2*4+3];
            //  r3[1][0] = r2[1][0] - mat[3*4+2];
            //  r3[1][1] = r2[1][1] - mat[3*4+3];
            //
            //  // r3.InverseSelf();
            //  det = r3[0][0] * r3[1][1] - r3[0][1] * r3[1][0];
            //
            //  if ( idMath::Fabs( det ) < MATRIX_INVERSE_EPSILON ) {
            //      return false;
            //  }
            //
            //  invDet = 1.0f / det;
            //
            //  a = r3[0][0];
            //  r3[0][0] =   r3[1][1] * invDet;
            //  r3[0][1] = - r3[0][1] * invDet;
            //  r3[1][0] = - r3[1][0] * invDet;
            //  r3[1][1] =   a * invDet;
            //
            //  // r2 = m2 * r0;
            //  r2[0][0] = mat[2*4+0] * r0[0][0] + mat[2*4+1] * r0[1][0];
            //  r2[0][1] = mat[2*4+0] * r0[0][1] + mat[2*4+1] * r0[1][1];
            //  r2[1][0] = mat[3*4+0] * r0[0][0] + mat[3*4+1] * r0[1][0];
            //  r2[1][1] = mat[3*4+0] * r0[0][1] + mat[3*4+1] * r0[1][1];
            //
            //  // m2 = r3 * r2;
            //  mat[2*4+0] = r3[0][0] * r2[0][0] + r3[0][1] * r2[1][0];
            //  mat[2*4+1] = r3[0][0] * r2[0][1] + r3[0][1] * r2[1][1];
            //  mat[3*4+0] = r3[1][0] * r2[0][0] + r3[1][1] * r2[1][0];
            //  mat[3*4+1] = r3[1][0] * r2[0][1] + r3[1][1] * r2[1][1];
            //
            //  // m0 = r0 - r1 * m2;
            //  mat[0*4+0] = r0[0][0] - r1[0][0] * mat[2*4+0] - r1[0][1] * mat[3*4+0];
            //  mat[0*4+1] = r0[0][1] - r1[0][0] * mat[2*4+1] - r1[0][1] * mat[3*4+1];
            //  mat[1*4+0] = r0[1][0] - r1[1][0] * mat[2*4+0] - r1[1][1] * mat[3*4+0];
            //  mat[1*4+1] = r0[1][1] - r1[1][0] * mat[2*4+1] - r1[1][1] * mat[3*4+1];
            //
            //  // m1 = r1 * r3;
            //  mat[0*4+2] = r1[0][0] * r3[0][0] + r1[0][1] * r3[1][0];
            //  mat[0*4+3] = r1[0][0] * r3[0][1] + r1[0][1] * r3[1][1];
            //  mat[1*4+2] = r1[1][0] * r3[0][0] + r1[1][1] * r3[1][0];
            //  mat[1*4+3] = r1[1][0] * r3[0][1] + r1[1][1] * r3[1][1];
            //
            //  // m3 = -r3;
            //  mat[2*4+2] = -r3[0][0];
            //  mat[2*4+3] = -r3[0][1];
            //  mat[3*4+2] = -r3[1][0];
            //  mat[3*4+3] = -r3[1][1];
            //
            //  return true;

            if (_this.RowSize != 4 || _this.ColSize != 4)
            {
                return(null);
            }

            MatrixByArr  mat = new MatrixByArr(_this);
            const double MATRIX_INVERSE_EPSILON = 0.000000001;

            //	6*8+2*6 = 60 multiplications
            //		2*1 =  2 divisions
            double det, invDet;

            // r0 = m0.Inverse();
            det = mat[0, 0] * mat[1, 1] - mat[0, 1] * mat[1, 0];

            if (Math.Abs(det) < MATRIX_INVERSE_EPSILON)
            {
                Debug.Assert(false);
                return(null);
            }

            invDet = 1.0f / det;

            double r0_00 = mat[1, 1] * invDet;
            double r0_01 = -mat[0, 1] * invDet;
            double r0_10 = -mat[1, 0] * invDet;
            double r0_11 = mat[0, 0] * invDet;

            // r1 = r0 * m1;
            double r1_00 = r0_00 * mat[0, 2] + r0_01 * mat[1, 2];
            double r1_01 = r0_00 * mat[0, 3] + r0_01 * mat[1, 3];
            double r1_10 = r0_10 * mat[0, 2] + r0_11 * mat[1, 2];
            double r1_11 = r0_10 * mat[0, 3] + r0_11 * mat[1, 3];

            // r2 = m2 * r1;
            double r2_00 = mat[2, 0] * r1_00 + mat[2, 1] * r1_10;
            double r2_01 = mat[2, 0] * r1_01 + mat[2, 1] * r1_11;
            double r2_10 = mat[3, 0] * r1_00 + mat[3, 1] * r1_10;
            double r2_11 = mat[3, 0] * r1_01 + mat[3, 1] * r1_11;

            // r3 = r2 - m3;
            double r3_00 = r2_00 - mat[2, 2];
            double r3_01 = r2_01 - mat[2, 3];
            double r3_10 = r2_10 - mat[3, 2];
            double r3_11 = r2_11 - mat[3, 3];

            // r3.InverseSelf();
            det = r3_00 * r3_11 - r3_01 * r3_10;

            if (Math.Abs(det) < MATRIX_INVERSE_EPSILON)
            {
                Debug.Assert(false);
                return(null);
            }

            invDet = 1.0f / det;

            double r3_00_prv = r3_00;

            r3_00 = r3_11 * invDet;
            r3_01 = -r3_01 * invDet;
            r3_10 = -r3_10 * invDet;
            r3_11 = r3_00_prv * invDet;

            // r2 = m2 * r0;
            r2_00 = mat[2, 0] * r0_00 + mat[2, 1] * r0_10;
            r2_01 = mat[2, 0] * r0_01 + mat[2, 1] * r0_11;
            r2_10 = mat[3, 0] * r0_00 + mat[3, 1] * r0_10;
            r2_11 = mat[3, 0] * r0_01 + mat[3, 1] * r0_11;

            // m2 = r3 * r2;
            mat[2, 0] = r3_00 * r2_00 + r3_01 * r2_10;
            mat[2, 1] = r3_00 * r2_01 + r3_01 * r2_11;
            mat[3, 0] = r3_10 * r2_00 + r3_11 * r2_10;
            mat[3, 1] = r3_10 * r2_01 + r3_11 * r2_11;

            // m0 = r0 - r1 * m2;
            mat[0, 0] = r0_00 - r1_00 * mat[2, 0] - r1_01 * mat[3, 0];
            mat[0, 1] = r0_01 - r1_00 * mat[2, 1] - r1_01 * mat[3, 1];
            mat[1, 0] = r0_10 - r1_10 * mat[2, 0] - r1_11 * mat[3, 0];
            mat[1, 1] = r0_11 - r1_10 * mat[2, 1] - r1_11 * mat[3, 1];

            // m1 = r1 * r3;
            mat[0, 2] = r1_00 * r3_00 + r1_01 * r3_10;
            mat[0, 3] = r1_00 * r3_01 + r1_01 * r3_11;
            mat[1, 2] = r1_10 * r3_00 + r1_11 * r3_10;
            mat[1, 3] = r1_10 * r3_01 + r1_11 * r3_11;

            // m3 = -r3;
            mat[2, 2] = -r3_00;
            mat[2, 3] = -r3_01;
            mat[3, 2] = -r3_10;
            mat[3, 3] = -r3_11;

            return(mat);
        }
Exemplo n.º 10
0
            public static void GetTriGeom(Vector pa, Vector pb, Vector pc
                                          , out double a, out double b, out double c
                                          , out double A, out double B, out double C
                                          , out double r
                                          , out Vector po
                                          )
            {
                Func <Vector, Vector, Vector, double> angle2 = delegate(Vector p1, Vector p2, Vector p3)
                {
                    Vector v21  = p1 - p2;
                    Vector v23  = p3 - p2;
                    double d21  = v21.Dist;
                    double d23  = v23.Dist;
                    double cos2 = LinAlg.DotProd(v21, v23) / (d21 * d23);
                    double ang2 = Math.Acos(cos2);
                    return(ang2);
                };
                ////////////////////////////////////////////////////////////////
                //             1     (1,2,3)
                //            /A\      |
                //           / | \     r
                //          c  |  b    |
                //         /   o   \   origin
                //        /B       C\
                //       2-----a-----3
                //
                /////////////////////////////////////////////////////////////////
                // http://schools-wikipedia.org/wp/t/Trigonometric_functions.htm
                // a/sinA = b/sinB = c/sinC = 2R
                Vector pt23 = pb - pc; double dist23 = pt23.Dist;
                Vector pt31 = pc - pa; double dist31 = pt31.Dist;
                Vector pt12 = pa - pb; double dist12 = pt12.Dist;

                a = dist23;             // =(pt2-pt3).Dist; // distance between pt2 and pt3
                b = dist31;             // =(pt3-pt1).Dist; // distance between pt2 and pt3
                c = dist12;             // =(pt1-pt2).Dist; // distance between pt2 and pt3
                A = angle2(pc, pa, pb); // angle A = ∠pt3-pt1(a)-pt2
                B = angle2(pa, pb, pc); // angle B = ∠pt1-pt2(b)-pt3
                C = angle2(pb, pc, pa); // angle C = ∠pt2-pt3(c)-pt1
                r = 0.5 * a / Math.Sin(A);
                // Barycentric coordinates from cross- and dot-products
                // http://en.wikipedia.org/wiki/Circumscribed_circle#Barycentric_coordinates_as_a_function_of_the_side_lengths
                /// po = v1.p1 + v2.p2 + v3.p3
                /// v1 = (|p2-p3|^2 * (p1-p2).(p1-p3)) / (2*|(p1-p2)x(p2-p3)|^2) = a*a*Dot(
                /// v2 = (|p1-p3|^2 * (p2-p1).(p2-p3)) / (2*|(p1-p2)x(p2-p3)|^2) = b*b*Dot(
                /// v3 = (|p1-p2|^2 * (p3-p1).(p3-p2)) / (2*|(p1-p2)x(p2-p3)|^2) = c*c*Dot(
                {
                    double div = 2 * LinAlg.CrossProd(pa - pb, pb - pc).Dist2;
                    double v1  = dist23 * dist23 * LinAlg.DotProd(pt12, -pt31) / div;
                    double v2  = dist31 * dist31 * LinAlg.DotProd(-pt12, pt23) / div;
                    double v3  = dist12 * dist12 * LinAlg.DotProd(pt31, -pt23) / div;
                    po = v1 * pa + v2 * pb + v3 * pc;
                }
                if (HDebug.IsDebuggerAttached)
                {
                    double la, lb, lc;
                    double lA, lB, lC;
                    double lr;
                    Vector lpo;
                    Geometry.GetTriGeom(pa, pb, pc, out la, out lb, out lc, out lA, out lB, out lC, out lr, out lpo);
                    HDebug.Assert(la == a, lb == b, lc == c);
                    HDebug.Assert(lA == A, lB == B, lC == C);
                    HDebug.Assert(lr == r);
                    HDebug.Assert(lpo == po);
                }
            }
Exemplo n.º 11
0
 public static Vector operator*(MatrixByArr lmat, Vector rvec)
 {
     return(LinAlg.MV(lmat, rvec));
 }
Exemplo n.º 12
0
 public static Vector operator*(Vector lvec, MatrixByArr rmat)
 {
     return(LinAlg.VtM(lvec, rmat));
 }
Exemplo n.º 13
0
        public static double DerivativeOfTriangleRadius(Vector p1, Vector p2, Vector p3, Vector dp1, Vector dp2, Vector dp3)
        {
            /// r = |p1-p2|*|p2-p3|*|p3-p1| / (2 area(p1,p2,p3))
            ///   = |p1-p2|*|p2-p3|*|p3-p1| / (2 |(p1-p2)x(p2-p3)|)
            /// r2 = ( |p1-p2|*|p2-p3|*|p3-p1| / (2 area(p1,p2,p3)) )^2
            ///    = |p1-p2|^2 * |p2-p3|^2 * |p3-p1|^2 / (4 |(p1-p2)x(p2-p3)|^2)
            /// (r+dr*t)  = R  = |(p1+dp1*t)-(p2+dp2*t)|*|(p2+dp2*t)-(p3+dp3*t)|*|(p3+dp3*t)-(p1+dp1*t)| / (2 area(p1+dp1*t,p2+dp2*t,p3+dp3*t))
            /// (r+dr*t)2 = R2 = { |(p1+dp1*t)-(p2+dp2*t)|*|(p2+dp2*t)-(p3+dp3*t)|*|(p3+dp3*t)-(p1+dp1*t)| / (2 area(p1+dp1*t,p2+dp2*t,p3+dp3*t)) }^2
            ///
            /// d(r+dr*t)/dt = dR_dt
            ///              = d(r+dr*t)/d((r+dr*t)^2) * d((r+dr*t)^2)/dt
            ///              = dR_dR2 * dR2_dt
            /// d(r+dr*t)/d((r+dr*t)^2) = dR_dR2
            ///                         = 1/(2*r)
            /// d((r+dr*t)^2)/dt = dR2_dt
            ///                = + (   Dotp31dp31 * P12dist2 * P23dist2
            ///                      + Dotp23dp31 * P12dist2 * P31dist2
            ///                      + Dotp12dp12 * P23dist2 * P31dist2
            ///                    )/(2 * Area2)
            ///                  - ( DotCroP12P23CroP12Dp23CroDp12P23 * P12dist2 * P23dist2 * P31dist2)/(2 * Area4)
            ///
            /// P12dist2 := ((p1x-p2x)^2+(p1y-p2y)^2+(p1z-p2z)^2) = (p1-p2).dist2
            /// P23dist2 := ((p2x-p3x)^2+(p2y-p3y)^2+(p2z-p3z)^2) = (p2-p3).dist2
            /// P31dist2 := ((p1x-p3x)^2+(p1y-p3y)^2+(p1z-p3z)^2) = (p1-p3).dist2
            /// Dotp12dp12 := ((dp1x-dp2x)*(p1x-p2x) + (dp1y-dp2y)*(p1y-p2y) + (dp1z-dp2z)*(p1z-p2z))
            ///             = [dp1x-dp2x, dp1y-dp2y, dp1z-dp2z] . [p1x-p2x, p1y-p2y, p1z-p2z]
            ///             = (dp1-dp2).(p1-p2)
            /// Dotp23dp31 := ((dp2x-dp3x)*(p2x-p3x) + (dp2y-dp3y)*(p2y-p3y) + (dp2z-dp3z)*(p2z-p3z))
            ///             = (dp2-dp3).(p2-p3)
            /// Dotp31dp31 := ((dp1x-dp3x)*(p1x-p3x) + (dp1y-dp3y)*(p1y-p3y) + (dp1z-dp3z)*(p1z-p3z))
            ///             = (dp1-dp3).(p1-p3)
            /// DotCroP12P23CroP12Dp23CroDp12P23 := Dot[Cross[p1-p2,p2-p3],(Cross[p1-p2,dp2-dp3]+Cross[dp1-dp2,p2-p3])]
            ///                                   = [(p1-p2)x(p2-p3)] . [(p1-p2)x(dp2-dp3) + (dp1-dp2)x(p2-p3)]

            if (HDebug.Selftest())
            #region selftest
            {
                Vector lp1  = new double[] { 1, 0, 0 };
                Vector lp2  = new double[] { 0, 1, 0 };
                Vector lp3  = new double[] { 0, 0, 1 };
                Vector ldp1 = new double[] { 0.1, 0.1, 0.1 };
                Vector ldp2 = new double[] { 1, 2, 3 };
                Vector ldp3 = new double[] { -1, 0, -0.1 };

                double r0  = Geometry.RadiusOfTriangle(lp1, lp2, lp3);
                double dr0 = DerivativeOfTriangleRadius(lp1, lp2, lp3, ldp1, ldp2, ldp3);
                List <Tuple <double, double, double, double> > drx = new List <Tuple <double, double, double, double> >();
                foreach (double dt in new double[] { 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001 })
                {
                    double t00 = -dt; double r00 = Geometry.RadiusOfTriangle(lp1 + t00 * ldp1, lp2 + t00 * ldp2, lp3 + t00 * ldp3);
                    double t01 = +dt; double r01 = Geometry.RadiusOfTriangle(lp1 + t01 * ldp1, lp2 + t01 * ldp2, lp3 + t01 * ldp3);
                    double dr1 = (r01 - r00) / (t01 - t00);
                    double dr2 = (r01 * r01 - r00 * r00) / (t01 - t00);

                    drx.Add(new Tuple <double, double, double, double>(dt, dr1, dr2, (0.5 / r0) * dr2));
                }
                double diff = dr0 - drx.Last().Item2;
                HDebug.AssertTolerance(0.00000001, diff);
            }
            #endregion

            double P12dist2   = (p1 - p2).Dist2;
            double P23dist2   = (p2 - p3).Dist2;
            double P31dist2   = (p1 - p3).Dist2;
            double Dotp12dp12 = LinAlg.VtV(dp1 - dp2, p1 - p2);
            double Dotp23dp31 = LinAlg.VtV(dp2 - dp3, p2 - p3);
            double Dotp31dp31 = LinAlg.VtV(dp1 - dp3, p1 - p3);
            double DotCroP12P23CroP12Dp23CroDp12P23 = LinAlg.VtV(LinAlg.CrossProd(p1 - p2, p2 - p3)
                                                                 , LinAlg.CrossProd(p1 - p2, dp2 - dp3) + LinAlg.CrossProd(dp1 - dp2, p2 - p3)
                                                                 );
            double Area2 = LinAlg.CrossProd(p1 - p2, p2 - p3).Dist2;
            double Area4 = Area2 * Area2;
            double Rad2  = P12dist2 * P23dist2 * P31dist2 / (4 * Area2);
            double Rad   = Math.Sqrt(Rad2);
            HDebug.AssertTolerance(0.00000001, Rad - Geometry.RadiusOfTriangle(p1, p2, p3));

            double t      = 1;
            double dR_dR2 = 0.5 / Rad;
            double dR2_dt = ((t * Dotp31dp31) * P12dist2 * P23dist2 + (t * Dotp23dp31) * P12dist2 * P31dist2 + (t * Dotp12dp12) * P23dist2 * P31dist2) / (2 * Area2)
                            - ((t * DotCroP12P23CroP12Dp23CroDp12P23) * P12dist2 * P23dist2 * P31dist2) / (2 * Area4);
            double dR_dt = dR_dR2 * dR2_dt;
            return(dR_dt);
        }
Exemplo n.º 14
0
        public static Tuple <MatrixByArr, Vector> Eig(MatrixByArr A)
        {
            if (HDebug.Selftest())
            {
                MatrixByArr tA = new double[, ] {
                    { 1, 2, 3 },
                    { 2, 9, 5 },
                    { 3, 5, 6 }
                };
                MatrixByArr tV = new double[, ] {
                    { -0.8879, 0.3782, 0.2618 },
                    { -0.0539, -0.6508, 0.7573 },
                    { 0.4568, 0.6583, 0.5983 }
                };
                Vector tD = new double[] { -0.4219, 2.7803, 13.6416 };

                Tuple <MatrixByArr, Vector> tVD = Eig(tA);
                Vector tV0 = tVD.Item1.GetColVector(0); double tD0 = tVD.Item2[0];
                Vector tV1 = tVD.Item1.GetColVector(1); double tD1 = tVD.Item2[1];
                Vector tV2 = tVD.Item1.GetColVector(2); double tD2 = tVD.Item2[2];

                HDebug.AssertTolerance(0.00000001, 1 - LinAlg.VtV(tV0, tV0));
                HDebug.AssertTolerance(0.00000001, 1 - LinAlg.VtV(tV1, tV1));
                HDebug.AssertTolerance(0.00000001, 1 - LinAlg.VtV(tV2, tV2));
                MatrixByArr tAA = tVD.Item1 * LinAlg.Diag(tVD.Item2) * tVD.Item1.Tr();
                HDebug.AssertTolerance(0.00000001, tA - tAA);

                //HDebug.AssertTolerance(0.0001, VD.Item1-tV);
                HDebug.AssertTolerance(0.0001, tVD.Item2 - tD);
            }

            HDebug.Assert(A.ColSize == A.RowSize);
            double[] eigval;
            double[,] eigvec;

            #region bool alglib.smatrixevd(double[,] a, int n, int zneeded, bool isupper, out double[] d, out double[,] z)
            /// Finding the eigenvalues and eigenvectors of a symmetric matrix
            ///
            /// The algorithm finds eigen pairs of a symmetric matrix by reducing it to
            /// tridiagonal form and using the QL/QR algorithm.
            ///
            /// Input parameters:
            ///     A       -   symmetric matrix which is given by its upper or lower
            ///                 triangular part.
            ///                 Array whose indexes range within [0..N-1, 0..N-1].
            ///     N       -   size of matrix A.
            ///     ZNeeded -   flag controlling whether the eigenvectors are needed or not.
            ///                 If ZNeeded is equal to:
            ///                  * 0, the eigenvectors are not returned;
            ///                  * 1, the eigenvectors are returned.
            ///     IsUpper -   storage format.
            ///
            /// Output parameters:
            ///     D       -   eigenvalues in ascending order.
            ///                 Array whose index ranges within [0..N-1].
            ///     Z       -   if ZNeeded is equal to:
            ///                  * 0, Z hasn’t changed;
            ///                  * 1, Z contains the eigenvectors.
            ///                 Array whose indexes range within [0..N-1, 0..N-1].
            ///                 The eigenvectors are stored in the matrix columns.
            ///
            /// Result:
            ///     True, if the algorithm has converged.
            ///     False, if the algorithm hasn't converged (rare case).
            ///
            ///   -- ALGLIB --
            ///      Copyright 2005-2008 by Bochkanov Sergey
            ///
            /// public static bool alglib.smatrixevd(
            ///     double[,] a,
            ///     int n,
            ///     int zneeded,
            ///     bool isupper,
            ///     out double[] d,
            ///     out double[,] z)
            #endregion
            bool success = alglib.smatrixevd(A, A.ColSize, 1, false, out eigval, out eigvec);

            if (success == false)
            {
                HDebug.Assert(false);
                return(null);
            }
            return(new Tuple <MatrixByArr, Vector>(eigvec, eigval));
        }
Exemplo n.º 15
0
        public static object LeastSquare
            (double[,] As, double[] bs
            , bool opt_get_stat = false
            )
        {
            if (HDebug.Selftest())
            {
                /// >> A = [ 1,3,2, 1 ; 4,5,6, 1 ; 7,9,9, 1 ; 11,11,12, 1 ; 13,16,15, 1 ]
                /// >> b = [1, 4, 6, 9, 12]'
                /// >> x = inv(A' * A) * (A' * b)
                ///     0.2171
                ///     0.2125
                ///     0.4205
                ///    -0.7339
                /// >> esti = A * x
                ///     0.9619
                ///     3.7203
                ///     6.4832
                ///     9.0381
                ///    11.7965
                /// >> corr(esti,b)
                ///     0.9976
                /// >> mean( (b-esti).^2 )
                ///     0.0712
                double[,] _A = new double[5, 3] {
                    { 1, 3, 2 }, { 4, 5, 6 }, { 7, 9, 9 }, { 11, 11, 12 }, { 13, 16, 15 }
                };
                double[] _b = new double[5] {
                    1, 4, 6, 9, 12
                };
                dynamic _out = LeastSquare(_A, _b, true);

                double   _matlab_corr = 0.9976;
                double   _matlab_mse  = 0.0712;
                double[] _matlab_x    = new double[] { 0.2171, 0.2125, 0.4205, -0.7339 };
                double[] _matlab_esti = new double[] { 0.9619, 3.7203, 6.4832, 9.0381, 11.7965 };

                double err1 = Math.Abs(_matlab_corr - _out.opt_estimation_corr);
                double err2 = Math.Abs(_matlab_mse - _out.opt_mean_square_err);
                double err3 = (_matlab_x - (Vector)_out.x).ToArray().MaxAbs();
                double err4 = (_matlab_esti - (Vector)_out.opt_estimation).ToArray().MaxAbs();

                HDebug.Assert(err1 < 0.0001);
                HDebug.Assert(err2 < 0.0001);
                HDebug.Assert(err3 < 0.0001);
                HDebug.Assert(err4 < 0.0001);
            }
            /// => A x = b
            ///
            /// => At A x = At b
            ///
            /// => AA * x = Ab
            /// => x = inv(AA) * Ab
            HDebug.Assert(As.GetLength(0) == bs.Length);
            int n = As.GetLength(0);
            int k = As.GetLength(1);

            Matrix A = Matrix.Zeros(n, k + 1);

            for (int c = 0; c < n; c++)
            {
                for (int r = 0; r < k; r++)
                {
                    A[c, r] = As[c, r];
                }
                A[c, k] = 1;
            }

            Matrix AA = LinAlg.MtM(A, A);
            Vector Ab = LinAlg.MtV(A, bs);

            Vector x;

            switch (k + 1)
            {
            case 2: { Matrix invAA = LinAlg.Inv2x2(AA.ToArray()); x = LinAlg.MV(invAA, Ab); } break;

            case 3: { Matrix invAA = LinAlg.Inv3x3(AA.ToArray()); x = LinAlg.MV(invAA, Ab); } break;

            case 4: { Matrix invAA = LinAlg.Inv4x4(AA.ToArray()); x = LinAlg.MV(invAA, Ab); } break;

            default:
                Matlab.PutMatrix("LinAlg_LeastSquare.AA", AA);
                Matlab.PutVector("LinAlg_LeastSquare.Ab", Ab);
                Matlab.Execute("LinAlg_LeastSquare.AA = inv(LinAlg_LeastSquare.AA);");
                Matlab.Execute("LinAlg_LeastSquare.x = LinAlg_LeastSquare.AA * LinAlg_LeastSquare.Ab;");
                x = Matlab.GetVector("LinAlg_LeastSquare.x");
                Matlab.Execute("clear LinAlg_LeastSquare;");
                break;
            }

            double?opt_mean_square_err = null;
            double?opt_estimation_corr = null;
            Vector opt_estimation      = null;

            if (opt_get_stat)
            {
                opt_estimation = new double[n];
                double avg_err2 = 0;
                for (int i = 0; i < n; i++)
                {
                    double esti = 0;
                    for (int j = 0; j < k; j++)
                    {
                        esti += As[i, j] * x[j];
                    }
                    esti += x[k];

                    opt_estimation[i] = esti;
                    avg_err2         += (esti - bs[i]) * (esti - bs[i]);
                }
                avg_err2 /= n;

                opt_mean_square_err = avg_err2;
                opt_estimation_corr = HMath.HCorr(opt_estimation, bs);
            }

            return(new
            {
                x = x,
                /// optional outputs
                opt_mean_square_err = opt_mean_square_err,
                opt_estimation_corr = opt_estimation_corr,
                opt_estimation = opt_estimation,
            });
        }
Exemplo n.º 16
0
        public static double[] LeastSquare
            (double[] As, double[] bs
            , double[] mean_square_err = null
            )
        {
            /// => A x = b
            ///
            /// => [A1, 1] * [ x ] = [b1]
            ///    [A2, 1]   [ t ]   [b2]
            ///    [A3, 1]           [b3]
            ///    [...  ]           [..]
            ///
            /// => At A xt = At b
            ///
            /// => [A1 A2 A3] * [A1, 1] * [ x ] = [A1 A2 A3] * [b1]
            ///    [ 1  1  1]   [A2, 1]   [ t ]   [ 1  1  1]   [b2]
            ///                 [A3, 1]                        [b3]
            ///                 [...  ]                        [..]
            ///
            /// => [A1^2 + A2^2 + A3^2 + ...,  A1+A2+A3+...] * [ x ] = [A1*b1 + A2*b2 + A3*b3 + ...]
            ///    [A1+A2+A3+...            ,  1+1+1+...   ]   [ t ] = [b1+b2+b3+...               ]
            ///
            /// => [sumA2, sumA ] * [ x ] = [sumAb]
            ///    [sumA , sum1 ]   [ t ] = [sumb ]
            ///
            /// => AA * xt = Ab
            /// => xt = inv(AA) * Ab
            double[,] AA = new double[2, 2];
            double[] Ab = new double[2];
            int      n  = As.Length;

            HDebug.Assert(n == As.Length);
            HDebug.Assert(n == bs.Length);
            for (int i = 0; i < n; i++)
            {
                double ai  = As[i];
                double bi  = bs[i];
                double Ai2 = ai * ai;
                AA[0, 0] += Ai2;
                AA[0, 1] += ai;
                AA[1, 0] += ai;
                AA[1, 1] += 1;
                Ab[0]    += ai * bi;
            }
            MatrixByArr invA = LinAlg.Inv2x2(AA);
            Vector      xt   = LinAlg.MV(invA, Ab);

            if (mean_square_err != null)
            {
                HDebug.Assert(mean_square_err.Length == 1);
                double err2 = 0;
                double x    = xt[0];
                double t    = xt[1];
                for (int i = 0; i < n; i++)
                {
                    double nbi  = As[i] * x + t;
                    double erri = (nbi - bs[i]);
                    err2 += erri * erri;
                }
                mean_square_err[0] = err2 / n;
            }

            return(xt);
        }