Mentions légales du service

Skip to content
Snippets Groups Projects
Commit ab78d4db authored by hhakim's avatar hhakim
Browse files

Bind into pyfaust the prox operators from cpp core.

See previous commit 79e43459 for equivalent matlab bindings (the two wrapper APIs are kept consistent).
parent a74ae436
No related branches found
No related tags found
No related merge requests found
......@@ -1339,7 +1339,7 @@ class FaustFactory:
- The pseudo-random generation of a Faust with FaustFactory.rand(),
- the discrete Fourier transform with FaustFactory.dft(),
- the Hadamard transform with FaustFactory.wht(),
- and the identity Faust with FaustFactory.eye().
- and the identity Faust with FaustFactory.eye().
"""
......@@ -1379,7 +1379,7 @@ class FaustFactory:
"the last residuum constraint defined in p. "
"Likewise its number of rows must be consistent "
"with the first factor constraint defined in p.")
return Faust(core_obj=FaustCorePy.FaustFact.fact_palm4MSA(M, p))
return Faust(core_obj=FaustCorePy.FaustFact.fact_palm4msa(M, p))
@staticmethod
def fact_hierarchical(M, p, ret_lambda=False):
......
# -*- coding: utf-8 -*-
from pyfaust import *
import FaustCorePy
"""
This module provides all the classes that represent the input parameters needed
......@@ -67,6 +68,10 @@ class ConstraintGeneric(object):
"""
return self._name.is_mat_constraint()
def project(self, M):
if(M.shape[0] != self._num_rows or M.shape[1] != self._num_cols):
raise ValueError("The dimensions must agree.")
class ConstraintInt(ConstraintGeneric):
"""
This class represents an integer constraint on a matrix-factor.
......@@ -85,6 +90,12 @@ class ConstraintInt(ConstraintGeneric):
'ConstraintName with a int type name '
'(name.is_int_constraint() must return True).')
def project(self, M):
# TODO: call parent project()
return FaustCorePy.ConstraintIntCore.project(M, self._name.name, self._num_rows,
self._num_cols, self._cons_value)
class ConstraintMat(ConstraintGeneric):
def __init__(self, name, num_rows, num_cols, cons_value):
......@@ -93,12 +104,18 @@ class ConstraintMat(ConstraintGeneric):
np.ndarray)):
raise TypeError('ConstraintMat must receive a numpy matrix as cons_value '
'argument.')
self.cons_value = float(self.cons_value)
self.cons_value = self._cons_value
if(not isinstance(self._name, ConstraintName) or not self._name.is_mat_constraint()):
raise TypeError('ConstraintMat first argument must be a '
'ConstraintName with a matrix type name '
'(name.is_mat_constraint() must return True)')
def project(self, M):
# TODO: call parent project()
return FaustCorePy.ConstraintMatCore.project(M, self._name.name, self._num_rows,
self._num_cols, self._cons_value)
class ConstraintReal(ConstraintGeneric):
"""
This class represents a real constraint on a matrix-factor.
......@@ -131,6 +148,11 @@ class ConstraintReal(ConstraintGeneric):
'ConstraintName with a real type name '
'(name.is_real_constraint() must return True).')
def project(self, M):
return FaustCorePy.ConstraintRealCore.project(M, self._name.name, self._num_rows,
self._num_cols, self._cons_value)
class ConstraintName:
"""
Attributes:
......
......@@ -101,15 +101,28 @@ cdef extern from "FaustCoreCpp.h" :
@staticmethod
FaustCoreCpp[FPP]* fourierFaust(unsigned int n)
# TODO: all the headers below should be in their own pxd file FaustFact.pxd
cdef extern from "FaustFact.h":
cdef cppclass PyxConstraintGeneric:
int name
unsigned long num_rows
unsigned long num_cols
bool is_int_constraint()
bool is_real_constraint()
bool is_mat_constraint()
cdef cppclass PyxConstraintInt(PyxConstraintGeneric):
unsigned long parameter
void prox_int[FPP](unsigned int cons_type, unsigned long cons_param, FPP* mat_in, unsigned long num_rows,
unsigned long num_cols, FPP* mat_out)
void prox_real[FPP,FPP2](unsigned int cons_type, FPP2 cons_param, FPP* mat_in, unsigned long num_rows,
unsigned long num_cols, FPP* mat_out)
void prox_mat[FPP](unsigned int cons_type, FPP* cons_param, FPP* mat_in, unsigned long num_rows,
unsigned long num_cols, FPP* mat_out)
cdef cppclass PyxConstraintScalar[FPP](PyxConstraintGeneric):
FPP parameter
......
......@@ -715,16 +715,118 @@ cdef check_matrix(isReal, M):
if (ndim_M > 2) | (ndim_M < 1):
raise ValueError('input M invalid number of dimensions')
cdef class ConstraintIntCore:
# no need to create an object, because project() needs to create core object
# for each call and for that purpose it needs to determine if mat is real or complex
# so it can't create the object before the call
# in that conditions a static method will suffice
@staticmethod
def project(M, name, num_rows, num_cols, parameter):
cdef double[:,:] M_view_dbl
cdef double[:,:] M_out_view_dbl
cdef complex[:,:] M_view_cplx
cdef complex[:,:] M_out_view_cplx
isReal = M.dtype in [ 'float', 'float128',
'float16', 'float32',
'float64', 'double']
M_out = np.empty(M.shape, dtype=M.dtype, order='F')
check_matrix(isReal, M)
if(isReal):
M_view_dbl = M
M_out_view_dbl = M_out
FaustCoreCy.prox_int[double](name, parameter, &M_view_dbl[0,0], num_rows,
num_cols,&M_out_view_dbl[0,0])
else:
M_view_cplx = M
M_out_view_cplx = M_out
FaustCoreCy.prox_int[complex](name, parameter, &M_view_cplx[0,0],
num_rows, num_cols, &M_out_view_cplx[0,0])
return M_out
cdef class ConstraintMatCore:
@staticmethod
def project(M, name, num_rows, num_cols, parameter):
cdef double[:,:] M_view_dbl
cdef double[:,:] M_out_view_dbl
cdef complex[:,:] M_view_cplx
cdef complex[:,:] M_out_view_cplx
cdef double[:,:] param_view_dbl
cdef complex[:,:] param_view_cplx
isReal = M.dtype in [ 'float', 'float128',
'float16', 'float32',
'float64', 'double']
M_out = np.empty(M.shape, dtype=M.dtype, order='F')
check_matrix(isReal, M)
check_matrix(isReal, parameter)
if(isReal):
M_view_dbl = M
M_out_view_dbl = M_out
param_view_dbl = parameter
FaustCoreCy.prox_mat[double](name, &param_view_dbl[0,0], &M_view_dbl[0,0], num_rows,
num_cols,&M_out_view_dbl[0,0])
else:
M_view_cplx = M
M_out_view_cplx = M_out
param_view_cplx = parameter
FaustCoreCy.prox_mat[complex](name, &param_view_cplx[0,0], &M_view_cplx[0,0],
num_rows, num_cols, &M_out_view_cplx[0,0])
return M_out
cdef class ConstraintRealCore:
# no need to create an object, because project() needs to create core object
# for each call and for that purpose it needs to determine if mat is real or complex
# so it can't create the object before the call
# in that conditions a static method will suffice
@staticmethod
def project(M, name, num_rows, num_cols, parameter):
cdef double[:,:] M_view_dbl
cdef double[:,:] M_out_view_dbl
cdef complex[:,:] M_view_cplx
cdef complex[:,:] M_out_view_cplx
isReal = M.dtype in [ 'float', 'float128',
'float16', 'float32',
'float64', 'double']
M_out = np.empty(M.shape, dtype=M.dtype, order='F')
check_matrix(isReal, M)
if(isReal):
M_view_dbl = M
M_out_view_dbl = M_out
FaustCoreCy.prox_real[double, double](name, parameter, &M_view_dbl[0,0], num_rows,
num_cols,&M_out_view_dbl[0,0])
else:
M_view_cplx = M
M_out_view_cplx = M_out
FaustCoreCy.prox_real[complex, double](name, parameter, &M_view_cplx[0,0],
num_rows, num_cols, &M_out_view_cplx[0,0])
return M_out
cdef class FaustFact:
@staticmethod
def fact_palm4MSA(M, p):
def fact_palm4msa(M, p):
isReal = M.dtype in [ 'float', 'float128',
'float16', 'float32',
'float64', 'double']
# double == float64
#TODO: it not float nor complex, raise exception
#TODO: if not float nor complex, raise exception
check_matrix(isReal, M)
cdef unsigned int M_num_rows=M.shape[0]
......
......@@ -35,6 +35,17 @@ class PyxConstraintMat : public PyxConstraintGeneric
FPP* parameter;
};
template<typename FPP>
void prox_int(unsigned int cons_type, unsigned long cons_param, FPP* mat_in, unsigned long num_rows,
unsigned long num_cols, FPP* mat_out);
template<typename FPP, typename FPP2>
void prox_real(unsigned int cons_type, FPP2 cons_param, FPP* mat_in, unsigned long num_rows,
unsigned long num_cols, FPP* mat_out);
template<typename FPP>
void prox_mat(unsigned int cons_type, FPP* cons_param, FPP* mat_in, unsigned long num_rows, unsigned long num_cols, FPP* mat_out);
template<typename FPP>
class PyxStoppingCriterion
{
......
......@@ -51,6 +51,70 @@ bool PyxConstraintGeneric::is_mat_constraint()
}
}
template<typename FPP>
void prox_mat(unsigned int cons_type, FPP* cons_param, FPP* mat_in, unsigned long num_rows, unsigned long num_cols, FPP* mat_out)
{
Faust::MatDense<FPP, Cpu> fmat(mat_in, num_rows, num_cols);
switch(static_cast<faust_constraint_name>(cons_type))
{
case CONSTRAINT_NAME_CONST: /**< Matrix equal to A ; MAT */
// nothing to do, same mat returned
break;
case CONSTRAINT_NAME_BLKDIAG:
//not impl. yet in cpp core
break;
case CONSTRAINT_NAME_SUPP: /**< Matrix which support is equal to A ; MAT ; (frobenius norm 1)*/
Faust::prox_supp(fmat, Faust::MatDense<FPP,Cpu>(cons_param, num_rows, num_cols));
break;
default:
throw invalid_argument("PyxConstraintMat::project() inconsistent constraint name");
}
memcpy(mat_out, fmat.getData(), sizeof(FPP)*num_rows*num_cols);
}
template<typename FPP>
void prox_int(unsigned int cons_type, unsigned long cons_param, FPP* mat_in, unsigned long num_rows,
unsigned long num_cols, FPP* mat_out)
{
Faust::MatDense<FPP, Cpu> fmat(mat_in, num_rows, num_cols);
switch(static_cast<faust_constraint_name>(cons_type))
{
case CONSTRAINT_NAME_SPCOL: /*!< fixed number of non zero elements per column INT (frobenius norm 1) */
Faust::prox_spcol(fmat, (faust_unsigned_int) cons_param);
break;
case CONSTRAINT_NAME_SPLIN: /*!< fixed number of non zero elements per line INT (frobenius norm 1) */
Faust::prox_splin(fmat, (faust_unsigned_int) cons_param);
break;
case CONSTRAINT_NAME_SPLINCOL:
Faust::prox_splincol(fmat, (faust_unsigned_int) cons_param);
break;
case CONSTRAINT_NAME_SP_POS:/**< fixed number of non zeros coefficients: INT (frobenius norm 1) */
Faust::prox_sp_pos(fmat, (faust_unsigned_int) cons_param);
break;
default:
throw invalid_argument("PyxConstraintInt::project() inconsistent constraint name");
}
memcpy(mat_out, fmat.getData(), sizeof(FPP)*num_rows*num_cols);
}
template<typename FPP, typename FPP2>
void prox_real(unsigned int cons_type, FPP2 cons_param, FPP* mat_in, unsigned long num_rows, unsigned long num_cols, FPP* mat_out)
{
Faust::MatDense<FPP, Cpu> fmat(mat_in, num_rows, num_cols);
switch(static_cast<faust_constraint_name>(cons_type))
{
case CONSTRAINT_NAME_NORMLIN:/**< 2nd norm of the lines of matrix A ; REAL */
Faust::prox_normlin(fmat, cons_param);
break;
case CONSTRAINT_NAME_NORMCOL:/*!< 2nd norm of the columns of A REAL */
Faust::prox_normcol(fmat, cons_param);
break;
default:
throw invalid_argument("PyxConstraintScalar::project() inconsistent constraint name");
}
memcpy(mat_out, fmat.getData(), sizeof(FPP)*num_rows*num_cols);
}
template<typename FPP, typename FPP2>
void prepare_fact(const FPP* mat, const unsigned int num_rows, const unsigned int num_cols, const PyxParamsFact<FPP,FPP2>* p,
/* out args */vector<const Faust::ConstraintGeneric*>& cons)
......@@ -106,7 +170,7 @@ void prepare_fact(const FPP* mat, const unsigned int num_rows, const unsigned in
else
handleError("FaustFact", "Invalid constraint.");
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment