use super::*;
pub struct PSDDomain<const N : usize> {
shape : [usize; N],
conedims : (usize,usize)
}
pub struct ScalablePSDDomain {
cone_dims : Option<(usize,usize)>
}
impl ScalablePSDDomain {
pub fn with_conedims(self,conedim0 : usize, conedim1 : usize) -> Self { ScalablePSDDomain{ cone_dims : Some((conedim0,conedim1)) }}
pub fn with_dim(self,dim : usize) -> PSDProtoDomain<2> {
PSDProtoDomain{
shape : [dim,dim],
cone_dims : self.cone_dims,
}
}
pub fn with_shape<const N : usize>(self, shape : &[usize;N]) -> PSDProtoDomain<N> {
let cone_dims = if let Some(cd) = self.cone_dims { cd } else { (N.max(2)-2,N.max(2)-1) };
PSDProtoDomain{shape:*shape, cone_dims : Some(cone_dims) }
}
}
impl IntoDomain for ScalablePSDDomain {
type Result = PSDDomain<0>;
fn try_into_domain(self) -> Result<Self::Result,String> {
Err("PSD Domain has no shape".to_string())
}
}
impl<const N : usize> IntoShapedDomain<N> for ScalablePSDDomain {
type Result = PSDDomain<N>;
fn try_into_domain(self,shape : [usize;N]) -> Result<Self::Result,String> {
if N < 2 {
return Err("PSD Domains by be at least two-dimensional".to_string());
}
let conedims =
if let Some((d0,d1)) = self.cone_dims {
if d0 == d1 {
return Err("PSD domains cone dimensions must be different".to_string());
}
else if d0.max(d1) >= N {
return Err("Invalid cone dimensions for PSD domain".to_string());
}
(d0,d1)
}
else {
(N-2,N-1)
};
Ok(PSDDomain{ shape, conedims })
}
}
pub struct PSDProtoDomain<const N : usize> {
shape : [usize;N],
cone_dims : Option<(usize,usize)>
}
impl<const N : usize> PSDProtoDomain<N> {
pub fn dissolve(self) -> ([usize;N],Option<(usize,usize)>) { (self.shape,self.cone_dims) }
pub fn with_conedims(self,conedim0 : usize, conedim1 : usize) -> Self { PSDProtoDomain{ cone_dims : Some((conedim0,conedim1)), ..self }}
pub fn with_shape<const M : usize>(self, shape : [usize;M]) -> PSDProtoDomain<M> {
PSDProtoDomain{
shape,
cone_dims : self.cone_dims
}
}
}
impl<const N : usize> IntoDomain for PSDProtoDomain<N> {
type Result = PSDDomain<N>;
fn try_into_domain(self) -> Result<Self::Result,String> {
if N < 2 {
return Err(format!("PSD Domains by be at least two-dimensional"));
}
let conedims =
if let Some((d0,d1)) = self.cone_dims {
if d0 == d1 {
return Err(format!("PSD domains cone dimensions must be different"));
}
else if d0.max(d1) >= N {
return Err(format!("Invalid cone dimensions for PSD domain"));
}
else if self.shape[d0] != self.shape[d1] {
return Err(format!("Cone dimensions for PSD domain must have same size"));
}
(d0,d1)
}
else {
(N-2,N-1)
};
Ok(PSDDomain{ shape : self.shape, conedims })
}
}
impl<const N : usize> IntoShapedDomain<N> for PSDProtoDomain<N> {
type Result = PSDDomain<N>;
fn try_into_domain(self,shape : [usize;N]) -> Result<Self::Result,String> {
let res = IntoDomain::try_into_domain(self)?;
if res.shape == shape {
Ok(res)
}
else {
Err(format!("Domain shape did not match the expected shape: {:?} vs {:?}",res.shape,shape))
}
}
}
impl<const N :usize> PSDDomain<N> {
pub fn dissolve(self) -> ([usize;N],(usize,usize)) { (self.shape,self.conedims) }
}
pub fn in_psd_cone() -> ScalablePSDDomain {
ScalablePSDDomain{
cone_dims : None
}
}
pub fn in_psd_cones<const N : usize>(shape : &[usize; N]) -> PSDProtoDomain<N> {
PSDProtoDomain{
shape : *shape,
cone_dims : None
}
}