[IFRT] Implement RemapArrays API
[IFRT] Implement RemapArrays API

We introduce `ifrt::Client::RemapArrays()`

* It takes `N` input arrays, returns `M` output arrays, performing is a
shard-level scatter-gather. It is a generalization of existing shard-level
APIs: `Client::AssembleArrayFromSingleDeviceArrays()`,
`Array::DisassembleIntoSingleDeviceArrays()`, and
`Array::FullyReplicatedShard()`.
* It is metadata-only operation.
No shard from the input can be used twice (no replication). No shard will have
its location changed (no transfer). However, some shards from the input may be
not used in any of the output arrays and be discarded.
