GatherTensorRowsString does an MPI AllGather on given String src tensor data, gathering into dest, using a row-based tensor organization (as in an table.Table). dest will have np * src.Rows Rows, filled with each processor's data, in order. dest must have same overall shape as src at start, but rows
(dest, src *tensor.String, comm *mpi.Comm)
| 62 | // dest will have np * src.Rows Rows, filled with each processor's data, in order. |
| 63 | // dest must have same overall shape as src at start, but rows will be enforced. |
| 64 | func GatherTensorRowsString(dest, src *tensor.String, comm *mpi.Comm) error { |
| 65 | sr, _ := src.RowCellSize() |
| 66 | dr, _ := dest.RowCellSize() |
| 67 | np := mpi.WorldSize() |
| 68 | dl := np * sr |
| 69 | if dr != dl { |
| 70 | dest.SetNumRows(dl) |
| 71 | dr = dl |
| 72 | } |
| 73 | ssz := len(src.Values) |
| 74 | dsz := len(dest.Values) |
| 75 | sln := make([]int, ssz) |
| 76 | dln := make([]int, dsz) |
| 77 | for i, s := range src.Values { |
| 78 | sln[i] = len(s) |
| 79 | } |
| 80 | err := comm.AllGatherInt(dln, sln) |
| 81 | if err != nil { |
| 82 | return err |
| 83 | } |
| 84 | mxlen := 0 |
| 85 | for _, l := range dln { |
| 86 | mxlen = max(mxlen, l) |
| 87 | } |
| 88 | if mxlen == 0 { |
| 89 | return nil // nothing to transfer |
| 90 | } |
| 91 | sdt := make([]byte, ssz*mxlen) |
| 92 | ddt := make([]byte, dsz*mxlen) |
| 93 | idx := 0 |
| 94 | for _, s := range src.Values { |
| 95 | l := len(s) |
| 96 | copy(sdt[idx:idx+l], []byte(s)) |
| 97 | idx += mxlen |
| 98 | } |
| 99 | err = comm.AllGatherU8(ddt, sdt) |
| 100 | idx = 0 |
| 101 | for i := range dest.Values { |
| 102 | l := dln[i] |
| 103 | s := string(ddt[idx : idx+l]) |
| 104 | dest.Values[i] = s |
| 105 | idx += mxlen |
| 106 | } |
| 107 | return err |
| 108 | } |
| 109 | |
| 110 | // ReduceTensor does an MPI AllReduce on given src tensor data, using given operation, |
| 111 | // gathering into dest. dest must have same overall shape as src -- will be enforced. |
no test coverage detected