/// <summary> /// Compute rigid motion using the singular value decomposition (SVD). /// Returns the best transformation that moves X towards Y minimizing the mean squared error (MSE), /// such that y = x*R + offset /// </summary> /// <param name="x">The list of source points (read-only)</param> /// <param name="y">The list of destination points (read-only)</param> /// <param name="R">The output rotation matrix (3x3)</param> /// <param name="offset">The output offset (3D vector)</param> public static void ComputeRigidMotion(List <Vector3> x, List <Vector3> y, out double[,] R, out double[] offset) { if (x.Count == 0) { // Extreme corner case R = AMath.Matrix.Identity(3); offset = new double[] { 0, 0, 0 }; return; } double[,] X = new double[x.Count, 3]; double[,] Y = new double[y.Count, 3]; for (int i = 0; i < x.Count; i++) { X[i, 0] = x[i][0]; X[i, 1] = x[i][1]; X[i, 2] = x[i][2]; Y[i, 0] = y[i][0]; Y[i, 1] = y[i][1]; Y[i, 2] = y[i][2]; } var Xc = Accord.Statistics.Measures.Mean(X, 0); var Yc = Accord.Statistics.Measures.Mean(Y, 0); var H = AMath.Matrix.TransposeAndDot(AMath.Elementwise.Subtract(Y, Yc, 0), AMath.Elementwise.Subtract(X, Xc, 0)); var svd = new AMath.Decompositions.SingularValueDecomposition(H); R = AMath.Matrix.DotWithTransposed(svd.RightSingularVectors, svd.LeftSingularVectors); if (AMath.Matrix.Determinant(R) < 0) // Check whether the determinant is -1 { // We have an improper rotation, i.e. a reflection transformation. double[,] V = svd.RightSingularVectors; V[0, 2] *= -1; V[1, 2] *= -1; V[2, 2] *= -1; R = AMath.Matrix.DotWithTransposed(V, svd.LeftSingularVectors); // Now the determinant is +1 } offset = AMath.Elementwise.Subtract(Yc, AMath.Matrix.Dot(Xc, R)); }
public override void Init(IRepository repository) { authorByRevision = repository.SelectionDSL() .Commits().TillRevision(model.PredictionRelease) .ToDictionary(x => x.Revision, x => x.Author); int releaseRevisionOrderedNumber = repository.Queryable <Commit>() .Single(x => x.Revision == model.PredictionRelease).OrderedNumber; var codeByAuthorAndFile = ( from cb in repository.Queryable <CodeBlock>() join m in repository.Queryable <Modification>() on cb.ModificationID equals m.ID join c in repository.Queryable <Commit>() on m.CommitID equals c.ID join f in repository.Queryable <ProjectFile>() on m.FileID equals f.ID where cb.Size > 0 && c.OrderedNumber <= releaseRevisionOrderedNumber group cb by new { Author = c.Author, FileID = f.ID } into g select new { Author = g.Key.Author, FileID = g.Key.FileID, CodeSize = g.Sum(x => x.Size) } ).ToArray(); var allFiles = model.AllFiles.Select(x => x.ID).ToArray(); var allAuthors = repository.SelectionDSL() .Commits().TillRevision(model.PredictionRelease) .Select(x => x.Author).Distinct().ToArray(); int numberOfFiles = allFiles.Count(); int numberOfAuthors = allAuthors.Count(); int numberOfEquations = numberOfFiles + numberOfAuthors + 1; double[,] equations = new double[numberOfEquations, numberOfEquations]; double[] results = new double[numberOfEquations]; int equation = 0; double locAdded = codeByAuthorAndFile.Sum(x => x.CodeSize); for (int i = 0; i < allFiles.Length; i++) { double locAddedInFile = codeByAuthorAndFile .Where(x => x.FileID == allFiles[i]) .Sum(x => x.CodeSize); equations[numberOfEquations - 1, i] = locAddedInFile / locAdded; equations[equation, i] = 1; if (locAddedInFile > 0) { double dcd = repository.SelectionDSL() .Commits() .TillRevision(model.PredictionRelease) .Files() .IdIs(allFiles[i]) .Modifications().InCommits().InFiles() .CodeBlocks().InModifications().CalculateDefectCodeDensity(model.PredictionRelease); for (int j = 0; j < allAuthors.Length; j++) { double locAddedInFileByAuthor = codeByAuthorAndFile .Where(x => x.FileID == allFiles[i] && x.Author == allAuthors[j]) .Sum(x => x.CodeSize); equations[equation, numberOfFiles + j] = (locAddedInFileByAuthor / locAddedInFile); } results[equation] = dcd; } equation++; } for (int i = 0; i < allAuthors.Length; i++) { double locAddedByAuthor = codeByAuthorAndFile .Where(x => x.Author == allAuthors[i]) .Sum(x => x.CodeSize); equations[numberOfEquations - 1, numberOfFiles + i] = locAddedByAuthor / locAdded; equations[equation, numberOfFiles + i] = 1; if (locAddedByAuthor > 0) { double dcd = repository.SelectionDSL() .Commits() .AuthorIs(allAuthors[i]) .TillRevision(model.PredictionRelease) .Modifications().InCommits() .CodeBlocks().InModifications().CalculateDefectCodeDensity(model.PredictionRelease); for (int j = 0; j < allFiles.Length; j++) { double locAddedByAuthorInFile = codeByAuthorAndFile .Where(x => x.Author == allAuthors[i] && x.FileID == allFiles[j]) .Sum(x => x.CodeSize); equations[equation, j] = (locAddedByAuthorInFile / locAddedByAuthor); } results[equation] = dcd; } equation++; } results[numberOfEquations - 1] = repository.SelectionDSL() .Commits() .TillRevision(model.PredictionRelease) .Modifications().InCommits() .CodeBlocks().InModifications().CalculateDefectCodeDensity(model.PredictionRelease); int varCount = equations.GetUpperBound(1) + 1; double[,] normalEquations = new double[varCount, varCount]; double[] normalResults = new double[varCount]; Func <double[, ], double[], int, int, double> nc = (e, r, n1, n2) => { double sum = 0; for (int i = 0; i < numberOfEquations; i++) { if (n2 < numberOfEquations) { sum += e[i, n1] * e[i, n2]; } else { sum += e[i, n1] * r[i]; } } return(sum); }; for (int i = 0; i < varCount; i++) { for (int j = 0; j < varCount; j++) { normalEquations[i, j] = nc(equations, results, i, j); } normalResults[i] = nc(equations, results, i, numberOfEquations); } var DCD = new Accord.Math.Decompositions.SingularValueDecomposition(normalEquations).Solve(normalResults); DCDF = new Dictionary <int, double>(); DCDA = new Dictionary <string, double>(); double DCD_min = 0.001; for (int i = 0; i < allFiles.Length; i++) { DCDF.Add(allFiles[i], DCD[i] > 0 ? DCD[i] : DCD_min); } for (int i = 0; i < allAuthors.Length; i++) { DCDA.Add(allAuthors[i], DCD[numberOfFiles + i] > 0 ? DCD[numberOfFiles + i] : DCD_min); } }
public override void Init(IRepositoryResolver repositories) { authorByRevision = repositories.SelectionDSL() .Commits().TillRevision(model.PredictionRelease) .ToDictionary(x => x.Revision, x => x.Author); int releaseRevisionOrderedNumber = repositories.Repository<Commit>() .Single(x => x.Revision == model.PredictionRelease).OrderedNumber; var codeByAuthorAndFile = ( from cb in repositories.Repository<CodeBlock>() join m in repositories.Repository<Modification>() on cb.ModificationID equals m.ID join c in repositories.Repository<Commit>() on m.CommitID equals c.ID join f in repositories.Repository<ProjectFile>() on m.FileID equals f.ID where cb.Size > 0 && c.OrderedNumber <= releaseRevisionOrderedNumber group cb by new { Author = c.Author, FileID = f.ID } into g select new { Author = g.Key.Author, FileID = g.Key.FileID, CodeSize = g.Sum(x => x.Size) } ).ToArray(); var allFiles = model.AllFiles.Select(x => x.ID).ToArray(); var allAuthors = repositories.SelectionDSL() .Commits().TillRevision(model.PredictionRelease) .Select(x => x.Author).Distinct().ToArray(); int numberOfFiles = allFiles.Count(); int numberOfAuthors = allAuthors.Count(); int numberOfEquations = numberOfFiles + numberOfAuthors + 1; double[,] equations = new double[numberOfEquations,numberOfEquations]; double[] results = new double[numberOfEquations]; int equation = 0; double locAdded = codeByAuthorAndFile.Sum(x => x.CodeSize); for (int i = 0; i < allFiles.Length; i++) { double locAddedInFile = codeByAuthorAndFile .Where(x => x.FileID == allFiles[i]) .Sum(x => x.CodeSize); equations[numberOfEquations-1, i] = locAddedInFile / locAdded; equations[equation, i] = 1; if (locAddedInFile > 0) { double dcd = repositories.SelectionDSL() .Commits() .TillRevision(model.PredictionRelease) .Files() .IdIs(allFiles[i]) .Modifications().InCommits().InFiles() .CodeBlocks().InModifications().CalculateDefectCodeDensity(model.PredictionRelease); for (int j = 0; j < allAuthors.Length; j++) { double locAddedInFileByAuthor = codeByAuthorAndFile .Where(x => x.FileID == allFiles[i] && x.Author == allAuthors[j]) .Sum(x => x.CodeSize); equations[equation, numberOfFiles + j] = (locAddedInFileByAuthor / locAddedInFile); } results[equation] = dcd; } equation++; } for (int i = 0; i < allAuthors.Length; i++) { double locAddedByAuthor = codeByAuthorAndFile .Where(x => x.Author == allAuthors[i]) .Sum(x => x.CodeSize); equations[numberOfEquations-1, numberOfFiles + i] = locAddedByAuthor / locAdded; equations[equation, numberOfFiles + i] = 1; if (locAddedByAuthor > 0) { double dcd = repositories.SelectionDSL() .Commits() .AuthorIs(allAuthors[i]) .TillRevision(model.PredictionRelease) .Modifications().InCommits() .CodeBlocks().InModifications().CalculateDefectCodeDensity(model.PredictionRelease); for (int j = 0; j < allFiles.Length; j++) { double locAddedByAuthorInFile = codeByAuthorAndFile .Where(x => x.Author == allAuthors[i] && x.FileID == allFiles[j]) .Sum(x => x.CodeSize); equations[equation, j] = (locAddedByAuthorInFile / locAddedByAuthor); } results[equation] = dcd; } equation++; } results[numberOfEquations-1] = repositories.SelectionDSL() .Commits() .TillRevision(model.PredictionRelease) .Modifications().InCommits() .CodeBlocks().InModifications().CalculateDefectCodeDensity(model.PredictionRelease); int varCount = equations.GetUpperBound(1)+1; double[,] normalEquations = new double[varCount, varCount]; double[] normalResults = new double[varCount]; Func<double[,],double[],int,int,double> nc = (e, r, n1, n2) => { double sum = 0; for (int i = 0; i < numberOfEquations; i++) { if (n2 < numberOfEquations) { sum += e[i,n1] * e[i,n2]; } else { sum += e[i,n1] * r[i]; } } return sum; }; for (int i = 0; i < varCount; i++) { for (int j = 0; j < varCount; j++) { normalEquations[i,j] = nc(equations,results,i,j); } normalResults[i] = nc(equations,results,i,numberOfEquations); } var DCD = new Accord.Math.Decompositions.SingularValueDecomposition(normalEquations).Solve(normalResults); DCDF = new Dictionary<int,double>(); DCDA = new Dictionary<string,double>(); double DCD_min = 0.001; for (int i = 0; i < allFiles.Length; i++) { DCDF.Add(allFiles[i], DCD[i] > 0 ? DCD[i] : DCD_min); } for (int i = 0; i < allAuthors.Length; i++) { DCDA.Add(allAuthors[i], DCD[numberOfFiles + i] > 0 ? DCD[numberOfFiles + i] : DCD_min); } }
private static void svdUsingAccord(double[,] matrix) { var svdd = new Accord.Math.Decompositions.SingularValueDecomposition(matrix); //svd.U() * svd.W() * svd.VT() }