Mentions légales du service

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

Reorganize the pyfaust module into a real package with submodules.

Updating cmake scripts, pkg gen. scripts, pkg post-inst. scripts, unit tests and doxydoc to conform with this change.
parent c7adcadd
No related branches found
No related tags found
No related merge requests found
...@@ -16,7 +16,7 @@ function link_py_files(){ ...@@ -16,7 +16,7 @@ function link_py_files(){
# on fedora python package path are suffixed by site-packages, on ubuntu it's rather dist-packages (TODO: on centos ? on debian ?) # on fedora python package path are suffixed by site-packages, on ubuntu it's rather dist-packages (TODO: on centos ? on debian ?)
PY_SITE_PACKAGES_PATH=$(python$PY_MAJOR_VER -c 'import os,site,re;print([path for path in site.getsitepackages() if (re.match(".*"+os.path.sep+"site-packages$", path) or re.match(".*"+os.path.sep+"dist-packages$", path)) and os.path.exists(path) ][0])') PY_SITE_PACKAGES_PATH=$(python$PY_MAJOR_VER -c 'import os,site,re;print([path for path in site.getsitepackages() if (re.match(".*"+os.path.sep+"site-packages$", path) or re.match(".*"+os.path.sep+"dist-packages$", path)) and os.path.exists(path) ][0])')
[[ ! -d ${PY_SITE_PACKAGES_PATH} ]] && echo -e "\033[1mWARNING\033[0m: couldn't link the Faust py wrapper for python$PY_MAJOR_VER to your system. Either python$PY_MAJOR_VER is not installed on your system and that's pretty normal or it failed for another reason and you'll have to add Faust to your PYTHONPATH manually for using it (see the documentation)." >&2 && return 1 [[ ! -d ${PY_SITE_PACKAGES_PATH} ]] && echo -e "\033[1mWARNING\033[0m: couldn't link the Faust py wrapper for python$PY_MAJOR_VER to your system. Either python$PY_MAJOR_VER is not installed on your system and that's pretty normal or it failed for another reason and you'll have to add Faust to your PYTHONPATH manually for using it (see the documentation)." >&2 && return 1
PYFILES=${FAUST_PY_WRAPPER_PATH}/pyfaust.py PYFILES=${FAUST_PY_WRAPPER_PATH}/pyfaust
[[ -n "$DEBUG" ]] && echo PY_MAJOR_VER=$PY_MAJOR_MINOR_VER [[ -n "$DEBUG" ]] && echo PY_MAJOR_VER=$PY_MAJOR_MINOR_VER
if [[ "$PY_MAJOR_VER" = 3* ]] if [[ "$PY_MAJOR_VER" = 3* ]]
then then
......
...@@ -16,7 +16,7 @@ function link_py_files(){ ...@@ -16,7 +16,7 @@ function link_py_files(){
PY_SITE_PACKAGES_PATH=$($PYTHON -c 'import os,site,re;print([path for path in site.getsitepackages() if re.match(".*"+os.path.sep+"site-packages$", path) and os.path.exists(path) ][0])') PY_SITE_PACKAGES_PATH=$($PYTHON -c 'import os,site,re;print([path for path in site.getsitepackages() if re.match(".*"+os.path.sep+"site-packages$", path) and os.path.exists(path) ][0])')
[[ ! -d "${PY_SITE_PACKAGES_PATH}" ]] && return [[ ! -d "${PY_SITE_PACKAGES_PATH}" ]] && return
[[ -n "$DEBUG" ]] && echo PY_SITE_PACKAGES_PATH=${PY_SITE_PACKAGES_PATH} [[ -n "$DEBUG" ]] && echo PY_SITE_PACKAGES_PATH=${PY_SITE_PACKAGES_PATH}
PYFILES=${FAUST_PY_WRAPPER_PATH}/pyfaust.py PYFILES=${FAUST_PY_WRAPPER_PATH}/pyfaust
[[ "$PY_MAJOR_MINOR_VER" = 3* ]] && PYFILES+=" ${FAUST_PY_WRAPPER_PATH}/FaustCorePy.cpython-3*so" || \ [[ "$PY_MAJOR_MINOR_VER" = 3* ]] && PYFILES+=" ${FAUST_PY_WRAPPER_PATH}/FaustCorePy.cpython-3*so" || \
PYFILES+=" ${FAUST_PY_WRAPPER_PATH}/FaustCorePy.so" PYFILES+=" ${FAUST_PY_WRAPPER_PATH}/FaustCorePy.so"
for PYFILE in $PYFILES for PYFILE in $PYFILES
......
...@@ -94,8 +94,9 @@ Section "" ; no component so name not needed ...@@ -94,8 +94,9 @@ Section "" ; no component so name not needed
CreateDirectory $INSTDIR\doc\html CreateDirectory $INSTDIR\doc\html
; install python wrapper ; install python wrapper
SetOutPath $INSTDIR\python SetOutPath $INSTDIR\python\pyfaust
File @PROJECT_BINARY_DIR@\wrapper\python\*py File @PROJECT_BINARY_DIR@\wrapper\python\*py
SetOutPath $INSTDIR\python
File @PROJECT_BINARY_DIR@\wrapper\python\*pyd File @PROJECT_BINARY_DIR@\wrapper\python\*pyd
File @PROJECT_BINARY_DIR@\wrapper\python\*pxd File @PROJECT_BINARY_DIR@\wrapper\python\*pxd
...@@ -115,8 +116,9 @@ Section "" ; no component so name not needed ...@@ -115,8 +116,9 @@ Section "" ; no component so name not needed
FileClose $1 FileClose $1
;MessageBox MB_OK "$2" ;MessageBox MB_OK "$2"
SetOutPath $2 SetOutPath $2\pyfaust
File @PROJECT_BINARY_DIR@\wrapper\python\*py File /r @PROJECT_BINARY_DIR@\wrapper\python\pyfaust\*py
SetOutPath $2
File @PROJECT_BINARY_DIR@\wrapper\python\*pyd File @PROJECT_BINARY_DIR@\wrapper\python\*pyd
File @PROJECT_BINARY_DIR@\wrapper\python\*pxd File @PROJECT_BINARY_DIR@\wrapper\python\*pxd
......
...@@ -427,8 +427,10 @@ class TestFaustFactory(unittest.TestCase): ...@@ -427,8 +427,10 @@ class TestFaustFactory(unittest.TestCase):
def testFactPalm4MSA(self): def testFactPalm4MSA(self):
print("Test FaustFactory.fact_palm4msa()") print("Test FaustFactory.fact_palm4msa()")
from pyfaust import FaustFactory, ParamsPalm4MSA, ConstraintReal,\ from pyfaust import FaustFactory;
ConstraintInt, ConstraintName, StoppingCriterion from pyfaust.constraints import ConstraintReal,\
ConstraintInt, ConstraintName
from pyfaust.params import ParamsPalm4MSA, StoppingCriterion
num_facts = 2 num_facts = 2
is_update_way_R2L = False is_update_way_R2L = False
init_lambda = 1.0 init_lambda = 1.0
...@@ -459,8 +461,10 @@ class TestFaustFactory(unittest.TestCase): ...@@ -459,8 +461,10 @@ class TestFaustFactory(unittest.TestCase):
def testFactHierarch(self): def testFactHierarch(self):
print("Test FaustFactory.fact_hierarchical()") print("Test FaustFactory.fact_hierarchical()")
from pyfaust import FaustFactory, ParamsHierarchicalFact, ConstraintReal,\ from pyfaust import FaustFactory
ConstraintInt, ConstraintName, StoppingCriterion from pyfaust.params import ParamsHierarchicalFact, StoppingCriterion
from pyfaust.constraints import ConstraintReal, ConstraintInt,\
ConstraintName
num_facts = 4 num_facts = 4
is_update_way_R2L = False is_update_way_R2L = False
init_lambda = 1.0 init_lambda = 1.0
...@@ -493,8 +497,10 @@ class TestFaustFactory(unittest.TestCase): ...@@ -493,8 +497,10 @@ class TestFaustFactory(unittest.TestCase):
def testFactHierarchCplx(self): def testFactHierarchCplx(self):
print("Test FaustFactory.fact_hierarchicalCplx()") print("Test FaustFactory.fact_hierarchicalCplx()")
from pyfaust import FaustFactory, ParamsHierarchicalFact, ConstraintReal,\ from pyfaust import FaustFactory
ConstraintInt, ConstraintName, StoppingCriterion from pyfaust.params import ParamsHierarchicalFact, StoppingCriterion
from pyfaust.constraints import ConstraintReal,\
ConstraintInt, ConstraintName
num_facts = 4 num_facts = 4
is_update_way_R2L = False is_update_way_R2L = False
init_lambda = 1.0 init_lambda = 1.0
...@@ -529,8 +535,10 @@ class TestFaustFactory(unittest.TestCase): ...@@ -529,8 +535,10 @@ class TestFaustFactory(unittest.TestCase):
def testFactPalm4MSACplx(self): def testFactPalm4MSACplx(self):
print("Test FaustFactory.fact_palm4msaCplx()") print("Test FaustFactory.fact_palm4msaCplx()")
from pyfaust import FaustFactory, ParamsPalm4MSA, ConstraintReal,\ from pyfaust import FaustFactory
ConstraintInt, ConstraintName, StoppingCriterion from pyfaust.params import ParamsPalm4MSA,StoppingCriterion
from pyfaust.constraints import ConstraintReal,\
ConstraintInt, ConstraintName
num_facts = 2 num_facts = 2
is_update_way_R2L = False is_update_way_R2L = False
init_lambda = 1.0 init_lambda = 1.0
......
...@@ -47,7 +47,14 @@ configure_file(${FAUST_PYTHON_SRC_DIR}/quickstart.py ${FAUST_PYTHON_BIN_DIR}/qui ...@@ -47,7 +47,14 @@ configure_file(${FAUST_PYTHON_SRC_DIR}/quickstart.py ${FAUST_PYTHON_BIN_DIR}/qui
configure_file(${FAUST_PYTHON_SRC_DIR}/setup.py.in ${FAUST_PYTHON_BIN_DIR}/setup.py @ONLY) configure_file(${FAUST_PYTHON_SRC_DIR}/setup.py.in ${FAUST_PYTHON_BIN_DIR}/setup.py @ONLY)
configure_file(${FAUST_PYTHON_SRC_SRC_DIR}/FaustCorePy.pyx ${FAUST_PYTHON_BIN_DIR}/FaustCorePy.pyx COPYONLY) configure_file(${FAUST_PYTHON_SRC_SRC_DIR}/FaustCorePy.pyx ${FAUST_PYTHON_BIN_DIR}/FaustCorePy.pyx COPYONLY)
configure_file(${FAUST_PYTHON_SRC_SRC_DIR}/FaustCoreCy.pxd ${FAUST_PYTHON_BIN_DIR}/FaustCoreCy.pxd COPYONLY) configure_file(${FAUST_PYTHON_SRC_SRC_DIR}/FaustCoreCy.pxd ${FAUST_PYTHON_BIN_DIR}/FaustCoreCy.pxd COPYONLY)
configure_file(${FAUST_PYTHON_SRC_DIR}/pyfaust.py ${FAUST_PYTHON_BIN_DIR}/pyfaust.py COPYONLY)
message(STATUS "Installing pyfaust.py as pyfaust/__init__.py")
configure_file(${FAUST_PYTHON_SRC_DIR}/pyfaust.py ${FAUST_PYTHON_BIN_DIR}/pyfaust/__init__.py)
FILE(GLOB_RECURSE PYFAUST_FILES RELATIVE ${FAUST_PYTHON_SRC_DIR} ${FAUST_PYTHON_SRC_DIR}/pyfaust/*py)
foreach(PYFAUST_FILE ${PYFAUST_FILES})
message(STATUS "Installing ${PYFAUST_FILE}")
configure_file(${FAUST_PYTHON_SRC_DIR}/${PYFAUST_FILE} ${FAUST_PYTHON_BIN_DIR}/${PYFAUST_FILE} COPYONLY)
endforeach()
add_custom_target(${FAUST_PYTHON_TARGET} ALL DEPENDS ${FAUST_TARGET}) add_custom_target(${FAUST_PYTHON_TARGET} ALL DEPENDS ${FAUST_TARGET})
...@@ -141,4 +148,4 @@ else() ...@@ -141,4 +148,4 @@ else()
endif() endif()
#install the python wrapper #install the python wrapper
install(DIRECTORY ${FAUST_PYTHON_BIN_DIR}/ DESTINATION ${CMAKE_INSTALL_PYTHON_PREFIX} FILE_PERMISSIONS ${INSTALL_FILE_PERMISSION} DIRECTORY_PERMISSIONS ${INSTALL_DIR_PERMISSION} FILES_MATCHING PATTERN "*.${MEX_EXT}" PATTERN "*.py" PATTERN "*.so" PATTERN "*.pyd" PATTERN "build" EXCLUDE PATTERN "setup*" EXCLUDE PATTERN "CMakeFiles*" EXCLUDE) install(DIRECTORY ${FAUST_PYTHON_BIN_DIR}/ DESTINATION ${CMAKE_INSTALL_PYTHON_PREFIX} FILE_PERMISSIONS ${INSTALL_FILE_PERMISSION} DIRECTORY_PERMISSIONS ${INSTALL_DIR_PERMISSION} FILES_MATCHING PATTERN "*.${MEX_EXT}" PATTERN "pyfaust/*.py" PATTERN "*.so" PATTERN "*.pyd" PATTERN "build" EXCLUDE PATTERN "setup*" EXCLUDE PATTERN "CMakeFiles*" EXCLUDE)
...@@ -46,7 +46,7 @@ import numpy as np ...@@ -46,7 +46,7 @@ import numpy as np
from scipy.io import savemat, loadmat from scipy.io import savemat, loadmat
from scipy.sparse import csr_matrix, csc_matrix from scipy.sparse import csr_matrix, csc_matrix
import FaustCorePy import FaustCorePy
import pyfaust
class Faust: class Faust:
"""FAµST Python wrapper main class. """FAµST Python wrapper main class.
...@@ -1146,7 +1146,7 @@ class FaustFactory: ...@@ -1146,7 +1146,7 @@ class FaustFactory:
>>> print(norm(F.get_factor(1)[:,i]), end=end) >>> print(norm(F.get_factor(1)[:,i]), end=end)
1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
""" """
if(not isinstance(p, ParamsPalm4MSA)): if(not isinstance(p, pyfaust.params.ParamsPalm4MSA)):
raise ValueError("p must be a ParamsPalm4MSA object.") raise ValueError("p must be a ParamsPalm4MSA object.")
FaustFactory._check_fact_mat('FaustFactory.fact_palm4msa()', M) FaustFactory._check_fact_mat('FaustFactory.fact_palm4msa()', M)
return Faust(core_obj=FaustCorePy.FaustFact.fact_palm4MSA(M, p)) return Faust(core_obj=FaustCorePy.FaustFact.fact_palm4MSA(M, p))
...@@ -1199,7 +1199,7 @@ class FaustFactory: ...@@ -1199,7 +1199,7 @@ class FaustFactory:
- FACTOR 2 (real) SPARSE, size 32x32, density 0.09375, nnz 96 - FACTOR 2 (real) SPARSE, size 32x32, density 0.09375, nnz 96
- FACTOR 3 (real) SPARSE, size 32x32, density 0.325195, nnz 333 - FACTOR 3 (real) SPARSE, size 32x32, density 0.325195, nnz 333
""" """
if(not isinstance(p, ParamsHierarchicalFact)): if(not isinstance(p, pyfaust.params.ParamsHierarchicalFact)):
raise ValueError("p must be a ParamsHierarchicalFact object.") raise ValueError("p must be a ParamsHierarchicalFact object.")
FaustFactory._check_fact_mat('FaustFactory.fact_hierarchical()', M) FaustFactory._check_fact_mat('FaustFactory.fact_hierarchical()', M)
return Faust(core_obj=FaustCorePy.FaustFact.fact_hierarchical(M, p)) return Faust(core_obj=FaustCorePy.FaustFact.fact_hierarchical(M, p))
...@@ -1383,265 +1383,3 @@ class FaustFactory: ...@@ -1383,265 +1383,3 @@ class FaustFactory:
# "factorization.") # "factorization.")
class ParamsFact(object):
def __init__(self, num_facts, is_update_way_R2L, init_lambda,
constraints, step_size, constant_step_size=False, is_verbose=False,
):
self.num_facts = num_facts
self.is_update_way_R2L = is_update_way_R2L
self.init_lambda = init_lambda
self.step_size = step_size
self.constraints = constraints
self.is_verbose = is_verbose
self.constant_step_size = constant_step_size
class ParamsPalm4MSA(ParamsFact):
def __init__(self, num_facts, is_update_way_R2L, init_lambda,
constraints, stop_crit, init_facts=None, step_size=10.0**-16,
constant_step_size=False,
is_verbose=False):
super(ParamsPalm4MSA, self).__init__(num_facts, is_update_way_R2L,
init_lambda,
constraints, step_size,
constant_step_size,
is_verbose)
if(init_facts != None and (not isinstance(init_facts, list) and not isinstance(init_facts,
tuple) or
len(init_facts) != num_facts)):
raise ValueError('ParamsPalm4MSA init_facts argument must be a '
'list/tuple of '+str(num_facts)+" (num_facts) arguments.")
else:
self.init_facts = init_facts
if(not isinstance(stop_crit, StoppingCriterion)):
raise TypeError('ParamsPalm4MSA stop_crit argument must be a StoppingCriterion '
'object')
self.stop_crit = stop_crit
#TODO: verify number of constraints is consistent with num_facts
class ParamsHierarchicalFact(ParamsFact):
def __init__(self, num_facts, is_update_way_R2L, init_lambda,
fact_constraints, res_constraints, data_num_rows,
data_num_cols, stop_crits,
step_size=10.0**-16, constant_step_size=False,
is_verbose=False,
is_fact_side_left = False):
constraints = fact_constraints + res_constraints
super(ParamsHierarchicalFact, self).__init__(num_facts,
is_update_way_R2L,
init_lambda,
constraints, step_size,
constant_step_size,
is_verbose)
self.data_num_rows = data_num_rows
self.data_num_cols = data_num_cols
self.stop_crits = stop_crits
self.is_fact_side_left = is_fact_side_left
#TODO: verify number of constraints is consistent with num_facts in
if((not isinstance(stop_crits, list) and not isinstance(stop_crits,
tuple)) or
len(stop_crits) != 2 or
not isinstance(stop_crits[0],StoppingCriterion) or not
isinstance(stop_crits[1],StoppingCriterion)):
raise TypeError('ParamsHierarchicalFact stop_crits argument must be a list/tuple of two '
'StoppingCriterion objects')
if((not isinstance(constraints, list) and not isinstance(constraints,
tuple)) or
np.array([not isinstance(constraints[i],ConstraintGeneric) for i in
range(0,len(constraints))]).any()):
raise TypeError('constraints argument must be a list/tuple of '
'ConstraintGeneric (or subclasses) objects')
class StoppingCriterion(object):
def __init__(self, is_criterion_error = False , error_treshold = 0.3,
num_its = 500,
max_num_its = 1000):
self.is_criterion_error = is_criterion_error
self.error_treshold = error_treshold
self.num_its = num_its
self.max_num_its = max_num_its
#TODO: check_validity() like C++ code does
if(is_criterion_error and num_its != 500):
raise ValueError("It's forbidden to set a number of iterations as stopping"
" criterion when is_criterion_error == True.")
elif(not is_criterion_error and (max_num_its != 1000 or error_treshold
!= 0.3)):
raise ValueError("When is_criterion_error == True it's forbidden to use"
" other arguments than num_its argument to define "
"the stopping criterion.")
class ConstraintName:
"""
Attributes:
SP: Designates a constraint on the sparsity/0-norm of a matrix.
SPCOL: Designates a sparsity/0-norm constraint on the columns of a
matrix.
SPLIN: Designates a sparsity/0-norm constraint on the lines of a
matrix.
SPLINCOL: Designates a constraint that imposes both SPLIN and SPCOL
constraints.
SP_POS: Designates a constraint that imposes a SP constraints and
besides erase the negative coefficients (it doesn't apply to complex
matrices).
NORMCOL: Designates a 2-norm constraint on the columns of a matrix.
NORMLIN: Designates a 2-norm constraint on the lines of a matrix.
CONST: Designates a constraint imposing to a matrix to be constant.
"""
SP = 0 # Int Constraint
SPCOL = 1 # Int Constraint
SPLIN=2 # Int Constraint
NORMCOL = 3 # Real Constraint
SPLINCOL = 4 # Int Constraint
CONST = 5 # Mat Constraint
SP_POS = 6 # Int Constraint
#BLKDIAG = 7 # ?? Constraint #TODO
SUPP = 8 # Mat Constraint
NORMLIN = 9 # Real Constraint
def __init__(self, name):
if(not isinstance(name, np.int) or name < ConstraintName.SP or name > ConstraintName.NORMLIN):
raise ValueError("name must be an integer among ConstraintName.SP,"
"ConstraintName.SPCOL, ConstraintName.NORMCOL,"
"ConstraintName.SPLINCOL, ConstraintName.CONST,"
"ConstraintName.SP_POS," # ConstraintName.BLKDIAG,
"ConstraintName.SUPP, ConstraintName.NORMLIN")
self.name = name
def is_int_constraint(self):
return self.name in [ ConstraintName.SP, ConstraintName.SPCOL,
ConstraintName.SPLIN, ConstraintName.SPLINCOL,
ConstraintName.SP_POS ]
def is_real_constraint(self):
return self.name in [ ConstraintName.NORMCOL, ConstraintName.NORMLIN ]
def is_mat_constraint(self):
return self.name in [ConstraintName.SUPP, ConstraintName.CONST ]
class ConstraintGeneric(object):
"""
This is the parent class for representing a factor constraint in FAµST factorization algorithms.
This class shouldn't be instantiated, rather rely on sub-classes.
<b/> See also: ConstraintInt, ConstraintReal, ConstraintMat, FaustFactory.fact_palm4msa, FaustFactory.fact_hierarchical.
Attributes:
_name: The name of the constraint applied to the factor (ConstraintName instance).
_num_rows: The number of rows to constrain the factor to.
_num_cols: The number of columns to constrain the factor to.
_cons_value: The parameter value of the constraint.
"""
def __init__(self, name, num_rows, num_cols, cons_value):
"""
Constructs a generic constraint.
Args:
name: the name of the constraint applied to the factor (ConstraintName instance).
num_rows: the number of rows to constrain the factor to.
num_cols: the number of columns to constrain the factor to.
cons_value: the parameter value of the constraint.
"""
self._name = name
self._num_rows = num_rows
self._num_cols = num_cols
self._cons_value = cons_value
@property
def name(self):
"""
Property to access the ConstraintName of the constraint.
"""
return self._name.name
def is_int_constraint(self):
"""
Returns True if this constraint is a ConstraintInt, False otherwise.
"""
return self._name.is_int_constraint()
def is_real_constraint(self):
"""
Returns True if this constraint is a ConstraintReal, False otherwise.
"""
return self._name.is_real_constraint()
def is_mat_constraint(self):
"""
Returns True if this constraint is a ConstraintMat, False otherwise.
"""
return self._name.is_mat_constraint()
class ConstraintReal(ConstraintGeneric):
"""
This class represents a real constraint on a matrix-factor.
It constrains a matrix by a column/row-vector 2-norm
(ConstraintName.NORMCOL, ConstraintName.NORMLIN).
"""
def __init__(self, name, num_rows, num_cols, cons_value):
"""
Constructs a real type constraint.
Args:
name: the name of the constraint applied to the factor. It must be
a ConstraintName instance.
num_rows: the number of rows to constrain the factor to.
num_cols: the number of columns to constrain the factor to.
cons_value: the parameter value of the constraint, it must be a
float number that designates the 2-norm imposed to all columns (if
name.name == ConstraintName.NORMCOL) or rows (if
name.name == ConstraintName.NORMLIN).
"""
super(ConstraintReal, self).__init__(name, num_rows, num_cols, cons_value)
if(not isinstance(cons_value, np.float) and not isinstance(cons_value, np.int)):
raise TypeError('ConstraintReal must receive a float as cons_value '
'argument.')
self._cons_value = float(self._cons_value)
if(not isinstance(name, ConstraintName) or not name.is_real_constraint()):
raise TypeError('ConstraintReal first argument must be a '
'ConstraintName with a real type name '
'(name.is_real_constraint() must return True).')
class ConstraintInt(ConstraintGeneric):
"""
This class represents an integer constraint on a matrix-factor.
It constrains a matrix by its column/row-vectors sparsity or 0-norm
(ConstraintName.SPLIN, ConstraintName.SPCOL, ConstraintName.SPLINCOL).
"""
def __init__(self, name, num_rows, num_cols, cons_value):
super(ConstraintInt, self).__init__(name, num_rows, num_cols, cons_value)
if(not isinstance(cons_value, np.int)):
raise TypeError('ConstraintInt must receive a int as cons_value '
'argument.')
if(not isinstance(name, ConstraintName) or not name.is_int_constraint()):
raise TypeError('ConstraintInt first argument must be a '
'ConstraintName with a int type name '
'(name.is_int_constraint() must return True).')
class ConstraintMat(ConstraintGeneric):
def __init__(self, name, num_rows, num_cols, cons_value):
super(ConstraintMat, self).__init__(name, num_rows, num_cols, cons_value)
if(not isinstance(cons_value, np.matrix) and not isinstance(cons_value,
np.ndarray)):
raise TypeError('ConstraintMat must receive a numpy matrix as cons_value '
'argument.')
self.cons_value = float(self.cons_value)
if(not isinstance(name, ConstraintName) or not 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).')
# -*- coding: utf-8 -*-
from pyfaust import *
class ConstraintGeneric(object):
"""
This is the parent class for representing a factor constraint in FAµST factorization algorithms.
This class shouldn't be instantiated, rather rely on sub-classes.
<b/> See also: ConstraintInt, ConstraintReal, ConstraintMat, FaustFactory.fact_palm4msa, FaustFactory.fact_hierarchical.
Attributes:
_name: The name of the constraint applied to the factor (ConstraintName instance).
_num_rows: The number of rows to constrain the factor to.
_num_cols: The number of columns to constrain the factor to.
_cons_value: The parameter value of the constraint.
"""
def __init__(self, name, num_rows, num_cols, cons_value):
"""
Constructs a generic constraint.
Args:
name: the name of the constraint applied to the factor (ConstraintName instance).
num_rows: the number of rows to constrain the factor to.
num_cols: the number of columns to constrain the factor to.
cons_value: the parameter value of the constraint.
"""
self._name = name
self._num_rows = num_rows
self._num_cols = num_cols
self._cons_value = cons_value
@property
def name(self):
"""
Property to access the ConstraintName of the constraint.
"""
return self._name.name
def is_int_constraint(self):
"""
Returns True if this constraint is a ConstraintInt, False otherwise.
"""
return self._name.is_int_constraint()
def is_real_constraint(self):
"""
Returns True if this constraint is a ConstraintReal, False otherwise.
"""
return self._name.is_real_constraint()
def is_mat_constraint(self):
"""
Returns True if this constraint is a ConstraintMat, False otherwise.
"""
return self._name.is_mat_constraint()
class ConstraintInt(ConstraintGeneric):
"""
This class represents an integer constraint on a matrix-factor.
It constrains a matrix by its column/row-vectors sparsity or 0-norm
(ConstraintName.SPLIN, ConstraintName.SPCOL, ConstraintName.SPLINCOL).
"""
def __init__(self, name, num_rows, num_cols, cons_value):
super(ConstraintInt, self).__init__(name, num_rows, num_cols, cons_value)
if(not isinstance(cons_value, np.int)):
raise TypeError('ConstraintInt must receive a int as cons_value '
'argument.')
if(not isinstance(name, ConstraintName) or not name.is_int_constraint()):
raise TypeError('ConstraintInt first argument must be a '
'ConstraintName with a int type name '
'(name.is_int_constraint() must return True).')
class ConstraintMat(ConstraintGeneric):
def __init__(self, name, num_rows, num_cols, cons_value):
super(ConstraintMat, self).__init__(name, num_rows, num_cols, cons_value)
if(not isinstance(cons_value, np.matrix) and not isinstance(cons_value,
np.ndarray)):
raise TypeError('ConstraintMat must receive a numpy matrix as cons_value '
'argument.')
self.cons_value = float(self.cons_value)
if(not isinstance(name, ConstraintName) or not 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)')
class ConstraintReal(ConstraintGeneric):
"""
This class represents a real constraint on a matrix-factor.
It constrains a matrix by a column/row-vector 2-norm
(ConstraintName.NORMCOL, ConstraintName.NORMLIN).
"""
def __init__(self, name, num_rows, num_cols, cons_value):
"""
Constructs a real type constraint.
Args:
name: the name of the constraint applied to the factor. It must be
a ConstraintName instance.
num_rows: the number of rows to constrain the factor to.
num_cols: the number of columns to constrain the factor to.
cons_value: the parameter value of the constraint, it must be a
float number that designates the 2-norm imposed to all columns (if
name.name == ConstraintName.NORMCOL) or rows (if
name.name == ConstraintName.NORMLIN).
"""
super(ConstraintReal, self).__init__(name, num_rows, num_cols, cons_value)
if(not isinstance(cons_value, np.float) and not isinstance(cons_value, np.int)):
raise TypeError('ConstraintReal must receive a float as cons_value '
'argument.')
self._cons_value = float(self._cons_value)
if(not isinstance(name, ConstraintName) or not name.is_real_constraint()):
raise TypeError('ConstraintReal first argument must be a '
'ConstraintName with a real type name '
'(name.is_real_constraint() must return True).')
class ConstraintName:
"""
Attributes:
SP: Designates a constraint on the sparsity/0-norm of a matrix.
SPCOL: Designates a sparsity/0-norm constraint on the columns of a
matrix.
SPLIN: Designates a sparsity/0-norm constraint on the lines of a
matrix.
SPLINCOL: Designates a constraint that imposes both SPLIN and SPCOL
constraints.
SP_POS: Designates a constraint that imposes a SP constraints and
besides erase the negative coefficients (it doesn't apply to complex
matrices).
NORMCOL: Designates a 2-norm constraint on the columns of a matrix.
NORMLIN: Designates a 2-norm constraint on the lines of a matrix.
CONST: Designates a constraint imposing to a matrix to be constant.
"""
SP = 0 # Int Constraint
SPCOL = 1 # Int Constraint
SPLIN=2 # Int Constraint
NORMCOL = 3 # Real Constraint
SPLINCOL = 4 # Int Constraint
CONST = 5 # Mat Constraint
SP_POS = 6 # Int Constraint
#BLKDIAG = 7 # ?? Constraint #TODO
SUPP = 8 # Mat Constraint
NORMLIN = 9 # Real Constraint
def __init__(self, name):
if(not isinstance(name, np.int) or name < ConstraintName.SP or name > ConstraintName.NORMLIN):
raise ValueError("name must be an integer among ConstraintName.SP,"
"ConstraintName.SPCOL, ConstraintName.NORMCOL,"
"ConstraintName.SPLINCOL, ConstraintName.CONST,"
"ConstraintName.SP_POS," # ConstraintName.BLKDIAG,
"ConstraintName.SUPP, ConstraintName.NORMLIN")
self.name = name
def is_int_constraint(self):
return self.name in [ ConstraintName.SP, ConstraintName.SPCOL,
ConstraintName.SPLIN, ConstraintName.SPLINCOL,
ConstraintName.SP_POS ]
def is_real_constraint(self):
return self.name in [ ConstraintName.NORMCOL, ConstraintName.NORMLIN ]
def is_mat_constraint(self):
return self.name in [ConstraintName.SUPP, ConstraintName.CONST ]
# -*- coding: utf-8 -*-
from pyfaust import *
from pyfaust.constraints import *
class ParamsFact(object):
def __init__(self, num_facts, is_update_way_R2L, init_lambda,
constraints, step_size, constant_step_size=False, is_verbose=False,
):
self.num_facts = num_facts
self.is_update_way_R2L = is_update_way_R2L
self.init_lambda = init_lambda
self.step_size = step_size
self.constraints = constraints
self.is_verbose = is_verbose
self.constant_step_size = constant_step_size
class ParamsHierarchicalFact(ParamsFact):
def __init__(self, num_facts, is_update_way_R2L, init_lambda,
fact_constraints, res_constraints, data_num_rows,
data_num_cols, stop_crits,
step_size=10.0**-16, constant_step_size=False,
is_verbose=False,
is_fact_side_left = False):
constraints = fact_constraints + res_constraints
super(ParamsHierarchicalFact, self).__init__(num_facts,
is_update_way_R2L,
init_lambda,
constraints, step_size,
constant_step_size,
is_verbose)
self.data_num_rows = data_num_rows
self.data_num_cols = data_num_cols
self.stop_crits = stop_crits
self.is_fact_side_left = is_fact_side_left
#TODO: verify number of constraints is consistent with num_facts in
if((not isinstance(stop_crits, list) and not isinstance(stop_crits,
tuple)) or
len(stop_crits) != 2 or
not isinstance(stop_crits[0],StoppingCriterion) or not
isinstance(stop_crits[1],StoppingCriterion)):
raise TypeError('ParamsHierarchicalFact stop_crits argument must be a list/tuple of two '
'StoppingCriterion objects')
if((not isinstance(constraints, list) and not isinstance(constraints,
tuple)) or
np.array([not isinstance(constraints[i],ConstraintGeneric) for i in
range(0,len(constraints))]).any()):
raise TypeError('constraints argument must be a list/tuple of '
'ConstraintGeneric (or subclasses) objects')
class ParamsPalm4MSA(ParamsFact):
def __init__(self, num_facts, is_update_way_R2L, init_lambda,
constraints, stop_crit, init_facts=None, step_size=10.0**-16,
constant_step_size=False,
is_verbose=False):
super(ParamsPalm4MSA, self).__init__(num_facts, is_update_way_R2L,
init_lambda,
constraints, step_size,
constant_step_size,
is_verbose)
if(init_facts != None and (not isinstance(init_facts, list) and not isinstance(init_facts,
tuple) or
len(init_facts) != num_facts)):
raise ValueError('ParamsPalm4MSA init_facts argument must be a '
'list/tuple of '+str(num_facts)+" (num_facts) arguments.")
else:
self.init_facts = init_facts
if(not isinstance(stop_crit, StoppingCriterion)):
raise TypeError('ParamsPalm4MSA stop_crit argument must be a StoppingCriterion '
'object')
self.stop_crit = stop_crit
#TODO: verify number of constraints is consistent with num_facts
class StoppingCriterion(object):
def __init__(self, is_criterion_error = False , error_treshold = 0.3,
num_its = 500,
max_num_its = 1000):
self.is_criterion_error = is_criterion_error
self.error_treshold = error_treshold
self.num_its = num_its
self.max_num_its = max_num_its
#TODO: check_validity() like C++ code does
if(is_criterion_error and num_its != 500):
raise ValueError("It's forbidden to set a number of iterations as stopping"
" criterion when is_criterion_error == True.")
elif(not is_criterion_error and (max_num_its != 1000 or error_treshold
!= 0.3)):
raise ValueError("When is_criterion_error == True it's forbidden to use"
" other arguments than num_its argument to define "
"the stopping criterion.")
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment