[IFRT] Add `DeserializeProgramOptions`
[IFRT] Add `DeserializeProgramOptions`

`DeserializeProgramOptions` is used when deserializing `Program`. It now takes
`lookup_device` that allows `Program` deserialization to reconstruct any
`Device`-related objects (e.g., `DeviceList`, `Sharding`).

Traditionally, a program encoded device ids without IFRT serialization support
-- e.g., `device_assignment` in `xla::ExecutableBuildOptions` included in
`xla::CompileOptions` or `devices` in IFRT IR. Similar for sharding
representations. They do not need to look up devices when deserializing
`Program`, but some stack needs to check the device ids and shardings
eventually. Having `lookup_device` in `DeserializeProgramOptions` would make
this validation done at the deserialization time and applied to `Program`
subclasses automaticallly as long as they use IFRT `Sharding` objects in the
subclasses.

Also move `Program` out of `ifrt/compiler.h` as a program stands by itself, and
is not dependent on `Compiler`.
