//// ورودی این متد بایستی نقاط تمیز شده باشد
        //public static LogisticGeometrySimplificationTrainingData GenerateTrainingData<T>(
        //    List<T> originalPoints,
        //    List<T> simplifiedPoints,
        //    //int zoomLevel,
        //    Func<IPoint, IPoint> toScreenMap,
        //    bool isRingMode) where T : IPoint
        //{
        //    if (originalPoints.IsNullOrEmpty() || simplifiedPoints.IsNullOrEmpty())
        //    {
        //        return new LogisticGeometrySimplificationTrainingData();
        //    }

        //    List<LogisticGeometrySimplificationParameters> parameters = new List<LogisticGeometrySimplificationParameters>();

        //    // ایجاد رکوردهای مثبت برای فایل ساده شده
        //    for (int i = 0; i < simplifiedPoints.Count - 2; i++)
        //    {
        //        parameters.Add(new LogisticGeometrySimplificationParameters(simplifiedPoints[i], simplifiedPoints[i + 1], simplifiedPoints[i + 2], /*zoomLevel,*/ toScreenMap)
        //        {
        //            IsRetained = true
        //        });
        //    }

        //    // تعیین ارتباط بین اندکس نقطه در لیست
        //    // اصلی و اندکس نقطه در لیست ساده شده
        //    Dictionary<int, int> indexMap = new Dictionary<int, int>();

        //    for (int simplifiedIndex = 0; simplifiedIndex < simplifiedPoints.Count; simplifiedIndex++)
        //    {
        //        var currentPoint = simplifiedPoints[simplifiedIndex];

        //        for (int originalIndex = simplifiedIndex; originalIndex < originalPoints.Count; originalIndex++)
        //        {
        //            if (currentPoint.X == originalPoints[originalIndex].X && currentPoint.Y == originalPoints[originalIndex].Y)
        //            {
        //                indexMap.Add(simplifiedIndex, originalIndex);

        //                break;
        //            }
        //        }
        //    }

        //    // ایجاد رکوردهای منفی برای فایل اصلی
        //    // پیمایش نقاط میانی و یافتن نقاط مانده
        //    // ابتدا و انتها
        //    // 1400.03.09
        //    // در حالت چندضلعی از نقاط ابتدا و انتهای
        //    // حذف شده در این جا چشم پوشی شده
        //    for (int i = 1; i < originalPoints.Count - 1; i++)
        //    {
        //        if (indexMap.ContainsValue(i))
        //            continue;

        //        // 1400.03.05
        //        // در حال چند رینگ ممکنه نقاط ابتدایی هم حذف
        //        // شوند این برخلاف حالت خط هست که همیشه
        //        // نقطه اول و اخر رو نگه می داریم
        //        var prevPoints = indexMap.Where(index => index.Value < i);

        //        KeyValuePair<int, int> prevRetainedPoint;

        //        if (isRingMode && prevPoints.IsNullOrEmpty())
        //        {
        //            prevRetainedPoint = indexMap.Last();
        //        }
        //        else
        //        {
        //            //prevRetainedPoint = indexMap.Where(index => index.Value < i).Last();
        //            prevRetainedPoint = prevPoints.Last();
        //        }
        //        //var prevRetainedPoint = indexMap.Where(index => index.Value < i).Last();

        //        //var nextRetainedPoint = indexMap.First(index => index.Value > i);
        //        var nextPoints = indexMap.Where(index => index.Value > i);

        //        KeyValuePair<int, int> nextRetainedPoint;

        //        if (isRingMode && nextPoints.IsNullOrEmpty())
        //        {
        //            nextRetainedPoint = indexMap.First();
        //        }
        //        else
        //        {
        //            //nextRetainedPoint = indexMap.First(index => index.Value > i);
        //            nextRetainedPoint = indexMap.First(index => index.Value > i);

        //        }

        //        parameters.Add(new LogisticGeometrySimplificationParameters(
        //            originalPoints[prevRetainedPoint.Value],
        //            originalPoints[i],
        //            originalPoints[nextRetainedPoint.Value],
        //            //zoomLevel,
        //            toScreenMap)
        //        {
        //            IsRetained = false
        //        });
        //    }

        //    return new LogisticGeometrySimplificationTrainingData() { Records = parameters };
        //}

        private bool?IsRetained(LogisticGeometrySimplificationParameters <T> parameters)
        {
            // 1400.03.20
            //List<double> xValues = new List<double>
            //{
            //    //1,
            //    //parameters.ZoomLevel,
            //    parameters.SemiDistanceToNext,
            //    parameters.SemiDistanceToPrevious,
            //    //parameters.SemiVerticalDistance,
            //    parameters.SemiArea,
            //    parameters.SquareCosineOfAngle,
            //    //parameters.CosineOfAngle
            //};

            List <double> xValues = parameters.FeatureValues;

            var result = _regression.Predict(xValues);

            if (result.HasValue)
            {
                if (result.Value > 1 || result.Value < 0)
                {
                }

                //return Math.Round(result.Value) == 1;
                return(result.Value > 0.5);
            }
            else
            {
                return(null);
            }
        }
        /// <summary>
        /// Check that the model is able to fit the classification data
        /// </summary>
        private void check_predictions(LogisticRegression<int> clf, Matrix<double> X, int[] y)
        {
            int nSamples = y.Length;
            int[] classes = y.Distinct().OrderBy(v => v).ToArray();
            int nClasses = classes.Length;

            clf.Fit(X, y);
            var predicted = clf.Predict(X);
            Assert.IsTrue(classes.SequenceEqual(clf.Classes));

            Assert.AreEqual(nSamples, predicted.Length);
            Assert.IsTrue(y.SequenceEqual(predicted));
                
            Matrix<double> probabilities = clf.PredictProba(X);
            Assert.AreEqual(Tuple.Create(nSamples, nClasses), probabilities.Shape());
            Assert.IsTrue(probabilities.SumOfEveryRow().AlmostEquals(DenseVector.Create(probabilities.RowCount, i => 1.0)));
            Assert.IsTrue(y.SequenceEqual(probabilities.ArgmaxColumns()));
        }
        /// <summary>
        /// Check that the model is able to fit the classification data
        /// </summary>
        private void check_predictions(LogisticRegression <int> clf, Matrix <double> X, int[] y)
        {
            int nSamples = y.Length;

            int[] classes  = y.Distinct().OrderBy(v => v).ToArray();
            int   nClasses = classes.Length;

            clf.Fit(X, y);
            var predicted = clf.Predict(X);

            Assert.IsTrue(classes.SequenceEqual(clf.Classes));

            Assert.AreEqual(nSamples, predicted.Length);
            Assert.IsTrue(y.SequenceEqual(predicted));

            Matrix <double> probabilities = clf.PredictProba(X);

            Assert.AreEqual(Tuple.Create(nSamples, nClasses), probabilities.Shape());
            Assert.IsTrue(probabilities.SumOfEveryRow().AlmostEquals(DenseVector.Create(probabilities.RowCount, i => 1.0)));
            Assert.IsTrue(y.SequenceEqual(probabilities.ArgmaxColumns()));
        }
        public void TestPredictIris()
        {
            int nSamples = iris.Data.RowCount;

            string[] target = iris.Target.Select(v => iris.TargetNames[v]).ToArray();
            var      clf    = new LogisticRegression <string>(c: iris.Data.RowCount);

            clf.Fit(iris.Data, target);
            Assert.IsTrue(target.Distinct().OrderBy(t => t).SequenceEqual(clf.Classes));

            var pred      = clf.Predict(iris.Data);
            var matchingN = pred.Zip(target, Tuple.Create).Where(t => t.Item1 == t.Item2).Count();

            Assert.IsTrue(1.0 * matchingN / pred.Length > 0.95);

            var probabilities = clf.PredictProba(iris.Data);

            Assert.IsTrue(probabilities.SumOfEveryRow().AlmostEquals(DenseVector.Create(nSamples, i => 1.0)));

            pred      = probabilities.RowEnumerator().Select(r => iris.TargetNames[r.Item2.MaximumIndex()]).ToArray();
            matchingN = pred.Zip(target, Tuple.Create).Where(t => t.Item1 == t.Item2).Count();
            Assert.IsTrue(1.0 * matchingN / pred.Length > 0.95);
        }
        public void TestPredictIris()
        {
            int nSamples = iris.Data.RowCount;

            string[] target = iris.Target.Select(v => iris.TargetNames[v]).ToArray();
            var clf = new LogisticRegression<string>(c: iris.Data.RowCount);
            clf.Fit(iris.Data, target);
            Assert.IsTrue(target.Distinct().OrderBy(t => t).SequenceEqual(clf.Classes));

            var pred = clf.Predict(iris.Data);
            var matchingN = pred.Zip(target, Tuple.Create).Where(t => t.Item1 == t.Item2).Count();
            Assert.IsTrue(1.0*matchingN/pred.Length > 0.95);

            var probabilities = clf.PredictProba(iris.Data);
            Assert.IsTrue(probabilities.SumOfEveryRow().AlmostEquals(DenseVector.Create(nSamples, i => 1.0)));

            pred = probabilities.RowEnumerator().Select(r => iris.TargetNames[r.Item2.MaximumIndex()]).ToArray();
            matchingN = pred.Zip(target, Tuple.Create).Where(t => t.Item1 == t.Item2).Count();
            Assert.IsTrue(1.0 * matchingN / pred.Length > 0.95);
        }
 protected override double GetFileEstimation(ProjectFile file)
 {
     return(regression.Predict(
                GetPredictorValuesFor(context.SetFiles(e => e.IdIs(file.ID)))
                ));
 }