public static double ComputeSolverError(
            LinearProblemProperties input,
            SolutionValues[] X)
        {
            double error = 0.0;

            for (int i = 0; i < input.Count; i++)
            {
                if (X[i].ConstraintStatus)
                    continue;

                SparseElement m = input.M[i];

                double[] bufValue = m.Value;
                int[] bufIndex = m.Index;

                double bValue = (1.0 / input.D[i]) * X[i].X;

                for (int j = 0; j < m.Count; j++)
                    bValue += bufValue[j] * X[bufIndex[j]].X;

                error += (bValue - input.B[i]) * (bValue - input.B[i]);
            }

            return error;
        }
        public SolutionValues[] Solve(
            LinearProblemProperties input,
            SolutionValues[] X = null)
        {
            if(X == null)
                X = new SolutionValues[input.Count];

			double internalSOR = SolverParameters.SOR;
            double solverError = double.MaxValue;

			for (int k = 0; k < SolverParameters.MaxIteration; k++) 
			{
				double[] sum = ElaborateLowerTriangularMatrix(input, X);

                	for (int i = 0; i < input.Count; i++)
				{
					double sumBuffer = sum [i];

					SparseElement m = input.M [i];

					double[] bufValue = m.Value;
					int[] bufIndex = m.Index;

					//Avoid first row elaboration
					if (i != 0) 
					{
						for (int j = 0; j < m.Count; j++) 
						{
							if (bufIndex[j] < i) 
								sumBuffer += bufValue [j] * X [bufIndex[j]].X;
						}
					}

                    sumBuffer = (input.B[i] - sumBuffer) * input.D[i];

                    	X[i].X += (sumBuffer - X[i].X) * internalSOR;

					X[i] = ClampSolution.Clamp (input, X, i);

                    sum[i] = sumBuffer;
				}

                if (SolverParameters.DynamicSORUpdate)
                {
                    double actualSolverError = SolverHelper.ComputeSolverError(input, X);
                    
                    if (actualSolverError > solverError)
                        internalSOR = Math.Max(internalSOR - SolverParameters.SORStep, SolverParameters.SORStep);
                    else
                        solverError = actualSolverError;

                    if (actualSolverError < SolverParameters.ErrorTolerance)
                        return X;
                }
            }
             
            return X;
        }
        public SolutionValues[] Solve(
            LinearProblemProperties linearProblemProperties, 
            SolutionValues[] X = null)
        {
            if (X == null)
                X = new SolutionValues[linearProblemProperties.Count];

            double[] x = new double[X.Length];
            for (int i = 0; i < x.Length; i++)
                x[i] = X[i].X;
            
            SparseElement[] A = linearProblemProperties.GetOriginalMatrixSparse();
            double[] g = Minus(Multiply(A, x), linearProblemProperties.B);
                        
            if (Dot(g, g) < 1E-50)
                return X;

            double[] pPhi = GetPhi(linearProblemProperties, A, x, g);
            
            for (int i = 0; i < SolverParameters.MaxIteration; i++)
            {
                double alphaKDen = Dot(Multiply(A, pPhi), pPhi);
                double alphaK = 0.0;
                if (alphaKDen != 0)
                    alphaK = Dot(g, pPhi) / alphaKDen;
                else
                {
                    string ciao = "ciao";
                }

                double[] halfX = Minus(x, Multiply(alphaK, pPhi));
                x = Project(linearProblemProperties, halfX);
                
                g = Minus(Multiply(A, x), linearProblemProperties.B);
                pPhi = GetPhi(linearProblemProperties, A, x, g);
            }

            for (int i = 0; i < x.Length; i++)
            {
                X[i].X = x[i];
                X[i] = ClampSolution.Clamp(linearProblemProperties, X, i);
            }
            
            return X;
        }
		public LinearProblemProperties (
			SparseElement[] M,
			double[] B,
			SolutionValues[] startX,
			double[] d,
			double[] constraintLimit,
			ConstraintType[] constraintType,
			int?[][] constraints,
            	int count)
		{
			this.M = M;
			this.B = B;
			D = d;
			ConstraintLimit = constraintLimit;
			ConstraintType = constraintType;
			Constraints = constraints;
			Count = count;
		}
        public SolutionValues[] Solve(
            LinearProblemProperties input,
            SolutionValues[] X = null)
        {
            if (X == null)
                X = new SolutionValues[input.Count];

            SolutionValues[] Xk = gaussSeidelSolver.Solve(input);
            double[] delta = calculateDelta(Xk, X);
            double[] searchDirection = negateArray(delta);

            SolutionValues[] Xk1 = new SolutionValues[input.Count];

            for (int i = 0; i < solverParam.MaxIteration; i++)
            {
                Xk1 = gaussSeidelSolver.Solve(input, Xk);
                                
                double[] deltaK = calculateDelta(Xk1, Xk);

                deltaErrorCheck = arraySquareModule(delta);
                
                double betaK = 1.1;
				if (Math.Abs(deltaErrorCheck) > 1E-40)
                    betaK = arraySquareModule(deltaK) / deltaErrorCheck;

				if (betaK > 1.0)
					searchDirection = new double[searchDirection.Length];
                else
                {
					Xk1 = calculateDirection (
						input,
						Xk1, 
						deltaK, 
						ref searchDirection, 
						betaK);
                }

                Array.Copy(Xk1, Xk, Xk1.Length);
                Array.Copy(deltaK, delta, deltaK.Length);
            }
            return Xk1;
        }
		public static SolutionValues Clamp(
			LinearProblemProperties input,
			SolutionValues[] X,
            	int i)
		{

            switch (input.ConstraintType[i])
            {
                case ConstraintType.Collision:
                case ConstraintType.JointLimit:
                    if (X[i].X < 0)
                        return new SolutionValues(0.0, true);
                    else
                        return new SolutionValues(X[i].X, false);
                                        
				case ConstraintType.Friction:
                    
                    double frictionLimit = X[input.Constraints[i][0].Value].X * input.ConstraintLimit[i];

                    if (X[i].X < -frictionLimit)
                        return new SolutionValues(-frictionLimit, true);
                    if (X[i].X > frictionLimit)
                        return new SolutionValues(frictionLimit, true);

                    return new SolutionValues(X[i].X, false);
                    

                case ConstraintType.JointMotor:
					double limit = input.ConstraintLimit[i];

                    if (X[i].X < -limit)
                        return new SolutionValues(-limit, true);
                    if (X[i].X > limit)
                        return new SolutionValues(limit, true);

                    return new SolutionValues(X[i].X, false);
                    				
				default:
                    return new SolutionValues(X[i].X, false);
            }
		}
        private double[] calculateDelta(
            SolutionValues[] a,
            SolutionValues[] b)
        {
			if (a.Length < 0 ||
				b.Length < 0 ||
				b.Length != a.Length)
			{
				throw new Exception("Different array size.");
			}

            double[] result = new double[a.Length];

            for (int i = 0; i < a.Length; i++)
                result[i] = -(a[i].X - b[i].X);
            
            return result;
        }
        private SolutionValues[] calculateDirection(
			LinearProblemProperties input,
			SolutionValues[] Xk1,
            double[] deltaK,
            ref double[] searchDirection,
            double betak)
        {
            SolutionValues[] result = new SolutionValues[Xk1.Length];

            for (int i = 0; i < Xk1.Length; i++)
            {
                double bDirection = betak * searchDirection[i];

                result[i].X = Xk1[i].X + bDirection;

                searchDirection[i] = bDirection - deltaK[i];

                result[i] = ClampSolution.Clamp(input, result, i);
            }

            return result;
        }
		/// <summary>
		/// Builds the LCP matrix for solver.
		/// </summary>
		private LinearProblemProperties BuildLCPMatrix(
			JacobianContact[] contact,
			bool positionStabilization = false)
		{
			if (contact.Length > 0) 
			{
				SparseElement[] M = new SparseElement[contact.Length];
				double[] B = new double[contact.Length];
				SolutionValues[] X = new SolutionValues[contact.Length];
				double[] D = new double[contact.Length];
				ConstraintType[] constraintsType = new ConstraintType[contact.Length];
				double[] constraintsLimit = new double[contact.Length];
				List<int?>[] constraints = new List<int?>[contact.Length];
                
				List<int>[] index = new List<int>[contact.Length];
				List<double>[] value = new List<double>[contact.Length];

				for (int i = 0; i < contact.Length; i++) 
				{
					index [i] = new List<int> ();
					value [i] = new List<double> ();
                    constraints[i] = new List<int?>();
                }

				//Critical section variable
				var sync = new object ();

				Parallel.For (0, 
					contact.Length, 
					new ParallelOptions { MaxDegreeOfParallelism = SimulationEngineParameters.MaxThreadNumber }, 
					i => {

						JacobianContact contactA = contact [i];

						if (positionStabilization)
							B[i] = contactA.CorrectionValue;
						else
							B[i] = -(contactA.B - ((contactA.CorrectionValue) < 0 ? Math.Max(contactA.CorrectionValue, -SimulationEngineParameters.MaxCorrectionValue):
                                                                                    Math.Min(contactA.CorrectionValue, SimulationEngineParameters.MaxCorrectionValue)));
						
						X[i].X = contactA.StartImpulse.StartImpulseValue;

                        
                        if (contactA.ContactReference.HasValue)
                            constraints[i].Add(contactA.ContactReference);
                        
						constraintsLimit [i] = contactA.ConstraintLimit;
						constraintsType [i] = contactA.Type;
                        
						double mValue = addLCPValue(contactA,
													contactA);

						//Diagonal value
						mValue += contactA.CFM +
								  SimulationEngineParameters.CFM +
								  1E-40;

                        D[i] = 1.0 / mValue;

                        	for (int j = i + 1; j < contact.Length; j++) 
						{
							JacobianContact contactB = contact[j];
							
							if (contactA.ObjectA == contactB.ObjectA ||
								contactA.ObjectB == contactB.ObjectB ||
								contactA.ObjectA == contactB.ObjectB ||
								contactA.ObjectB == contactB.ObjectA)
							{
                                if (contactA.Type == contactB.Type && 
                                    contactB.Type == ConstraintType.Collision && 
                                    contactA.ObjectA == contactB.ObjectA && 
                                    contactA.ObjectB == contactB.ObjectB)
                                {
                                    constraints[i].Add(j);
                                    constraints[j].Add(i);
                                }

								mValue = addLCPValue(
									contactA,
									contactB);
                                
								if (Math.Abs(mValue) > 1E-30)
								{
									lock (sync)
									{
										index[i].Add(j);
										value[i].Add(mValue);
										index[j].Add(i);
										value[j].Add(mValue);
									}
								}
							}
						}
					});


                int?[][] constraintsArray = new int?[contact.Length][];
                for (int i = 0; i < contact.Length; i++) 
				{
					M [i] = new SparseElement (
						value [i].ToArray (),
						index [i].ToArray (),
                        contact.Length);

                    constraintsArray[i] = constraints[i].ToArray();
				}
                

				return new LinearProblemProperties (
					M,
					B,
					X,
					D,
					constraintsLimit,
					constraintsType,
                    constraintsArray,
                    	contact.Length);
			}

			return null;
		}
		private void PhysicsExecutionFlow()
		{
			var stopwatch = new Stopwatch();

			stopwatch.Reset();

			stopwatch.Start();

			#region Contact and Joint elaboration

			solverError = 0.0;

            if (SimulationEngineParameters.PositionStabilization)
            {
                bool positionUpdated = PhysicsJointPositionCorrection();

                if (positionUpdated)
                {
                    CollisionDetectionStep();
                    PartitionEngineExecute();
                }
            }
            
            if (collisionPartitionedPoints != null) 
			{
                bool convertSetting = false;
                if (SimulationEngineParameters.PositionStabilization)
                {
                    SimulationEngineParameters.SetPositionStabilization(false);
                    convertSetting = true;
                }

                for (int i = 0; i < collisionPartitionedPoints.Count;i++)
				{
                    JacobianContact[] jacobianConstraints = GetJacobianConstraint(
                                                                   collisionPartitionedPoints[i].ToArray(),
																   partitionedJoint[i],
																   simulationObjects,
																   SimulationEngineParameters).ToArray();

                    if (jacobianConstraints.Length > 0)
                    {
                        SolutionValues[] overallSolution = new SolutionValues[jacobianConstraints.Length];

                        #region Solve Normal And Friction Constraints

                        if (SimulationEngineParameters.FrictionAndNormalIterations > 0)
                        {
                            JacobianContact[] frictionConstraint = Helper.FilterConstraints(jacobianConstraints,
                                                                                       ConstraintType.Friction,
                                                                                       ConstraintType.Collision);

                            LinearProblemProperties frictionLCP = BuildLCPMatrix(
                                                                    frictionConstraint,
                                                                    SimulationEngineParameters.PositionStabilization);

                            SolutionValues[] contactSolution = BuildMatrixAndExecuteSolver(
                                                        frictionConstraint,
                                                        frictionLCP,
                                                        SimulationEngineParameters.FrictionAndNormalIterations);
                        }

                        #endregion

                        #region Solve Joint Constraint

                        if (simulationJoints.Count > 0 &&
                            SimulationEngineParameters.JointsIterations > 0)
                        {
                            JacobianContact[] jointConstraints = Helper.FindJointConstraints(jacobianConstraints);

                            LinearProblemProperties jointLCP = BuildLCPMatrix(
                                                                    jointConstraints,
                                                                    SimulationEngineParameters.PositionStabilization);

                            SolutionValues[] jointSolution = BuildMatrixAndExecuteSolver(
                                                        jointConstraints,
                                                        jointLCP,
                                                        SimulationEngineParameters.JointsIterations);
                        }

                        #endregion

                        #region Solver Overall Constraints

                        jacobianConstraints = ContactSorting(jacobianConstraints);

                        LinearProblemProperties overallLCP = BuildLCPMatrix(
                                                                jacobianConstraints,
                                                                SimulationEngineParameters.PositionStabilization);

                        if (overallLCP != null &&
                           SimulationEngineParameters.OverallConstraintsIterations > 0)
                        {
                            solver.GetSolverParameters().SetSolverMaxIteration(SimulationEngineParameters.OverallConstraintsIterations);

                            overallSolution = solver.Solve(overallLCP);

                            double[] overallError = new double[overallLCP.Count];

                            //SolverParameters test = new SolverParameters(300, solver.GetSolverParameters().ErrorTolerance, solver.GetSolverParameters().SOR, solver.GetSolverParameters().MaxThreadNumber, solver.GetSolverParameters().SORStep, solver.GetSolverParameters().DynamicSORUpdate);

                            //ProjectedGaussSeidel testVerifica = new ProjectedGaussSeidel(test);

                            //SolutionValues[] sol = testVerifica.Solve(overallLCP);

                            Console.WriteLine("error " + SolverHelper.ComputeSolverError(overallLCP, overallSolution));
                            //Console.WriteLine("errorTest " + SolverHelper.ComputeSolverError(overallLCP, sol));
                        }
                        else if (SimulationEngineParameters.OverallConstraintsIterations == 0)
                        {
                            for (int j = 0; j < overallSolution.Length; j++)
                                overallSolution[j].X = jacobianConstraints[j].StartImpulse.StartImpulseValue;
                        }

                        UpdateVelocity(
                                jacobianConstraints,
                                simulationObjects,
                                overallSolution);

                        #endregion
                    }
                }
                if (convertSetting)
                {
                    SimulationEngineParameters.SetPositionStabilization(true);
                }
            }

            #endregion

            #region Position and Velocity integration

            IntegrateObjectsPosition (simulationObjects);

			#endregion

			stopwatch.Stop();

			Console.WriteLine("Inner Engine Elapsed={0}", stopwatch.ElapsedMilliseconds);

		}
        private void UpdatePositionBasedVelocity(
            JacobianContact[] contact,
            SimulationObject[] simulationObj,
            SolutionValues[] X)
        {
            for (int i = 0; i < contact.Length; i++)
            {
                double impulse = X[i].X;

                JacobianContact ct = contact[i];

                SetPositionBasedVelocity(
                    simulationObj,
                    ct.LinearComponentA,
                    ct.AngularComponentA,
                    impulse,
                    ct.ObjectA);

                SetPositionBasedVelocity(
                    simulationObj,
                    ct.LinearComponentB,
                    ct.AngularComponentB,
                    impulse,
                    ct.ObjectB);
            }
        }
        /// <summary>
        /// Updates velocity of the simulations objects.
        /// </summary>
        private void UpdateVelocity(
			JacobianContact[] contact,
			SimulationObject[] simulationObj,
			SolutionValues[] X)
		{
			for (int i =0; i< contact.Length;i++) 
			{
                if (Math.Abs(X[i].X) > 1E-50)
                {
                    double impulse = X[i].X;

                    JacobianContact ct = contact[i];

                    UpdateObjectVelocity(
                        simulationObj,
                        ct.LinearComponentA,
                        ct.AngularComponentA,
                        impulse,
                        ct.ObjectA);

                    UpdateObjectVelocity(
                        simulationObj,
                        ct.LinearComponentB,
                        ct.AngularComponentB,
                        impulse,
                        ct.ObjectB);

                    ct.StartImpulse.SetStartValue(impulse * SimulationEngineParameters.WarmStartingValue);
                }
			}
		}
        private double kernel(
            LinearProblemProperties input,
            SolutionValues[] X,
            int i)
        {
			double sumBuffer = 0.0;

			//Avoid last row elaboration
			if (i + 1 != input.Count)
            {
				double[] bufValue = input.M [i].Value;
				int[] bufIndex = input.M [i].Index;

				for (int j = 0; j < input.M [i].Count; j++) {
					if(bufIndex [j] > i) 
						sumBuffer += bufValue [j] * X [bufIndex [j]].X;
				}
			}
            return sumBuffer;
        }
        private double[] ElaborateLowerTriangularMatrix(
            LinearProblemProperties input,
            SolutionValues[] X)
        {
            double[] sum = new double[input.Count];

			Parallel.For (0, 
				input.Count, 
				new ParallelOptions { MaxDegreeOfParallelism = SolverParameters.MaxThreadNumber }, 
				i => {
					sum [i] = kernel (input, X, i);
				});
				
            return sum;
        }