Network Resnet50 {
	Layer CONV1 {
		Type: CONV
		Stride { X: 2, Y: 2 }
		Dimensions { K: 64, C: 3, R: 7, S: 7, Y:224, X:224 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}
	}

	Layer CONV2_1_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 64, C: 64, R: 1, S: 1, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}
	}

	Layer CONV2_1_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 64, C: 64, R: 3, S: 3, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}
	}

	Layer CONV2_1_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 64, R: 1, S: 1, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}
	}

	Layer CONV2_1_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 256, R: 1, S: 1, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}
	}

	Layer CONV2_2_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 64, C: 256, R: 1, S: 1, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV2_2_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 64, C: 64, R: 3, S: 3, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV2_2_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 64, R: 1, S: 1, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV2_2_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 256, R: 1, S: 1, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV2_3_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 64, C: 256, R: 1, S: 1, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV2_3_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 64, C: 64, R: 3, S: 3, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV2_3_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 64, R: 1, S: 1, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV2_3_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 256, R: 1, S: 1, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_1_1 {
		Type: CONV
		Stride { X: 2, Y: 2 }
		Dimensions { K: 128, C: 256, R: 1, S: 1, Y: 56, X: 56 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_1_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 128, C: 128, R: 3, S: 3, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_1_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 512, C: 128, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_1_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 512, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_2_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 128, C: 256, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_2_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 128, C: 128, R: 3, S: 3, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_2_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 512, C: 128, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_1_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 512, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_3_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 128, C: 256, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_3_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 128, C: 128, R: 3, S: 3, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_3_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 512, C: 128, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_3_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 512, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_4_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 128, C: 256, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_4_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 128, C: 128, R: 3, S: 3, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_4_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 512, C: 128, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV3_4_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 512, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_1_1 {
		Type: CONV
		Stride { X: 2, Y: 2 }
		Dimensions { K: 256, C: 512, R: 1, S: 1, Y: 28, X: 28 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}
	}

	Layer CONV4_1_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 256, R: 3, S: 3, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_1_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1024, C: 256, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_1_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_2_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_2_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 256, R: 3, S: 3, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_2_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1024, C: 256, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_2_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_3_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_3_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 256, R: 3, S: 3, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_3_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1024, C: 256, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_3_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_4_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_4_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 256, R: 3, S: 3, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}
	}

	Layer CONV4_4_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1024, C: 256, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_4_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_5_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_5_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 256, R: 3, S: 3, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_5_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1024, C: 256, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_5_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_6_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_6_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 256, C: 256, R: 3, S: 3, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_6_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1024, C: 256, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV4_6_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_1_1 {
		Type: CONV
		Stride { X: 2, Y: 2 }
		Dimensions { K: 512, C: 1024, R: 1, S: 1, Y: 14, X: 14 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_1_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 512, C: 512, R: 3, S: 3, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_1_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 2048, C: 512, R: 1, S: 1, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_1_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 2048, R: 1, S: 1, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_2_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 512, C: 2048, R: 1, S: 1, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_2_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 512, C: 512, R: 3, S: 3, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_2_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 2048, C: 512, R: 1, S: 1, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_2_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 2048, R: 1, S: 1, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_3_1 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 512, C: 2048, R: 1, S: 1, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_3_2 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 512, C: 512, R: 3, S: 3, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_3_3 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 2048, C: 512, R: 1, S: 1, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer CONV5_3_Residual {
		Type: DSCONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1, C: 2048, R: 1, S: 1, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

	Layer FC1000 {
		Type: CONV
		Stride { X: 1, Y: 1 }
		Dimensions { K: 1000, C: 2048, R: 7, S: 7, Y: 7, X: 7 }
		Dataflow {
			TemporalMap (1,1) K;
			TemporalMap (Sz(R), 1) Y;
			TemporalMap (Sz(S), 1) X;
			TemporalMap (Sz(R), Sz(R)) R;
			TemporalMap (Sz(S), Sz(S)) S;
			SpatialMap (1,1) C;
		}

	}

}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% compute joint speed according to speeddata variable
% vmax means maximum speed for each joint
% the other cases are scaled according to a maximum value of v6000
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Copyright (C) 2012, by Arturo Gil Aparicio
%
% This file is part of ARTE (A Robotics Toolbox for Education).
%
% ARTE is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% ARTE is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with ARTE.  If not, see <http://www.gnu.org/licenses/>.
function vel=obtain_joint_speed(robot, speeddata)

if strncmp(speeddata, 'vmax',4)
    vel=robot.velmax;
else
    [tag,remain] = strtok(speeddata, 'v');
    vel = robot.velmax.*str2num(tag)/6000;
end


function vect = convertxyz2Vect(xyz)

% CONVERTXYZ2VECT convert an xyz matrix into a vector.
%
%	Description:
%
%	channelsFinal = gradientDescent(skel, initialChannels, finalChannels,
%	error,step)
%
%	 Returns:
%	 VECT - a line vector
%	 Arguments:
%	 XYZ - the xyz matrix to be transformed

for i=1:size(xyz,1)
    for j=1:size(xyz,2)
        vect((i-1)*3 + j) = xyz(i,j);
    end
end


function [Gbest,CrowdDis] = UpdateGbest(Gbest,N)
% Update the global best set

%------------------------------- Copyright --------------------------------
% Copyright (c) 2023 BIMK Group. You are free to use the PlatEMO for
% research purposes. All publications which use this platform or any code
% in the platform should acknowledge the use of "PlatEMO" and reference "Ye
% Tian, Ran Cheng, Xingyi Zhang, and Yaochu Jin, PlatEMO: A MATLAB platform
% for evolutionary multi-objective optimization [educational forum], IEEE
% Computational Intelligence Magazine, 2017, 12(4): 73-87".
%--------------------------------------------------------------------------

    Gbest    = Gbest(NDSort(Gbest.objs,1)==1);
    CrowdDis = CrowdingDistance(Gbest.objs);
    [~,rank] = sort(CrowdDis,'descend');
    Gbest    = Gbest(rank(1:min(N,length(Gbest))));
    CrowdDis = CrowdDis(rank(1:min(N,length(Gbest))));
end


classdef gen80211aTestWaveform
    properties (Constant)
        %%
        fs  = 20e6 % sample rate
    end

    properties (Access = public)
        %%
        % carrier frequency
        fc
        % number of frames
        numPackets = 50
        % IEEE 802.11a Modulation and Coding Scheme [0-7]
        mcs = 2
        % Fix the WLAN frame length to a constant value? (true/false)
        constPktLen = true
        % Simulation seed
        % 0 - generate a random seed
        % xyz - seed is set to xyz
        seed = 0
    end

    properties (Access = public) % derived properties
        %%
        SampleTime_rx
        random_delay
        txPSDU
        txMPDU
        packetLen
        txWaveform
        MSDULenOctets
        MSDULenBits
        nht
    end

    properties (Access = public)
        %%
        noiseVar = 1e-6
        gain_per_packet
        rxWaveform
    end

    methods
        function obj = gen80211aTestWaveform(sim_settings, wlan_settings)
            mustBeMember(wlan_settings.fc,5180e6:20e6:5320e6);
            obj.fc = wlan_settings.fc;
            mustBeMember(wlan_settings.mcs,0:7);
            obj.mcs = wlan_settings.mcs;
            obj.constPktLen = wlan_settings.constPktLen;
            obj.seed = wlan_settings.seed;
            obj.numPackets = wlan_settings.numPackets;
            obj.SampleTime_rx = 1/obj.fs;
            obj.snr = sim_settings.snr;

            % Generate Non-HT Waveform
            obj = obj.genTestWaveform();
            if (sim_settings.SIM_STUDY == true)
                % apply channel impairments
                obj = obj.applyImpairments(sim_settings);
            end
        end
    end

    methods (Access = private)
        function obj = genTestWaveform(obj)
            % Generate 20 MHz Non-HT Waveform
            if (obj.seed == 0)
                obj.seed = int32(randi(intmax));
            end

            % If the data payload is of random length,
            % the minimum MSDU length is set to 250.
            % Otherwise, it is set to 2304.
            rng(obj.seed);
            if (obj.constPktLen)
                obj.MSDULenOctets = 2304*ones(obj.numPackets, 1);
            else
                obj.MSDULenOctets = randi([250 2304], obj.numPackets, 1);
            end
            rng(obj.seed);
            payload = randi([0 255], sum(obj.MSDULenOctets), 1);

            macConfig = wlanMACFrameConfig;
            macConfig.FrameType = 'Data';
            prev = 0;
            for ii = 1:obj.numPackets
                obj.nht{ii} = wlanNonHTConfig('MCS', obj.mcs, ...
                    'PSDULength', obj.MSDULenOctets(ii));

                macConfig.SequenceNumber = ii;
                [obj.txMPDU{ii}, lengthMPDU] = wlanMACFrame(payload(prev+1:prev+obj.MSDULenOctets(ii)), macConfig);
                prev = prev+obj.MSDULenOctets(ii);
                obj.nht{ii}.PSDULength = lengthMPDU;
                obj.txPSDU{ii} = reshape(de2bi(hex2dec(obj.txMPDU{ii}), 8)', [], 1);

                % WLAN waveform
                obj.txWaveform{ii} = wlanWaveformGenerator(obj.txPSDU{ii}, obj.nht{ii}, ...
                    'NumPackets',1,'IdleTime',20e-6).';
                obj.packetLen(ii) = length(obj.txWaveform{ii});
            end
            obj.MSDULenBits = (obj.MSDULenOctets+28)*8; % take overhead into account
            obj.txWaveform = cell2mat(obj.txWaveform).';
            obj.txWaveform = obj.txWaveform(:);

            % Start of the transmission is random
            obj.random_delay = round(2^17*(0.15+0.1*rand()));
            prepend_sig = zeros(obj.random_delay, 1);
            obj.txWaveform = [prepend_sig; obj.txWaveform];
        end

        function obj = applyImpairments(obj, sim_settings)
            % AWGN
            rng(obj.seed);
            awgnChan = comm.AWGNChannel('SignalPower',var(obj.txWaveform));
            awgnChan.NoiseMethod = 'Signal to noise ratio (SNR)';
            awgnChan.SNR = obj.snr;
            obj.rxWaveform = awgnChan(obj.txWaveform);
            % frequency/phase/timing offsets
            pfo = comm.PhaseFrequencyOffset('SampleRate', obj.fs, 'FrequencyOffset', 500, 'PhaseOffset', 30);
            obj.rxWaveform = pfo(obj.rxWaveform);

            % add channel impairments based on SIM_MODE
            if ((sim_settings.SIM_MODE == 2) || (sim_settings.SIM_MODE == 3))
                % Pass Non-HT waveform through a SISO channel.
                % The free-space path loss simulated is over a
                % (a) transmitter-to-receiver separation distance of 3 m,
                % (b) maximum Doppler shift of 3 Hz and
                % (c) an RMS path delay equal to 2x the sample time.
                dist = 30;
                pathLoss = 10^(-log10(4*pi*dist*(obj.fc/physconst('LightSpeed'))))*1e3;
                trms = 2/obj.fs;
                maxDoppShift = 3;
                rng(obj.seed);
                ch802 = comm.RayleighChannel('SampleRate',obj.fs,'MaximumDopplerShift',maxDoppShift,'PathDelays',trms);
                obj.rxWaveform = ch802(obj.rxWaveform)*pathLoss;
            end

            % arbitrary gain per packet
            if (sim_settings.GAIN_MODE == 0)
                obj.gain_per_packet = ones(obj.numPackets, 1);
                obj.rxWaveform = obj.txWaveform/150; % an arbitrary value to scale the entire waveform
            elseif (sim_settings.GAIN_MODE == 1)
                % Interpolated Gaussian random values as a model of gain
                % evolution. Values are scaled based on default AD9361 gain
                % table mappings.
                tmp_len = ceil(obj.numPackets/50)*50;
                tmp_g = randn(1,tmp_len/5);
                tmp_g = interp(tmp_g, 5);
                tmp_g = tmp_g-min(tmp_g);
                tmp_g = tmp_g/max(tmp_g);
                tmp_g = round(tmp_g*65);
                g = tmp_g(1:obj.numPackets);

                % Gain per packet in linear scale.
                obj.gain_per_packet = 10.^(g./20);
            end
            prev = obj.random_delay;
            for ii = 1:obj.numPackets
                obj.rxWaveform(prev+(1:obj.packetLen(ii)), :) = ...
                    obj.gain_per_packet(ii)*obj.rxWaveform(prev+(1:obj.packetLen(ii)), :);
                prev = prev+obj.packetLen(ii);
            end
        end
    end
end


function  exponent_m = separable(exponent_m,exponent_p,options);
%SEPARABLE Internal function, not used

% %exponent_m(sum((exponent_m>0),2)>2,:)=[];
%
% card = max(sum((exponent_p>0),2));
%
% n_less = exponent_m(sum((exponent_m>0),2)<card,:);
% n_equ  = exponent_m(sum((exponent_m>0),2)==card,:);
% n_larg = exponent_m(sum((exponent_m>0),2)>card,:);
%
% A = minksum(n_less,n_less);
% B = minksum(n_less,n_equ);
% C = minksum(n_less,n_larg);
% D = minksum(n_equ,n_equ);
% E = minksum(n_equ,n_larg);
% F = minksum(n_larg,n_larg);

disconnected = [];
for i = 1:size(exponent_p,2)
    for j = i+1:size(exponent_p,2)
        if ~any(exponent_p(:,i) & exponent_p(:,j))
            disconnected = [disconnected;i j];
        end
    end
end

for i = 1:size(disconnected,1)
    j = disconnected(i,1);
    k = disconnected(i,2);
    n0 = find(~exponent_m(:,j) & ~exponent_m(:,k));
    nx = find(exponent_m(:,j) & ~exponent_m(:,k));
    nz = find(~exponent_m(:,j) & exponent_m(:,k));
    nxz = find(exponent_m(:,j) & exponent_m(:,k));

%     m0 = exponent_m(n0,:);
%     mx = exponent_m(nx,:);
%     mz = exponent_m(nz,:);
%     mxz = exponent_m(nxz,:);
%
%     from_E = minksum(mx,mz);
%     from_B = minksum([m0;mx;mz],mxz);
%     from_C = minksum(mxz,mxz);
%     m_e = exponent_m(union(nx,nz),:)
%     m_cb = exponent_m(union(nx,nz),:)
    exponent_m = exponent_m([n0;nx;nz],:);
end

function msum = minksum(a,b);
msum = [];
for i = 1:size(a,1)
    for j = i:size(b,1)
        msum = [msum;a(i,:)+b(j,:)];
    end
end


classdef SymBuilder < handle
%SYMBUILDER  Create a SYMBUILDER object for creating symbolic optimization problems
%
%   B = SymBuilder() creates a blank optimization problem
%
%   See also SymBuilder.AddObj SymBuilder.AddCon SymBuilder.Build
%
%   Copyright (C) 2012 Jonathan Currie (www.inverseproblem.co.nz)

    properties(SetAccess=private)
        vars        %Symbolic array of symbolic variables
        sobj        %Symbolic matrix of equations
        jac         %Symbolic jacobian of equations
        hess        %Structure of hessians of each equation
        hesslag     %Symbolic hessian of the lagrangian
        Opt         %OPTI object
        lastSolveOpts %Last Options passed when Solve() was called
    end

    properties(SetAccess=private)%,GetAccess=private)
        eqs         %Equations symbolic array
        cl          %Constraint Lower Bounds
        cu          %Constraint Upper Bounds
        constnt     %Cell array of constants
        exprsn      %Cell array of expressions
        bnds        %Cell array of bounds
        lb          %Double array of lower bounds
        ub          %Double array of upper bounds
        vartypes    %Cell array of variable types
        xtype       %Char array of variable types
        indobj      %Index of objectives in equations
        objlin      %Index of linear, quadratic and nonlinear objectives
        conlin      %Index of linear, quadratic and nonlinear constraints
        objbias     %Problem bias terms (for linear and quadratic problems)
        noObjs      %Counter of number objectives
        noCons      %Counter of number of constraints
        bldstat     %Build Status
        bldtime     %Build Time
        resgrp      %Cell array of result groups
        resexp      %Cell array of result expressions
        verbose     %Verbosity mode
    end

    methods
        function B = SymBuilder(verbose)
            if(nargin < 1), verbose = true; end
            if (~exist('syms.m','file')), error('The Symbolic Math Toolbox must be installed to use SymBuilder!'); end
            %Initialization
            B.noObjs = 0;
            B.noCons = 0;
            B.verbose = verbose;
            Unbuild(B);
        end

        function B = AddObj(B,str)
        %Add a General Objective (Linear or Nonlinear)

            %Check for string
            if(ischar(str))
                digits(16);
                wstate = warning('off','symbolic:sym:sym:DeprecateExpressions');
                s = sym(str);
                warning(wstate);
            elseif(isa(str,'sym'))
                s = str;
            else
                error('Unknown objective form');
            end

            %Concatenate with existing equations
            B.eqs = [B.eqs;s];
            B.cl = [B.cl;NaN];
            B.cu = [B.cu;NaN];
            if(isempty(B.indobj))
                B.indobj = length(B.cl);
            else
                B.indobj = [B.indobj;length(B.cl)];
            end
            %Add no objs
            B.noObjs = B.noObjs + 1;
            %Indicate Rebuild Required
            Unbuild(B);
        end

        function B = AddCon(B,str_in,cl,cu)
        %Add a General Constraint (Linear or Nonlinear)

            %Check for string
            if(ischar(str_in))
                %Parse constraint string
                [str,l,u] = SymBuilder.parseConstraint(str_in);
                digits(16);
                wstate = warning('off','symbolic:sym:sym:DeprecateExpressions');
                s = sym(str);
                warning(wstate);
            elseif(isa(str_in,'sym'))
                if(nargin < 4 || ~isnumeric(cl) || ~isnumeric(cu) || length(cl)~=length(cu) || length(cl)~=length(str_in))
                    error('When supplying a symbolic expression to AddCon, you must supply as AddCon(sym_con,cl,cu) with cl, cu as numeric vectors of the same length.');
                end
                if(size(str_in,2) > 1)
                    s = str_in.';
                else
                    s = str_in;
                end
                l = cl; u = cu;
            else
                 error('Unknown constraint form');
            end
            %Concatenate with existing equations if not empty
            if(~isempty(s))
                B.eqs = [B.eqs;s];
                B.cl = [B.cl;l];
                B.cu = [B.cu;u];
                %Add no cons
                B.noCons = B.noCons + length(l);
                %Indicate Rebuild Required
                Unbuild(B);
            else
                optiwarn('symb:emptycon','The following constraint will be ignored by SymBuilder as both sides appear to be numeric.\n  %s\n',str_in);
            end
        end

        function B = AddLinCon(B,x,A,rl,ru)
        %Add a Linear Constraint

            if(nargin < 5 || ~isnumeric(rl) || ~isnumeric(ru) || length(rl)~=length(ru) || length(rl)~=size(A,1))
                error('When supplying linear constraints, you must supply as AddLinCon(x,A,rl,ru) with rl, ru as numeric vectors of the same length.');
            elseif(~isa(x,'sym') || length(x) ~= size(A,2))
                error('x must be a symbolic variable vector = size(A,2)');
            end
            %Evaluate Matrix & Store
            B.eqs = [B.eqs;A*x];
            B.cl = [B.cl;rl];
            B.cu = [B.cu;ru];
            %Add no cons
            B.noCons = B.noCons + length(rl);
            %Indicate Rebuild Required
            Unbuild(B);
        end

        function B = AddConstraint(B,str)
        %Same as AddCon()
            B = AddCon(B,str);
        end

        function B = AddConstant(B,str,val,varargin)
        %Identify variable as a constant

            %Concatenate with existing constants
            B.constnt = [B.constnt; {str val}];
            %If user has passed multiple constants, process all
            if(nargin > 3 && ~isempty(varargin))
                if(mod(length(varargin),2))
                    error('You must supply a name and value for each constant');
                else
                    for i = 1:2:length(varargin)
                        B.constnt = [B.constnt; varargin(i:i+1)];
                    end
                end
            end
            %Indicate Rebuild Required
            Unbuild(B);
        end

        function B = AddExpression(B,str,grp,ex)
        %Identify variable as an expression

            %Parse expression string
            [str,exp] = SymBuilder.parseExpression(str);
            %Concatenate with existing expressions
            B.exprsn = [B.exprsn; {str exp}];
            %If group passed, add to result group
            if(nargin > 3), B = AddResultExp(B,grp,exp,ex);
            elseif(nargin > 2), B = AddResultExp(B,grp,exp); end
            %Indicate Rebuild Required
            Unbuild(B);
        end

        function B = AddBound(B,str)
        %Add variable bound

            %Parse expression string
            [var,llb,lub] = SymBuilder.parseBound(str);
            %Concatenate with existing bounds
            B.bnds = [B.bnds; {var llb lub}];
            %Indicate Rebuild Required
            Unbuild(B);
        end

        function B = AddBounds(B,x,lb,ub)
        %Add numerical bounds

            bds = cell(length(x),3);
            for i = 1:length(x)
                bds{i,1} = char(x(i));
                bds{i,2} = sprintf('%1.15g',lb(i));
                bds{i,3} = sprintf('%1.15g',ub(i));
            end
            %Concatenate with existing bounds
            B.bnds = [B.bnds; bds];
            %Indicate Rebuild Required
            Unbuild(B);
        end

        function B = AddInteger(B,str)
        %Add integer constraint

            %Parse expression string
            [var,xx] = SymBuilder.parseInteger(str);
            %Concatenate with existing constants
            B.vartypes = [B.vartypes; {var xx}];
            %Indicate Rebuild Required
            Unbuild(B);
        end

        function B = AddIntegers(B,x,str)
        %Add integer constraints with character string

            xx = cell(length(x),2);
            for i = 1:length(x)
                xx{i,1} = char(x(i));
                xx{i,2} = str(i);
            end
            %Concatenate with existing constants
            B.vartypes = [B.vartypes; xx];
            %Indicate Rebuild Required
            Unbuild(B);
        end

        function B = AddResultGroup(B,name,str)
        %Add Result Group
            %Concatenate with existing groups
            B.resgrp = [B.resgrp; {name str}];
        end

        function B = AddResultExp(B,name,str,bin)
        %Add Result Expression
            %Parse expression string
            [group,name] = SymBuilder.parseResExp(name);
            %Concatenate with existing groups
            if(nargin > 3)
                B.resexp = [B.resexp; {group name str bin}];
            else
                B.resexp = [B.resexp; {group name str []}];
            end
        end

        function B = Draft(B)
        %Draft the object by solving for the system Jacobian
            t = tic;
            %Build Symbolic representation of the equations
            if(B.verbose), fprintf('\nGenerating Symbolic Representation of Equations...'); end
            buildSymRep(B);
            if(B.verbose), fprintf('Done\n'); end
            %Generate Equations Jacobian
            if(B.verbose), fprintf('Generating Symbolic Jacobian...'); end
            buildJac(B);
            if(B.verbose), fprintf('Done\n'); end
            %Determine Linear & Nonlinear Equations
            if(B.verbose), fprintf('Generating Equation Linearity...'); end
            detLinearity(B);
            if(B.verbose), fprintf('Done\n'); end
            %Save build time
            B.bldtime = toc(t);
            %Assign build Status
            B.bldstat = 'draft';
        end

        function B = Build(B)
        %Build the object by solving for the system Hessian
            t = tic;
            %Build Symbolic representation of the equations
            if(B.verbose), fprintf('\nGenerating Symbolic Representation of Equations...'); end
            buildSymRep(B);
            if(B.verbose), fprintf('Done\n'); end
            %Generate Equations Jacobian
            if(B.verbose), fprintf('Generating Symbolic Jacobian...'); end
            buildJac(B);
            if(B.verbose), fprintf('Done\n'); end
            %Generate Equations Hessians (also determines linearity)
            if(B.verbose), fprintf('Generating Symbolic Hessian...'); end
            buildHess(B);
            if(B.verbose), fprintf('Done\n'); end
            %Save build time
            B.bldtime = toc(t);
            %Assign build Status
            B.bldstat = 'built';
        end

        function B = Unbuild(B)
        %Unbuild object (free memory)

            B.jac = [];
            B.hess = [];
            B.hesslag = [];
            B.bldstat = 'unbuilt';
            B.bldtime = 0;
            B.Opt = [];

            clear symb_cb
        end

        function prob = GetLinProb(B)
        %Get Linear Problem Matrices [min f'*x s.t. rl <= A*x <= ru]

            %Check is built
            IsBuilt(B,1);
            prob = optiprob;
            %Get Linear Objective Index
            ind = B.objlin == 1;
            if(sum(ind) == 0)
                error('This object does not contain a linear objective');
            end
            prob.f = double(B.jac(ind,:))';
            %Get Linear Constraint Indices
            ind = B.conlin == 1;
            %Check we have some constraints
            if(B.noCons && sum(ind) > 0)
                if(isempty(B.objbias)), B.objbias = zeros(size(ind)); end %HACK
                %Get Linear Jacobian
                prob.A = sparse(double(B.jac(ind,:)));
                prob.rl = B.cl(ind) - B.objbias(ind);
                prob.ru = B.cu(ind) - B.objbias(ind);
            end
            %Bounds & Integer Vars
            prob.lb = B.lb;
            prob.ub = B.ub;
            prob.int = B.xtype;
            prob.objbias = B.objbias(B.indobj);
            %Problem Name
            if(any(B.xtype=='I'))
                prob.Name = 'SymBuilder MILP';
            elseif(any(B.xtype=='B'))
                prob.Name = 'SymBuilder BILP';
            else
                prob.Name = 'SymBuilder LP';
            end
        end

        function prob = GetQuadProb(B)
        %Get Quadratic Problem Matrices [min 0.5*x'*H'x + f'*x
        %s.t. rl <= A*x <= ru, qrl <= x'*Q*x + l'*x <= qru]

            %Check is built
            IsBuilt(B,1);
            prob = optiprob;
            %Get quadratic objective indices
            ind = B.objlin == 2;
            if(isempty(ind))
                error('This object does not contain an objective');
            elseif(sum(ind) > 1)
                error('This interface only supports a single quadratic objective');
            end
            %Get Hessian (DON'T NEED 0.5!)
            if(~any(ind)) %linear objective
                ind = B.objlin == 1;
                n = size(B.jac,2);
                prob.H = spalloc(n,n,0);
                prob.f = double(B.jac(ind,:));
            else
                prob.H = sparse(double(B.hess(ind).H));
                %Get Gradient, remove 2nd derivative parts
                f = B.jac(ind,:); v = symvar(f);
                prob.f = double(subs(f,v,{zeros(size(v))}).');
            end

            %Get Linear Constraint Indices
            ind = B.conlin == 1;
            %Check we have some constraints
            if(B.noCons && sum(ind) > 0)
                %Get Linear Jacobian
                prob.A = sparse(double(B.jac(ind,:)));
                prob.rl = B.cl(ind) - B.objbias(ind);
                prob.ru = B.cu(ind) - B.objbias(ind);
            end
            %Get Quadratic Constraint Indices
            ind = B.conlin == 2;
            %Check we have some constraints
            if(B.noCons && sum(ind) > 0)
                prob.qrl = B.cl(ind) - B.objbias(ind);
                prob.qru = B.cu(ind) - B.objbias(ind);
                ind = find(ind);
                %Get each quadratic constraint
                len = length(ind);
                prob.Q = cell(len,1);
                prob.l = cell(len,1);
                for i = 1:len
                    %Get Hessian (0.5* requried!)
                    prob.Q{i} = 0.5*sparse(double(B.hess(ind(i)).H));
                    %Get Gradient, remove 2nd derivative parts
                    f = B.jac(ind(i),:); v = symvar(f);
                    prob.l{i} = double(subs(f,v,{zeros(size(v))}).');
                end
            end
            %Bounds & Integer Vars
            prob.lb = B.lb;
            prob.ub = B.ub;
            prob.int = B.xtype;
            prob.objbias = B.objbias(B.indobj);
            %Problem Name
            if(any(B.xtype=='I'))
                prob.Name = 'SymBuilder MIQP';
            else
                prob.Name = 'SymBuilder QP';
            end
        end

        function prob = GetNLProb(B,opts)
        %Get Nonlinear Problem Callbacks, generating files as we go

            if(nargin < 2), opts = symbset; end
            opts.verbose = B.verbose;
            %Check is built
            IsBuilt(B,1);
            prob = optiprob;
            %Determine most efficient callback form IF auto selected
            if(strcmpi(opts.cbmode,'auto'))
                %Only relevant if we have any nonlinear terms & > 8 variables
                if((any(B.objlin > 2) || any(B.conlin > 2)) && length(B.vars) > 8)
                    %See if we have 2nd deriv info
                    if(~isempty(B.hess))
                        %Generate Hess Lag (will need it later anyway)
                        buildHessLag(B);
                        %Build Hessian Structure
                        lHstr = zeros(size(B.hesslag));
                        lHstr(logical(B.hesslag ~= 0)) = 1;
                        %If greater than 10% dense, use CppAD
                        if(nnz(lHstr)/numel(lHstr) > 0.1)
                            if(SymBuilder.CheckCppADCompile(false))
                                opts.cbmode = 'cppad';
                            else
                                opts.cbmode = 'mcode';
                            end
                        else
                            opts.cbmode = 'mcode';
                        end
                    %Only 1st deriv info
                    else
                        ind = B.conlin > 0;
                        ajac = B.jac(ind,:);
                        %Build Jacobian Structure
                        jacstr = zeros(size(ajac));
                        jacstr(logical(ajac ~= 0)) = 1;
                        %If greater than 10% dense, use CppAD
                        if(nnz(jacstr)/numel(jacstr) > 0.1)
                            if(SymBuilder.CheckCppADCompile(false))
                                opts.cbmode = 'cppad';
                            else
                                opts.cbmode = 'mcode';
                            end
                        else
                            opts.cbmode = 'mcode';
                        end
                    end
                else
                    opts.cbmode = 'mcode';
                end
            end
            %Determine whether we are generating C or M files
            if(strcmpi(opts.cbmode,'mcode'))
                fgen = 'M';
            elseif(strcmpi(opts.cbmode,'cppad'))
                fgen = 'A';
            else
                fgen = 'C';
            end
            %Create New Callback Function based on req'd callbacks
            opts.havCon = any(B.conlin > 0);
            if(fgen == 'M')
                B.buildMFun('new',[],[],opts);
            else
                B.buildCFun('new',[],[],opts);
            end
            %Get Objective (Nonlinear or not, returned as f(x))
            ind = B.objlin >= 1;
            if(sum(ind) == 0)
                error('This object does not contain an objective');
            end
            %Build Objective Callback
            if(fgen == 'M')
                prob.fun = B.buildMFun('obj',B.sobj(ind),B.vars,opts);
            else
                prob.fun = B.buildCFun('obj',B.sobj(ind),B.vars,opts);
            end
            %If requested, build gradient callback
            if(strcmpi(opts.use1stDerivs,'yes'))
                if(fgen == 'A')
                    prob.f = @(x) symb_ccb('grad',x); %no need to generate
                else
                    ajac = B.jac(ind,:);
                    if(fgen == 'M')
                        prob.f = B.buildMFun('grad',ajac,B.vars,opts);
                    else
                        prob.f = B.buildCFun('grad',ajac,B.vars,opts);
                    end
                end
            elseif(fgen=='C')
                B.buildCFun('grad'); %default empty
            end

            %If we have constraints, create callbacks
            if(opts.havCon)
                %Get ALL Constraint Indices
                ind = B.conlin > 0;
                %Build Con Callback + row constraints
                if(fgen == 'M')
                    prob.nlcon = B.buildMFun('con',B.sobj(ind),B.vars,opts);
                else
                    prob.nlcon = B.buildCFun('con',B.sobj(ind),B.vars,opts);
                end
                prob.cl = B.cl(ind);
                prob.cu = B.cu(ind);
                %If we want derivatives, create jacobian + structure
                if(strcmpi(opts.use1stDerivs,'yes'))
                    if(fgen == 'A')
                        prob.nljac = @(x) symb_ccb('jac',x); %no need to generate
                        prob.nljacstr = @() symb_ccb('jacstr');
                    else
                        ajac = B.jac(ind,:);
                        if(fgen == 'M')
                            prob.nljac = B.buildMFun('jac',ajac,B.vars,opts);
                        else
                            prob.nljac = B.buildCFun('jac',ajac,B.vars,opts);
                        end
                        %Build Jacobian Structure Callback
                        jacstr = zeros(size(ajac));
                        jacstr(logical(ajac ~= 0)) = 1;
                        prob.nljacstr = @() sparse(jacstr);
                    end
                elseif(fgen=='C')
                    B.buildCFun('jac'); %default empty
                end
            elseif(fgen=='C' || fgen=='A')
                B.buildCFun('con',[],[],opts); %default empty
                B.buildCFun('jac',[],[],opts); %default empty
            end
            %If we want 2nd derivatives, add them too
            if(strcmpi(opts.use2ndDerivs,'yes'))
                if(fgen == 'A')
                    prob.H = @(x,sigma,lambda) symb_ccb('hess',x,sigma,lambda); %no need to generate
                    prob.Hstr = @() symb_ccb('hstr');
                else
                    %Check if we have done a full build
                    if(isempty(B.hess))
                        if(B.verbose), optiwarn('No 2nd Derivatives Added - You may only obtain the Hessian of the Lagrangian if you called Build().\nDraft() only computes 1st Derivatives%s\n','.'); end
                        if(fgen=='C')
                            B.buildCFun('hess'); %default empty
                        end
                    else
                        %Build HessLag
                        buildHessLag(B);
                        %Build NL Hessian Callback
                        if(fgen=='M')
                            prob.H = B.buildMFun('hess',B.hesslag,B.vars,opts);
                        else
                            prob.H = B.buildCFun('hess',B.hesslag,B.vars,opts,B.noCons);
                        end
                        %Build Hessian Structure
                        lHstr = zeros(size(B.hesslag));
                        lHstr(logical(B.hesslag ~= 0)) = 1;
                        prob.Hstr = @() sparse(lHstr);
                    end
                end
            elseif(fgen=='C')
                B.buildCFun('hess'); %default empty
            end

            %Bounds & Integer Vars
            prob.lb = B.lb;
            prob.ub = B.ub;
            prob.int = B.xtype;
            %Problem Name
            if(any(B.xtype=='I'))
                prob.Name = 'SymBuilder MINLP';
            else
                prob.Name = 'SymBuilder NLP';
            end

            %Generate pretend x0 incase none given
            prob.x0 = (prob.ub - prob.lb)./2;
            prob.x0(isnan(prob.x0)) = 0;
            prob.x0(isinf(prob.x0)) = 0;

            %Compile if C Code
            if(fgen ~= 'M')
                if(B.verbose), fprintf('Compiling....'); end
                %If compiling with VS2015 but pre R2015a, need to manually add in UCRT location
                cc = mex.getCompilerConfigurations(); post = [];
                for i = 1:length(cc)
                    if(~isempty(strfind(cc(i).Name,'Microsoft Visual C++')) && str2double(cc(i).Version) >= 14 && verLessThan('matlab','8.5'))
                        post = opti_FindUCRT();
                        break;
                    end
                end
                if(fgen == 'A')
                    src = 'symb_ccb.cpp';
                    %find cppad source (expected in utilities folder)
                    str = which('asl');
                    if(isempty(str)), error('Cannot find asl to locate CppAD source!'); end
                    idx = strfind(str,filesep); str = str(1:idx(end));
                    str = [str 'Source'];
                    str = ['mex -largeArrayDims symb_ccb.cpp -I"' str '" ' post];
                    if(strcmpi(computer,'PCWIN'))
                        str = [str ' -DCPPAD_SIZE_T_SAME_UNSIGNED_INT=1'];
                    end
                	eval(str);
                else
                    src = 'symb_ccb.c';
                    str = ['mex -largeArrayDims symb_ccb.c ' post];
                    eval(str);
                end
                if(B.verbose), fprintf('Done\n'); end
                if(strcmpi(opts.srckeep,'no'))
                    delete(src);
                end
            end
        end

        %Get Build Status
        function tf = IsBuilt(B,doErr)
            if(nargin < 2), doErr = false; end
            if(strcmp(B.bldstat,'unbuilt'))
                tf = false;
                if(doErr)
                    error('Please build the object using Draft() or Build()');
                end
            else
                tf = true;
            end
        end

        function [x,fval,ef,info] = solve(B,x0,opts)
        %Lowercase version
            if(nargin < 3), opts = []; end
            if(nargin < 2), x0 = []; end
            [x,fval,ef,info] = Solve(B,x0,opts);
        end

        function [x,fval,ef,info] = Solve(B,x0,opts)
        %Solve Object using OPTI

            %Check is built
            if(~IsBuilt(B))
                error('Please build the object first using Draft() or Build()');
            end
            if(nargin < 3 || isempty(opts)), opts = symbset; end
            if(nargin < 2), x0 = []; end

            %Cusomtize settings based on solver
            switch(lower(opts.solver))
                %White box solvers
                case {'scip','baron'}
                     opts = symbset(opts,'use1stDerivs','no','use2ndDerivs','no','preallocate','no');
                %Derivative free solvers
                case {'nomad','pswarm','gmatlab'}
                    opts = symbset(opts,'use1stDerivs','no','use2ndDerivs','no');
                %No Hessian Support
                case {'filtersd','lbfgsb','nlopt'}
                    opts = symbset(opts,'use2ndDerivs','no');
            end
            if (isempty(B.Opt) || isempty(B.lastSolveOpts) || ~isequal(B.lastSolveOpts, opts))
                if(B.verbose), fprintf('\nGenerating OPTI Object....\n'); end
                B.Opt = GetOPTI(B,opts);
                B.lastSolveOpts = opts;
                if(B.verbose), fprintf('Done\n\n'); end
            else
                if(B.verbose), fprintf('\nRe-using OPTI Object\n'); end
            end
            %Solve
            [x,fval,ef,info] = solve(B.Opt,x0);
        end

        function B = plus(B,C)
        %Add objective, constraint, bound or integer declaration to SymBuilder Object
            if(~isa(B,'SymBuilder'))
                error('The LHS object must be a SymBuilder Object');
            end
            if(~ischar(C))
                error('The RHS object must be a string');
            end
            %Check for objective
            idx = strfind(C,'min');
            if(~isempty(idx))
                if(length(idx) > 1), error('min most only appear once in the objective'); end
                B.AddObj(C(idx(1)+4:end));
                return;
            end
            idx = strfind(C,'max');
            if(~isempty(idx))
                if(length(idx) > 1), error('max most only appear once in the objective'); end
                B.AddObj(['-(' C(idx(1)+4:end) ')']);
                return;
            end
            %Check for bound or integer (no mathematical ops)
            idx = regexp(C,{'*','+','-','/','^'});
            if(~isempty([idx{:}]))
                B.AddCon(C);
            else
                idx = regexp(C,{'<=','>='});
                if(~isempty([idx{:}]))
                    B.AddBound(C);
                else
                    B.AddInteger(C);
                end
            end

        end
    end

    methods(Access=private)

        function buildSymRep(B)
        %Build symbolic representation of the equations

            %Check if something new has been added
            if(strcmp(B.bldstat,'unbuilt'))
                %Build Symbolic Object
                symobj = B.eqs;
                %Substitute expressions
                if(~isempty(B.exprsn))
                    %Now subs into full equation system
                    wstate = warning('off','symbolic:sym:sym:DeprecateExpressions');
                    symobj = subs(symobj,B.exprsn(:,1),B.exprsn(:,2));
                    warning(wstate);
                    %Have to repeat until all nested expressions are sub'd
                    n = 10;  %max depth
                    no = size(B.exprsn,1);
                    se = sym(B.exprsn(:,1));
                    while n > 0
                        v = symvar(symobj); alldone = 1;
                        for i = 1:no
                            if(any(se(i) == v))
                                wstate = warning('off','symbolic:sym:sym:DeprecateExpressions');
                                symobj = subs(symobj,B.exprsn(i,1),B.exprsn(i,2));
                                warning(wstate);
                                alldone = 0;
                            else
                                if(i == no && alldone) %ensure we have checked them all
                                    n = -10;
                                    break;
                                end
                            end
                        end
                        n = n - 1;
                    end
                    if(n == 0)
                        error('Maximum expression recursion depth reached!');
                    else
%                         fprintf('%d exp recursions required\n',n+10);
                    end
                end
                %Convert constants to decimal form
%                 digits(16); %set vpa digits
%                 BV = cell(size(B.constnt,1),1);
%                 for i = 1:size(B.constnt,1)
%                     BV{i} = sym(B.constnt{i,2},'d');
%                 end
                %Substitute constants
                if(~isempty(B.constnt))
                    wstate = warning('off','symbolic:sym:sym:DeprecateExpressions');
                    symobj = subs(symobj,B.constnt(:,1),B.constnt(:,2));
                    warning(wstate);
                end
                %Save symbolic vector
                B.sobj = symobj;
                %Save Variables
                B.vars = symvar(B.sobj);

                %Build default bounds and xtype
                n = length(B.vars);
                B.lb = -1*Inf(n,1);
                B.ub = Inf(n,1);
                B.xtype = repmat('C',1,n);
                %Get names of variables and their indices
                names = SymBuilder.detVarNames(B.vars);
                if(isempty(names) && size(B.bnds,1) > 0)
                    error('Cannot process bounds without declared variables!');
                end

                %Process bound declarations
                for i = 1:size(B.bnds,1)
                    %Check if bounds are numerical
                    llb = str2double(B.bnds{i,2});
                    if(isnan(llb)) %not a number, check constants
                        try
                            ind = strcmp(B.constnt(:,1),B.bnds{i,2});
                            if(any(ind))
                                llb = B.constnt{ind,2};
                            else
                                error('Unknown lower bound: %s',B.bnds{i,2});
                            end
                        catch
                            error('Error processing lower bound for var %d',i);
                        end
                    end
                    lub = str2double(B.bnds{i,3});
                    if(isnan(lub)) %not a number, check constants
                        try
                            ind = strcmp(B.constnt(:,1),B.bnds{i,3});
                            if(any(ind))
                                lub = B.constnt{ind,2};
                            else
                                error('Unknown upper bound: %s',B.bnds{i,3});
                            end
                        catch
                            error('Error processing upper bound for var %d',i);
                        end
                    end
                    %Check if variable exists
                    ind = logical(B.vars == sym(B.bnds{i,1}));
                    if(any(ind))
                        if(~isinf(llb)), B.lb(ind) = llb; end
                        if(~isinf(lub)), B.ub(ind) = lub; end
                    else %could be applied to multiple variables
                        ind = strcmp(names(:,1),B.bnds{i,1});
                        if(isempty(ind) || all(ind  == 0))
                            error('Unknown bound: %s',B.bnds{i,1});
                        elseif(sum(ind) > 1)
                            error('Bound name is ambiguous and matches more than one variable name');
                        else
                            %Extract indices
                            start = names{ind,2}(1);
                            send = names{ind,2}(end);
                            if(~isinf(llb)), B.lb(start:send) = llb; end
                            if(~isinf(lub)), B.ub(start:send) = lub; end
                        end
                    end
                end

                %Process integer declarations
                for i = 1:size(B.vartypes,1)
                    %Check if variable exists
                    ind = logical(B.vars == sym(B.vartypes{i,1}));
                    if(any(ind))
                         B.xtype(ind) = B.vartypes{i,2};
                    else %could be applied to multiple variables
                        ind = strcmp(names(:,1),B.vartypes{i,1});
                        if(isempty(ind))
                            error('Unknown variable: %s',B.vartypes{i,1});
                        elseif(sum(ind) > 1)
                            error('Variable name is ambiguous and matches more than one variable name');
                        else
                            %Extract indices
                            start = names{ind,2}(1);
                            send = names{ind,2}(end);
                            B.xtype(start:send) = B.vartypes{i,2};
                        end
                    end
                end
            end
        end

        function buildJac(B)
        %Evaluate Jacobian of entire equation system

            if(isempty(B.sobj))
                error('You must build a symbolic representation of the system first!');
            end
            %Call SymToolbox jacobian function
            B.jac = jacobian(B.sobj);
        end

        function buildHess(B)
        %Evaluate Hessian(s) of entire equation system

            if(isempty(B.jac))
                error('You must evaluate the Jacobian of the system first!');
            end
            noeq = B.noObjs + B.noCons;
            B.hess = struct('H',cell(noeq,1),'lin',cell(noeq,1));
            %Build Index Vectors
            B.conlin = zeros(noeq,1);
            B.objlin = zeros(noeq,1);
            B.objbias = zeros(noeq,1);
            %Go through each equation
            for i = 1:noeq
                J = B.jac(i,:);
                %Determine if linear
                if(isempty(symvar(J)))
                    B.hess(i).lin = 1;
                    B.hess(i).H = 0;
                else
                    %Hessian is the Jacobian of the Jacobian (in this case)
                    H = jacobian(J,B.vars);
                    s = symvar(H);
                    %Determine if quadratic
                    if(isempty(s))
                        B.hess(i).lin = 2;
                        B.hess(i).H = H;
                    else
                        %Otherwise must be nonlinear, save entire symobj (for now)
                        B.hess(i).lin = 3;
                        B.hess(i).H = H;
                    end
                end
                %If linear or quadratic, save bias term
                if(B.hess(i).lin <= 2)
                    eq = B.sobj(i);
                    v = symvar(eq);
                    %Find bias term
                    B.objbias(i) = double(subs(eq,v,{zeros(size(v))}));
                end

                %Save linearity
                if(any(B.indobj == i))
                    B.objlin(i) = B.hess(i).lin;
                else
                    B.conlin(i) = B.hess(i).lin;
                end
            end
        end

        function buildHessLag(B)
        %Build Lagrangian Hessian assuming IPOPT (tril) format

            if(isempty(B.hess))
                error('You must evaluate the Hessian of the system first!');
            elseif(~isempty(B.hesslag))
                return; %already done
            end
            %Start with objective
            nvars = length(B.vars);
            ind = B.objlin >= 2;
            if(any(ind)) %check we have a nonlinear (or quadratic) objective
                if(sum(ind) > 1)
                    error('This interface only support single objective problems');
                end
                s = sym('sigma');
                objH = B.hess(ind).H;
                H = s*objH;
            else
                H = zeros(nvars);
            end
            %Now each nonlinear (or quadratic) constraint
            ind = B.conlin > 1;
            %Two sets of indexes, one for lambda, one for B.hess
            index_BH = find(ind);
            ind(B.indobj) = [];
            index_L = find(ind);
            wstate = warning('off','symbolic:sym:sym:DeprecateExpressions');
            for i = 1:length(index_BH)
                l = sym(sprintf('lambda(%d)',index_L(i)));
                H = H + l*B.hess(index_BH(i)).H;
            end
            warning(wstate);
            %Save resulting Hessian
            B.hesslag = tril(H);
        end

        function detLinearity(B)
        %Determine linearity of the supplied equations (without Hessian)

            if(isempty(B.jac))
                error('You must evaluate the Jacobian of the system first!');
            end
            %Build Index Vectors
            noeq = B.noCons + B.noObjs;
            B.conlin = zeros(noeq,1);
            B.objlin = zeros(noeq,1);
            B.objbias = zeros(noeq,1);
            %Determine Linearity (based on existence of symvars)
            for i = 1:noeq %must search all equations
                %Gather first derivative vars
                s = symvar(B.jac(i,:));
                %Objective
                if(any(B.indobj == i))
                    if(isempty(s))
                        B.objlin(i) = 1; %lin
                    else
                        B.objlin(i) = 3; %nonlin
                    end
                else
                    if(isempty(s))
                        B.conlin(i) = 1;
                    else
                        B.conlin(i) = 3;
                    end
                end
            end
            % Find objective bias terms
            for i = 1:noeq
                % If linear, save bias term
                if(B.objlin(i) == 1 || B.conlin(i) == 1)
                    eq = B.sobj(i);
                    v = symvar(eq);
                    %Find bias term
                    B.objbias(i) = double(subs(eq,v,{zeros(size(v))}));
                end
            end
        end
    end

    methods(Static)
        %Parse Constraint String
        [str,l,u] = parseConstraint(str);
        %Extract RHS of expression string, remove from eq, and return LHS
        [str,exp] = parseExpression(str);
        %Extract Group and Name from Result Expression Name
        [group,name] = parseResExp(name);
        %Parse bound string
        [var,lb,ub] = parseBound(str);
        %Parse integer string
        [var,xtype] = parseInteger(str);
        %Determine Variable names
        varn = detVarNames(svar);
        %Build MATLAB function file
        cb = buildMFun(mode,sobj,svar,opts);
        %Build C Code function file
        cb = buildCFun(mode,sobj,svar,opts,nocon);
        %Convert symbolic expression into matlab function
        fun = sym2fun(sobj,svar,var,skipSubs);

        %Check we have a compiler suitable for use with Cppad
        function ok = CheckCppADCompile(doerr)
            ok = true;
            c = mex.getCompilerConfigurations('c++');
            if(isempty(c) || (isempty(strfind(c.Name,'Microsoft Visual C++')) && isempty(strfind(c.Name,'Intel C++'))))
                str = sprintf(['CppAD compilation is only available with Microsoft Visual Studio or Intel as the C++ compiler.\n\nPlease either select it'...
                           ' as the MEX compiler (via mex -setup), or download from Microsoft:\n\n %s (2012, recommended)\n\nor\n\n %s (2013)'],...
                           'http://www.microsoft.com/en-nz/download/details.aspx?id=34673','http://www.visualstudio.com/en-us/products/visual-studio-express-vs.aspx');
                if(doerr)
                    error(str) %#ok<SPERR>
                else %warning, auto has selected it
                    ok = false;
                    optiwarn('symb:cppad',sprintf('SymBuilder has chosen CppAD has the most effective callback strategy, but %s',str));
                end
            end
        end
    end

end


addpath(genpath('../mutils/My/'));
addpath(genpath('../ptv'));
%%
dat = load('data/molli.mat');
imgs = double(reshape(dat.imgs, [size(dat.imgs, 1), size(dat.imgs, 2), 1, 1, size(dat.imgs,3)]));
imgs = imgs(50:160, 50:160, :, :, :);

opts = [];
opts.check_gradients = 155*0;
opts.mean_penalty = 1e-3;
opts.pix_resolution = [1,1];
opts.metric = 'nuclear';

opts.grid_spacing = [10, 10];
opts.isoTV = 5e-3;

opts.spline_order = 1;
opts.max_iters = 100;

opts.display = 'off';
opts.opt_method = 'lbfsg';

opts.border_mask = 6;
opts.k_down = 0.7;

tic
[voldef_pl, Tmin_pl,  Kmin_pl] = ptv_register(imgs, [], opts);
toc

%%
imgs_exp = [];
for i = 1 : size(imgs, 5)
    hold off;
    imagesc(squeeze(imgs(:,:, 1, :, i)));
    colormap gray;
    hold on;
    plot_wiremesh(squeeze(Tmin_pl(:,:, 1, :, i)), 10, 'r-');
    daspect([1,1,1]);
    F = getframe;
    imgs_exp = cat(4, imgs_exp, double(F.cdata));
%     pause(0.1);
end
%%
savegif('results/molli_register.gif', squeeze([imgs, voldef_pl]), 1/5);
savegif('results/molli_track.gif', squeeze([imgs_exp]/250), 1/5);


function [ know, x ] = p24_sol ( n )

%*****************************************************************************80
%
%% P24_SOL returns the solution for problem 24.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    31 December 2000
%
%  Author:
%
%    John Burkardt
%
%  Parameters:
%
%    Input, integer N, the order of the problem.  This value
%    is only needed for those problems with variable N.
%
%    Output, integer KNOW.
%    If KNOW is 0, then the solution is not known.
%    If KNOW is positive, then the solution is known, and is returned in X.
%
%    Output, real X(N), the solution, if known.
%
  know = 1;

  x(1:n) = -5.0;

  return
end


function plot_varN2(params,nMode,const)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Example: plot_parvar1(params, 2,200,[],100)
%
% This function plots z, beta, and the probability of them as a function of
% input parameter like sampling size, window length and bin size. For each
% plot the other two parameters are kept fixed.
% The plot shows the distribution of values over all the grid point, the
% mean and the error as a standard deviation.
%
% Input
% params        structural array from
% nMode         parameter to plot z, beta, prob's against. Choose
%                      1 : Sampling Volume, N
%                      2 : Window Length, Tw
%                      3 : Bin Size, Tbin
% vN            Vector with range of sample sizes
% vTw           Vector with range of window length
% vTbin         Vector with range of bin size
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Author:
% van Stiphout, Thomas, vanstiphout@sed.ethz.ch
%
% Created on 16.08.2007
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% prepare x-labels and ...
%         sXLabel='Sampling Volume, N';
switch nMode
    case 1
        %prepare calculation
        nPos1=1;
        vVariable2=params.vTw; nPos2=2;
        vVariable3=params.vTbin(const); nPos3=3;
        % perform calculation
        calc_plotval
        % prepare plotting
        sXLabel='Sampling Volume, N';
        sName=sprintf('z(N,Tw) - const. Tbin=%4.1f',vVariable3);
        sPrint=sprintf('RatesfN_Tw_const_Tbin-%03.0f.png',vVariable3);
        plot_values
    case 2
        %prepare calculation
        nPos1=1;
        vVariable2=params.vTbin;nPos2=3;
        vVariable3=params.vTw(const); nPos3=2;
        % perform calculation
        calc_plotval;
        % prepare plotting
        sXLabel='Sampling Volume, N';
        sName=sprintf('z(N,Tbin) - const. Tw=%4.1f',vVariable3);
        sPrint=sprintf('RatesfN_Tbin_const_Tw-%03.0f.png',vVariable3);
        plot_values;
    case 3
        %prepare calculation
        nPos1=2;
        vVariable2=params.vN;nPos2=1;
        vVariable3=params.vTbin(const); nPos3=3;
        % perform calculation
        calc_plotval;
        % prepare plotting
        sXLabel='Sampling Volume, Tw';
        sName=sprintf('z(Tw,N) - const. Tbin=%4.1f',vVariable3);
        sPrint=sprintf('RatesfTw_N_const_Tbin-%03.0f.png',vVariable3);
        plot_values;
    case 4
        %prepare calculation
        nPos1=2;
        vVariable2=params.vTbin;nPos2=3;
        vVariable3=params.vN(const); nPos3=1;
        % perform calculation
        calc_plotval;
        % prepare plotting
        sXLabel='Sampling Volume, Tw';
        sName=sprintf('z(Tw,Tbin) - const. N=%4.1f',vVariable3);
        sPrint=sprintf('RatesfTw_Tbin_const_N-%03.0f.png',vVariable3);
        plot_values;
    case 5
        %prepare calculation
        nPos1=3;
        vVariable2=params.vN; nPos2=1;
        vVariable3=params.vTw(const); nPos3=2;
        % perform calculation
        calc_plotval;
        % prepare plotting
        sXLabel='Sampling Volume, Tbin';
        sName=sprintf('z(Tbin,N) - const. Tw=%4.1f',vVariable3);
        sPrint=sprintf('RatesfTbin_N_const_Tw-%03.0f.png',vVariable3);
        plot_values;
    case 6
        %prepare calculation
        nPos1=3;
        vVariable2=params.vTw; nPos2=2;
        vVariable3=params.vN(const); nPos3=1;
        % perform calculation
        calc_plotval;
        % prepare plotting
        sXLabel='Sampling Volume, Tbin';
        sName=sprintf('z(Tbin,Tw) - const. N=%4.1f',vVariable3);
        sPrint=sprintf('RatesfTbin_Tw_const_N-%03.0f.png',vVariable3);
        plot_values;
end  % end switch

    function calc_plotval
        for ii=1:size(vVariable2,1)
            vSel=logical((params.mVar(:,nPos2) == vVariable2(ii)).*(params.mVar(:,nPos3)==vVariable3));
            params.mVar(vSel,:);
            mN.V1=params.mVar(vSel,nPos1);
            for i=1:size(params.mResult_,1)
                mN.V2.Z{ii}(:,i)=squeeze(params.mResult_(i,1,vSel));
                mN.V2.B{ii}(:,i)=squeeze(params.mResult_(i,2,vSel));
                mN.V2.pZ{ii}(:,i)=squeeze(params.mResult_(i,3,vSel));
                mN.V2.pB{ii}(:,i)=squeeze(params.mResult_(i,4,vSel));
            end  % end for i
            mN.V2.Z_mean(:,ii)=mean(mN.V2.Z{ii},2);
            mN.V2.B_mean(:,ii)=mean(mN.V2.B{ii},2);
            mN.V2.pZ_mean(:,ii)=mean(mN.V2.pZ{ii},2);
            mN.V2.pB_mean(:,ii)=mean(mN.V2.pB{ii},2);
            mN.V2.Z_std(:,ii)=std(mN.V2.Z{ii},0,2);
            mN.V2.B_std(:,ii)=std(mN.V2.B{ii},0,2);
            mN.V2.pZ_std(:,ii)=std(mN.V2.pZ{ii},0,2);
            mN.V2.pB_std(:,ii)=std(mN.V2.pB{ii},0,2);
        end % end for ii
    end  % end function calc_plotval

    function plot_values
        figure_w_normalized_uicontrolunits('Position',[100 25 400 600],'Name',sName);
        mPlot{1}.X1=mN.V1
        mPlot{1}.Y1=mN.V2.Z_mean;
        mPlot{1}.Y2=mN.V2.Z_mean-mN.V2.Z_std;
        mPlot{1}.Y3=mN.V2.Z_mean+mN.V2.Z_std;
        mPlot{2}.X1=mN.V1;
        mPlot{2}.Y1=mN.V2.B_mean;
        mPlot{2}.Y2=mN.V2.B_mean-mN.V2.B_std;
        mPlot{2}.Y3=mN.V2.B_mean+mN.V2.B_std;
        mPlot{3}.X1=mN.V1;
        mPlot{3}.Y1=mN.V2.pZ_mean;
        mPlot{3}.Y2=mN.V2.pZ_mean-mN.V2.pZ_std;
        mPlot{3}.Y3=mN.V2.pZ_mean+mN.V2.pZ_std;
        mPlot{4}.X1=mN.V1;
        mPlot{4}.Y1=mN.V2.pB_mean;
        mPlot{4}.Y2=mN.V2.pB_mean-mN.V2.pB_std;
        mPlot{4}.Y3=mN.V2.pB_mean+mN.V2.pB_std;

        sTitle=[cellstr(char('z(lta)-variation')), cellstr(char('p(Z)-variation')),...
            cellstr(char('\beta-variation')),  cellstr(char('p(\beta)-variation'))];
        sYLabel=[cellstr(char('z(lta)')),cellstr(char('p(Z)')),cellstr(char('\beta')), cellstr(char('p(\beta)'))];

        for pp=1:4
            subplot(2,2,pp);
            hold on;plot(mPlot{pp}.X1,mPlot{pp}.Y1,'x--','LineWidth',2,'MarkerSize',12)
            if pp==1  legend(num2str(vVariable2)); end
            hold on;plot(mPlot{pp}.X1,mPlot{pp}.Y2  ,'+:','LineWidth',1)
%             hold on;plot(mPlot{pp}.X1,mPlot{pp}.Y2,'+')
            hold on;plot(mPlot{pp}.X1,mPlot{pp}.Y3,':+','LineWidth',1)
%             hold on;plot(mPlot{pp}.X1,mPlot{pp}.Y3,'+')
            title(sTitle(pp));
            ylabel(sYLabel(pp));
            xlabel(sXLabel);
        end % end for pp
    end % end plot_values

    mN;
    sPrint=sprintf('print -dpng %s',sPrint);
    eval(sPrint)
end % end function

%
%     xlabel(sXLabel);
%     switch nSubplot
%         case 1
%             title('z(lta)-variation');
%             ylabel('z(lta)');
%         case 2
%             title('p(z)-variation');
%             ylabel('p(z)');
%         case 3
%             title('\beta-variation');
%             ylabel('\beta');
%         case 4
%             title('p(\beta)-variation');
%             ylabel('p(\beta)');
%     end
%     subplot(2,2,nSubplot);
%     Y=mean(squeeze(params.mResult_(:,nSubplot,vSel)));
%     E=std(squeeze(params.mResult_(:,nSubplot,vSel)));
%     errorbar(params.mVar(vSel,nMode),Y,E,'xr','MarkerSize',10,'LineWidth',1);
% end


classdef ORBoost < Algorithm
    %ORBoost ORBoost Boosting ensemble for Ordinal Regression [1]. This class
    %uses orensemble implementation at http://www.work.caltech.edu/~htlin/program/orensemble/
    %
    %   ORBoost methods:
    %      fitpredict               - runs the corresponding algorithm,
    %                                   fitting the model and testing it in a dataset.
    %      fit                        - Fits a model from training data
    %      predict                    - Performs label prediction
    %
    %   References:
    %
    %     [1] H.-T. Lin and L. Li, Large-margin thresholded ensembles for
    %         ordinal regression: Theory and practice, in Proc. of the 17th
    %         Algorithmic Learning Theory International Conference, ser.
    %         Lecture Notes in Artificial Intelligence (LNAI), J. L. Balcazar,
    %         P. M. Long, and F. Stephan, Eds., vol. 4264. Springer-Verlag,
    %         October 2006, pp. 319-333.
    %     [1] P.A. Gutiérrez, M. Pérez-Ortiz, J. Sánchez-Monedero,
    %         F. Fernández-Navarro and C. Hervás-Martínez
    %         Ordinal regression methods: survey and experimental study
    %         IEEE Transactions on Knowledge and Data Engineering, Vol. 28. Issue 1
    %         2016
    %         http://dx.doi.org/10.1109/TKDE.2015.2457911
    %
    %   This file is part of ORCA: https://github.com/ayrna/orca
    %   Original authors: Pedro Antonio Gutiérrez, María Pérez Ortiz, Javier Sánchez Monedero
    %   Citation: If you use this code, please cite the associated paper http://www.uco.es/grupos/ayrna/orreview
    %   Copyright:
    %       This software is released under the The GNU General Public License v3.0 licence
    %       available at http://www.gnu.org/licenses/gpl-3.0.html
    properties
        description = 'OR Ensemble with perceptrons';
        parameters = [];
        weights = true;
    end

    methods

        function obj = ORBoost(varargin)
            %ORBoost constructs an object of the class ORBoost and sets its default
            %   characteristics
            %   OBJ = ORBoost() builds ORBoost object
            obj.parseArgs(varargin);
        end

        function [projectedTrain, predictedTrain] = privfit(obj,train,parameters)
            %PRIVFIT trains the model for the ORBoost method with TRAIN data and
            %vector of parameters PARAMETERS.

            % Output model file
            modelFile = tempname();
            % Write train file
            trainFile = tempname();
            dlmwrite(trainFile,[train.patterns train.targets],'delimiter',' ','precision',10);

            % Prepare command line
            if ispc
                bin_train = fullfile('Algorithms','orensemble', 'boostrank-train.exe');
                execute_train = sprintf('%s %s %d %d %d1 204 %d 2000 %s',...
                    bin_train, trainFile,size(train.patterns,1),size(train.patterns,2),(3+obj.weights),max(unique(train.targets)),modelFile);
            else
                execute_train = sprintf('%s/orensemble/hack.sh %s/orensemble/boostrank-train %s %d %d %d1 204 %d 2000 %s',...
                    fileparts(which('Algorithm.m')), fileparts(which('Algorithm.m')),...
                    trainFile,size(train.patterns,1),size(train.patterns,2),(3+obj.weights),max(unique(train.targets)),modelFile);
            end

            % Execute train
            system(execute_train);

            % Extract contents of model file
            fid = fopen(modelFile);
            if ~(exist ('OCTAVE_VERSION', 'builtin') > 0) && verLessThan('matlab','8.4')
                s = textscan(fid,'%s','Delimiter','\n','bufsize', 2^18-1);
            else
                s = textscan(fid,'%s','Delimiter','\n');
            end
            s = s{1};
            fclose(fid);

            model.textInformation = s;
            model.weights = obj.weights;
            obj.model = model;
            [projectedTrain,predictedTrain] = obj.predict(train.patterns);
            % Delete temp files
            delete(trainFile);
            delete(modelFile);
        end

        function [projected, predicted]= privpredict( obj,test)
            %PREDICT predicts labels of TEST patterns labels. The object needs to be fitted to the data first.

            % Write test file
            testFile = tempname();
            dlmwrite(testFile,[test ones(size(test,1),1)],'delimiter',' ','precision',10);
            % Write model file
            modelFile = tempname();
            fid = fopen(modelFile,'w');
            nLines = size(obj.model.textInformation,1);
            for iLine = 1:nLines
                fprintf(fid,'%s\n',obj.model.textInformation{iLine});
            end
            fclose(fid);
            % Name of prediction file
            predictFile = tempname();

            % Prepare command line
            if ispc
                bin_predict = fullfile(fileparts(which('Algorithm.m')),'orensemble', 'boostrank-predict.exe');
                execute_test = sprintf('%s %s %d %d %s 2000 %s',...
                    bin_predict,testFile,size(test,1),...
                    size(test,2),modelFile,predictFile);
            else
                execute_test = ...
                    sprintf('%s/orensemble/hack.sh %s/orensemble/boostrank-predict %s %d %d %s 2000 %s',...
                    fileparts(which('Algorithm.m')),fileparts(which('Algorithm.m')),testFile,size(test,1),size(test,2),modelFile,predictFile);
            end

            % Execute test
            system(execute_test);
            % Extract predictions (targets and projections)
            all = load(predictFile);
            predicted = all(:,1);
            projected = all(:,2);
            % Delete temp files
            delete(predictFile);
            delete(testFile);
            delete(modelFile);
        end

    end
end


function test_ft_sourceparcellate

% WALLTIME 00:10:00
% MEM 2gb
% DEPENDENCY ft_sourceparcellate ft_read_atlas ft_sourceinterpolate

% see also https://github.com/fieldtrip/fieldtrip/issues/1753

%%

atlasfilename   = dccnpath('/home/common/matlab/fieldtrip/template/atlas/aal/ROI_MNI_V4.nii');

npos = 38*48*41;
ntime = 20;

source = [];
source.pos = 200*rand(npos,3) - 100;
source.unit = 'mm';
source.time = 1:ntime;
source.pow = randn(npos,ntime);
source.inside = 1:npos;

atlas = ft_read_atlas(atlasfilename);

cfg = [];
cfg.interpmethod = 'nearest';
cfg.parameter = 'tissue';
parcellation = ft_sourceinterpolate(cfg, atlas, source);

cfg = [];
cfg.parcellation = 'tissue';
result = ft_sourceparcellate(cfg, source, parcellation);

%%

x = -5:5;
y = -5:5;
z = -5:5;

[X, Y, Z] = ndgrid(x, y, z);
dim = [length(x) length(y) length(z)];

source = [];
source.dim = dim;
source.pos = [X(:) Y(:) Z(:)];
source.time = linspace(-0.1, 0.5, 15);
source.pow   = randn(prod(dim), 1);
for i=1:prod(dim)
  source.eta{i} = source.pow(i);
end
source.timecourse = randn(prod(dim), 15);
source.moment     = cell(prod(dim), 1);
for i=1:prod(dim)
  source.moment{i} = source.timecourse(i,:);
end
source.powdimord = 'pos';
source.etadimord = '{pos}';
source.timecoursedimord = 'pos_time';
source.momentdimord = '{pos}_ori_time';

atlas = [];
atlas.dim = dim;
atlas.pos = [X(:) Y(:) Z(:)];
atlas.tissue = zeros(prod(dim),1);
roi1 = atlas.pos(:,1)<0;
roi2 = atlas.pos(:,1)>0;
atlas.tissue(roi1) = 1;
atlas.tissue(roi2) = 2;
atlas.tissuelabel{1} = 'left';
atlas.tissuelabel{2} = 'right';

%%

cfg = [];
cfg.method = 'mean';

cfg.parameter = 'pow';
parcel1 = ft_sourceparcellate(cfg, source, atlas);
manual = mean(source.(cfg.parameter)(roi1, :), 1);
assert(isequal(parcel1.pow(1,:), manual));

cfg.parameter = 'eta';
parcel2 = ft_sourceparcellate(cfg, source, atlas);
assert(isalmostequal(parcel1.pow(:), parcel2.eta(:), 'abstol', 100*eps));

cfg.parameter = 'timecourse';
parcel3 = ft_sourceparcellate(cfg, source, atlas);
manual = mean(source.(cfg.parameter)(roi1, :), 1);
assert(isequal(parcel3.timecourse(1,:), manual));

cfg.parameter = 'moment';
parcel4 = ft_sourceparcellate(cfg, source, atlas);
assert(isalmostequal(parcel3.timecourse(:), parcel4.moment(:), 'abstol', 100*eps));

%%

cfg = [];
cfg.method = 'median';

cfg.parameter = 'pow';
parcel1 = ft_sourceparcellate(cfg, source, atlas);
manual = median(source.(cfg.parameter)(roi1, :), 1);
assert(isequal(parcel1.pow(1,:), manual));

cfg.parameter = 'eta';
parcel2 = ft_sourceparcellate(cfg, source, atlas);
assert(isalmostequal(parcel1.pow(:), parcel2.eta(:), 'abstol', 100*eps));

cfg.parameter = 'timecourse';
parcel3 = ft_sourceparcellate(cfg, source, atlas);
manual = median(source.(cfg.parameter)(roi1, :), 1);
assert(isequal(parcel3.timecourse(1,:), manual));

cfg.parameter = 'moment';
parcel4 = ft_sourceparcellate(cfg, source, atlas);
assert(isalmostequal(parcel3.timecourse(:), parcel4.moment(:), 'abstol', 100*eps));

%%

cfg = [];
cfg.method = 'min';

cfg.parameter = 'pow';
parcel1 = ft_sourceparcellate(cfg, source, atlas);
manual = min(source.(cfg.parameter)(roi1, :), [], 1);
assert(isequal(parcel1.pow(1,:), manual));

cfg.parameter = 'eta';
parcel2 = ft_sourceparcellate(cfg, source, atlas);
assert(isalmostequal(parcel1.pow(:), parcel2.eta(:), 'abstol', 100*eps));

cfg.parameter = 'timecourse';
parcel3 = ft_sourceparcellate(cfg, source, atlas);
manual = min(source.(cfg.parameter)(roi1, :), [], 1);
assert(isequal(parcel3.timecourse(1,:), manual));

cfg.parameter = 'moment';
parcel4 = ft_sourceparcellate(cfg, source, atlas);
assert(isalmostequal(parcel3.timecourse(:), parcel4.moment(:), 'abstol', 100*eps));

%%

cfg = [];
cfg.method = 'max';

cfg.parameter = 'pow';
parcel1 = ft_sourceparcellate(cfg, source, atlas);
manual = max(source.(cfg.parameter)(roi1, :), [], 1);
assert(isequal(parcel1.pow(1,:), manual));

cfg.parameter = 'eta';
parcel2 = ft_sourceparcellate(cfg, source, atlas);
assert(isalmostequal(parcel1.pow(:), parcel2.eta(:), 'abstol', 100*eps));

cfg.parameter = 'timecourse';
parcel3 = ft_sourceparcellate(cfg, source, atlas);
manual = max(source.(cfg.parameter)(roi1, :), [], 1);
assert(isequal(parcel3.timecourse(1,:), manual));

cfg.parameter = 'moment';
parcel4 = ft_sourceparcellate(cfg, source, atlas);
assert(isalmostequal(parcel3.timecourse(:), parcel4.moment(:), 'abstol', 100*eps));

%%

cfg = [];
cfg.method = 'std';

cfg.parameter = 'pow';
parcel1 = ft_sourceparcellate(cfg, source, atlas);
manual = std(source.(cfg.parameter)(roi1, :), 0, 1);
assert(isequal(parcel1.pow(1,:), manual));

cfg.parameter = 'eta';
parcel2 = ft_sourceparcellate(cfg, source, atlas);
assert(isalmostequal(parcel1.pow(:), parcel2.eta(:), 'abstol', 100*eps));

cfg.parameter = 'timecourse';
parcel3 = ft_sourceparcellate(cfg, source, atlas);
manual = std(source.(cfg.parameter)(roi1, :), 0, 1);
assert(isequal(parcel3.timecourse(1,:), manual));

cfg.parameter = 'moment';
parcel4 = ft_sourceparcellate(cfg, source, atlas);
assert(isalmostequal(parcel3.timecourse(:), parcel4.moment(:), 'abstol', 100*eps));


function CMap = cmap_jetinv(nbVals)
% CMAP_JETINV: Inversed JET colormap

% @=============================================================================
% This function is part of the Brainstorm software:
% https://neuroimage.usc.edu/brainstorm
%
% Copyright (c) University of Southern California & McGill University
% This software is distributed under the terms of the GNU General Public License
% as published by the Free Software Foundation. Further details on the GPLv3
% license can be found at http://www.gnu.org/copyleft/gpl.html.
%
% FOR RESEARCH PURPOSES ONLY. THE SOFTWARE IS PROVIDED "AS IS," AND THE
% UNIVERSITY OF SOUTHERN CALIFORNIA AND ITS COLLABORATORS DO NOT MAKE ANY
% WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF
% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, NOR DO THEY ASSUME ANY
% LIABILITY OR RESPONSIBILITY FOR THE USE OF THIS SOFTWARE.
%
% For more information type "brainstorm license" at command prompt.
% =============================================================================@
%
% Authors: Francois Tadel, 2009

CMap = bst_flip(jet(nbVals), 1);


function pass = test_iszero( pref )

% Grab some preferences
if ( nargin == 0 )
    pref = chebfunpref();
end

% Test with vector 1-1
f = ballfun(ones(19,20,22));
F = ballfunv(f,f,f);
G = F-F;
pass(1) = iszero(G);
end


% CLASSIFY
% See also
%
% Clustering:
%   demoCluster        - Clustering demo.
%   demoGenData        - Generate data drawn form a mixture of Gaussians.
%   kmeans2            - Fast version of kmeans clustering.
%   meanShift          - meanShift clustering algorithm.
%   meanShiftIm        - Applies the meanShift algorithm to a joint spatial/range image.
%   meanShiftImExplore - Visualization to help choose sigmas for meanShiftIm.
%
% Calculating distances efficiently:
%   distMatrixShow     - Useful visualization of a distance matrix of clustered points.
%   pdist2             - Calculates the distance between sets of vectors.
%   softMin            - Calculates the softMin of a vector.
%
% Principal components analysis:
%   pca                - Principal components analysis (alternative to princomp).
%   pcaApply           - Companion function to pca.
%   pcaRandVec         - Generate random vectors in PCA subspace.
%   pcaVisualize       - Visualization of quality of approximation of X given principal comp.
%   visualizeData      - Project high dim. data unto principal components (PCA) for visualization.
%
% Confusion matrix display:
%   confMatrix         - Generates a confusion matrix according to true and predicted data labels.
%   confMatrixShow     - Used to display a confusion matrix.
%
% Radial Basis Functions (RBFs):
%   rbfComputeBasis    - Get locations and sizes of radial basis functions for use in rbf network.
%   rbfComputeFtrs     - Evaluate features of X given a set of radial basis functions.
%   rbfDemo            - Demonstration of rbf networks for regression.
%
% Fast random fern/forest classification/regression code:
%   fernsClfApply      - Apply learned fern classifier.
%   fernsClfTrain      - Train random fern classifier.
%   fernsInds          - Compute indices for each input by each fern.
%   fernsRegApply      - Apply learned fern regressor.
%   fernsRegTrain      - Train boosted fern regressor.
%   forestApply        - Apply learned forest classifier.
%   forestTrain        - Train random forest classifier.
%
% Fast boosted decision tree code:
%   adaBoostTrain      - Train boosted decision tree classifier.
%   adaBoostApply      - Apply learned boosted decision tree classifier.
%   binaryTreeTrain    - Train binary decision tree classifier.
%   binaryTreeApply    - Apply learned binary decision tree classifier.


function [F10, F01] = retrieveQ1001(level, o, H, L)
%------------------------------------------------------------------------------
%
% This function extracts gridfunction F10 and F01 from H.
% F10 is of colour '10' and F01 is of colour '01' such that together they
% constitute a quincunx gridfunction.
%
%                H   H   H   H
%              V   V   V   V   V       V ~ F10
%                H   H   H   H         H ~ F01
%              V   V   V   V   V
%                H   H   H   H
%              V   V   V   V   V
%                H   H   H   H
%              V   V   V   V   V
%                H   H   H   H
%       (domain of quincunx gridfunction)
%
% F10 & F01 are supposed to be uniquely determined by the integer L (level)
% and character o describing its type.
% Function retrieveQ1001 is the counterpart of storeQ1001.
% This function is a two-dimensional lifting scheme utility.
%
% F10 = 2D gridfunction of coefficients of colour '10' extracted from H.
%
% F01 = 2D gridfunction of coefficients of colour '01' extracted from H.
%
% level = integer designated as the level of both F10 and F01.
%
% o = character, should be either 'a' or 'd',
%     describing the type of both F10 and F01:
%     'a' relates to approximation (coefficients) and
%     'd' relates to detail (coefficients)
%
% L = 2D integer array of bookkeeping, see function storeR.
%
% H = 1D array that functions as storage (heap). The coefficients of both F10
%     and F01 are extracted from H as a result of calling retrieveQ1001.
%
% See also: retrieveQ1001, retrieveQ, retrieveQ0110.
%
% Design and implementation by:
% Dr. Paul M. de Zeeuw <Paul.de.Zeeuw@cwi.nl>  http://homepages.cwi.nl/~pauldz/
% Last Revision: October 17, 2002.
% (c) 1999-2002 Stichting CWI, Amsterdam.
%------------------------------------------------------------------------------
F10 = retrieveQ(level, '10', o, H, L);
F01 = retrieveQ(level, '01', o, H, L);
if isempty(F10) || isempty(F01)
  disp([' retrieveQ1001 - ERROR at type ' o ' with level ' num2str(level)]);
  error(' retrieveQ1001 - empty result ')
else
  [n10, m10]=size(F10);
  [n01, m01]=size(F01);
  if m01 > m10
    disp([' retrieveQ1001 - ERROR at type ' o ' with level ' num2str(level)]);
    error(' retrieveQ1001 - dimensions do not match for m01 > m10 ')
  end
  if n10 > n01
    disp([' retrieveQ1001 - ERROR at type ' o ' with level ' num2str(level)]);
    error(' retrieveQ1001 - dimensions do not match for n10 > n01 ')
  end
  if m10 > m01+1
    disp([' retrieveQ1001 - ERROR at type ' o ' with level ' num2str(level)]);
    error(' retrieveQ1001 - dimensions do not match for m10 > m01+1 ')
  end
  if n01 > n10+1
    disp([' retrieveQ1001 - ERROR at type ' o ' with level ' num2str(level)]);
    error(' retrieveQ1001 - dimensions do not match for n01 > n10+1 ')
  end
%
% m01 <= m10 <= m01+1 is satisfied
% n10 <= n01 <= n10+1 is satisfied
%
end
%------------------------------------------------------------------------------