Selaa lähdekoodia

Fix NaNs in burndown interpolation

Vadim Markovtsev 7 vuotta sitten
vanhempi
commit
2ec9e46e74
2 muutettua tiedostoa jossa 93 lisäystä ja 4 poistoa
  1. 7 1
      burndown.go
  2. 86 3
      burndown_test.go

+ 7 - 1
burndown.go

@@ -527,6 +527,9 @@ func addBurndownMatrix(matrix [][]int64, granularity, sampling int, daily [][]fl
 				continue
 			}
 			decay := func(startIndex int, startVal float32) {
+				if startVal == 0 {
+					return
+				}
 				k := float32(matrix[y][x]) / startVal // <= 1
 				scale := float32((y+1)*sampling - startIndex)
 				for i := x * granularity; i < (x+1)*granularity; i++ {
@@ -545,6 +548,9 @@ func addBurndownMatrix(matrix [][]int64, granularity, sampling int, daily [][]fl
 				if startIndex < x*granularity {
 					startIndex = x * granularity
 				}
+				if startIndex == finishIndex {
+					return
+				}
 				avg := (finishVal - initial) / float32(finishIndex-startIndex)
 				for j := y * sampling; j < finishIndex; j++ {
 					for i := startIndex; i <= j; i++ {
@@ -585,7 +591,7 @@ func addBurndownMatrix(matrix [][]int64, granularity, sampling int, daily [][]fl
 				//  / y
 				if x*granularity <= y*sampling {
 					raise((y+1)*sampling, float32(matrix[y][x]))
-				} else {
+				} else if (y+1)*sampling > x*granularity {
 					raise((y+1)*sampling, float32(matrix[y][x]))
 					avg := float32(matrix[y][x]) / float32((y+1)*sampling-x*granularity)
 					for j := x * granularity; j < (y+1)*sampling; j++ {

+ 86 - 3
burndown_test.go

@@ -678,9 +678,14 @@ func TestBurndownAddMatrixCrazy(t *testing.T) {
 		  6  9 13
 	*/
 	addBurndownMatrix(added, 5, 3, daily, 0)
-	/*for _, row := range daily {
-		fmt.Println(row)
-	}*/
+	/*
+	for _, row := range daily {
+	  for _, v := range row {
+		  fmt.Print(v, " ")
+	  }
+		fmt.Println()
+	}
+	*/
 	// check pinned points
 	for y := 0; y < 5; y++ {
 		for x := 0; x < 3; x++ {
@@ -713,6 +718,84 @@ func TestBurndownAddMatrixCrazy(t *testing.T) {
 	}
 }
 
+func TestBurndownAddMatrixNaNs(t *testing.T) {
+	size := 4 * 4
+	daily := make([][]float32, size)
+	for i := range daily {
+		daily[i] = make([]float32, size)
+	}
+	added := make([][]int64, 4)
+	for i := range added {
+		added[i] = make([]int64, 4)
+		switch i {
+		case 0:
+			added[i][0] = 20
+		case 1:
+			added[i][0] = 18
+			added[i][1] = 30
+		case 2:
+			added[i][0] = 15
+			added[i][1] = 25
+			added[i][2] = 28
+		case 3:
+			added[i][0] = 12
+			added[i][1] = 20
+			added[i][2] = 25
+			added[i][3] = 40
+		}
+	}
+	// yaml.PrintMatrix(os.Stdout, added, 0, "test", true)
+	/*
+			"test": |-
+		  20 0  0  0
+		  18 30 0  0
+		  15 25 28 0
+		  12 20 25 40
+	*/
+	addBurndownMatrix(added, 4, 4, daily, 0)
+  /*
+	for _, row := range daily {
+	  for _, v := range row {
+		  fmt.Print(v, " ")
+	  }
+		fmt.Println()
+	}
+  */
+	// check pinned points
+	for y := 0; y < 4; y++ {
+		for x := 0; x < 4; x++ {
+			var sum float32
+			for i := x * 4; i < (x+1)*4; i++ {
+				sum += daily[(y+1)*4-1][i]
+			}
+			assert.InDelta(t, sum, added[y][x], 0.00001)
+		}
+	}
+	// check overall trend: 0 -> const -> peak -> decay
+	for x := 0; x < 16; x++ {
+		for y := 0; y < x; y++ {
+			assert.Zero(t, daily[y][x])
+		}
+		var prev float32
+		for y := x-4; y < x; y++ {
+			if y < 0 {
+				continue
+			}
+			if prev == 0 {
+				prev = daily[y][x]
+			}
+			assert.Equal(t, daily[y][x], prev)
+		}
+		for y := x; y < 16; y++ {
+			if prev == 0 {
+				prev = daily[y][x]
+			}
+			assert.True(t, daily[y][x] <= prev)
+			prev = daily[y][x]
+		}
+	}
+}
+
 func TestBurndownMergeGlobalHistory(t *testing.T) {
 	people1 := [...]string{"one", "two"}
 	res1 := BurndownResult{