| 56 | | // ------------------------------------------------ |
|---|
| 57 | | // Dealing with linear algebra types |
|---|
| 58 | | // ------------------------------------------------ |
|---|
| 59 | | |
|---|
| 60 | | /// Determine the (tensor) rank of type T; ie 0 if T is a scalar, 1 for vector, |
|---|
| 61 | | /// 2 for matrix, 3 for rank-3 tensor, etc |
|---|
| 62 | | template Rank(T) { |
|---|
| 63 | | // If it can be indexed, it's a vector |
|---|
| 64 | | static if (is(typeof(T[0]))) const int Rank = 1 + Rank!(typeof(T[0])); |
|---|
| 65 | | else const int Rank = 0; |
|---|
| 66 | | } |
|---|
| 67 | | |
|---|
| 68 | | /// Return the type of element stored in T. Eg, ElementType!(double[][35][]) is double. |
|---|
| 69 | | template ElementType(T) { |
|---|
| 70 | | static if (is(typeof(T[0]))) alias ElementType!(typeof(T[0])) ElementType; |
|---|
| 71 | | else alias T ElementType; |
|---|
| 72 | | } |
|---|
| 73 | | |
|---|
| 74 | | /// Convert tuple to string. |
|---|
| 75 | | /// |
|---|
| 76 | | /// This is only necessary because CTFE functions cannot iterate over the elements |
|---|
| 77 | | /// of a tuple. The solution is to use templates to create a string representation |
|---|
| 78 | | /// of the types in the tuple. |
|---|
| 79 | | template elementTupleToString(X...) |
|---|
| 80 | | { |
|---|
| 81 | | static if (X.length==0) const char [][] elementTupleToString = []; |
|---|
| 82 | | else const char [][] elementTupleToString = elementTupleToString!(X[0..$-1]) ~ [ElementType!(X[$-1]).stringof]; |
|---|
| 83 | | } |
|---|
| 84 | | |
|---|
| 85 | | unittest { |
|---|
| 86 | | static assert( elementTupleToString!(real [], double) == ["real", "double"]); |
|---|
| 87 | | static assert( elementTupleToString!() == cast(char[][])([])); |
|---|
| 88 | | } |
|---|
| 89 | | |
|---|
| 90 | | |
|---|
| 91 | | /// Determine the rank of every item of the tuple T. |
|---|
| 92 | | template TupleRank(T...) { |
|---|
| 93 | | static if (T.length==1) const int[] TupleRank = [ Rank!(T[0])]; |
|---|
| 94 | | else const int[] TupleRank = Rank!(T[0]) ~ TupleRank!(T[1..$]); |
|---|
| 95 | | } |
|---|
| 96 | | |
|---|
| 97 | | debug(UnitTest) { |
|---|
| 98 | | private: |
|---|
| 99 | | class TestTensor(int rank) { |
|---|
| 100 | | static if (rank>1) { |
|---|
| 101 | | TestTensor!(rank-1) opIndex(int k) { return null; } |
|---|
| 102 | | } else { |
|---|
| 103 | | cfloat opIndex(int k) { return 0 + 0i; } |
|---|
| 104 | | } |
|---|
| 105 | | } |
|---|
| 106 | | |
|---|
| 107 | | unittest { |
|---|
| 108 | | class Test { ulong opIndex(int k){ return 0; } } |
|---|
| 109 | | double padding_for_test; |
|---|
| 110 | | |
|---|
| 111 | | assert(TupleRank!(int[][], float, double[], double[45])==[2,0,1,1]); |
|---|
| 112 | | static assert(is(ElementType!(Test[35])==ulong)); |
|---|
| 113 | | static assert(is(ElementType!(double[][35][])==double)); |
|---|
| 114 | | static assert(is(ElementType!(TestTensor!(5))==cfloat)); |
|---|
| 115 | | static assert(Rank!(TestTensor!(5))==5); |
|---|
| 116 | | } |
|---|
| 117 | | |
|---|
| 118 | | } |
|---|
| 119 | | |
|---|
| 402 | | int vectorNum(int [] ranklist, char var) |
|---|
| 403 | | { |
|---|
| 404 | | int numVecs=0; |
|---|
| 405 | | for (int i=0; i<var-'A'; ++i) { |
|---|
| 406 | | if (ranklist[i]==1) ++numVecs; |
|---|
| 407 | | } |
|---|
| 408 | | return numVecs; |
|---|
| 409 | | } |
|---|
| 410 | | |
|---|
| 411 | | int realScalarNum(char [][] typelist, int [] ranklist, char var) |
|---|
| 412 | | { |
|---|
| 413 | | int k=0; |
|---|
| 414 | | for (int i=0; i<var-'A'; ++i) { |
|---|
| 415 | | if (ranklist[i]==0 && typelist[i]=="real") ++k; |
|---|
| 416 | | } |
|---|
| 417 | | return k; |
|---|
| 418 | | } |
|---|
| 419 | | |
|---|
| 420 | | int scalarNum(int [] ranklist, char var) |
|---|
| 421 | | { |
|---|
| 422 | | int k=0; |
|---|
| 423 | | for (int i=0; i<var-'A'; ++i) { |
|---|
| 424 | | if (ranklist[i]==0) ++k; |
|---|
| 425 | | } |
|---|
| 426 | | return k; |
|---|
| 427 | | } |
|---|
| 428 | | |
|---|
| 429 | | |
|---|