Handle transposed matrices for Go.

This commit is contained in:
Ryan Curtin
2022-12-01 11:52:29 -05:00
parent 774726c8c8
commit 8b5db73eac
6 changed files with 73 additions and 7 deletions
+2 -2
View File
@@ -91,7 +91,7 @@ func (m *mlpackArma) allocArmaPtrMatWithInfo(p *params,
}
// Passes a Gonum matrix to C by using the underlying data from the Gonum matrix.
func gonumToArmaMat(p *params, identifier string, m *mat.Dense) {
func gonumToArmaMat(p *params, identifier string, m *mat.Dense, trans bool) {
// Get the number of elements in the Armadillo column.
r, c := m.Dims()
blas64General := m.RawMatrix()
@@ -100,7 +100,7 @@ func gonumToArmaMat(p *params, identifier string, m *mat.Dense) {
// Pass pointer of the underlying matrix to mlpack.
ptr := unsafe.Pointer(&data[0])
C.mlpackToArmaMat(p.mem, C.CString(identifier), (*C.double)(ptr),
C.size_t(c), C.size_t(r))
C.size_t(c), C.size_t(r), C.bool(trans))
}
// Passes a Gonum matrix to C by using the underlying data from the Gonum matrix.
@@ -28,13 +28,18 @@ void mlpackToArmaMat(void* params,
const char* identifier,
double* mat,
const size_t row,
const size_t col)
const size_t col,
bool transpose)
{
util::Params& p = *((util::Params*) params);
// Advanced constructor.
arma::mat m(mat, row, col, false, false);
// Transpose if necessary.
if (transpose)
arma::inplace_trans(m);
// Set input parameter with corresponding matrix in IO.
SetParam(p, identifier, m);
}
@@ -28,7 +28,8 @@ void mlpackToArmaMat(void* params,
const char* identifier,
double* mat,
const size_t row,
const size_t col);
const size_t col,
bool transpose);
/**
* Pass Gonum Dense pointer and wrap an Armadillo mat around it.
@@ -149,12 +149,26 @@ void PrintInputProcessing(
*
* // Detect if the parameter was passed; set if so.
* if param.Name != nil {
* gonumToArma<type>(params, "paramName", param.Name)
* gonumToArma<type>(params, "paramName", param.Name, false)
* setPassed(params, "paramName")
* }
*
* where the boolean parameter indicates if the matrix needs to be transposed,
* and is only included for arma::mat type parameters.
*/
std::cout << prefix << "// Detect if the parameter was passed; set if so."
<< std::endl;
// Add extra transpose option, but only for arma::mat types.
std::string transStrExtra = "";
if (d.cppType == "arma::mat")
{
if (d.noTranspose)
transStrExtra = ", true";
else
transStrExtra = ", false";
}
if (!d.required)
{
std::cout << prefix << "if param." << goParamName
@@ -163,7 +177,7 @@ void PrintInputProcessing(
// Print function call to set the given parameter into the io.
std::cout << prefix << prefix << "gonumToArma" << GetType<T>(d)
<< "(params, \"" << d.name << "\", param." << goParamName
<< ")" << std::endl;
<< transStrExtra << ")" << std::endl;
// Print function call to set the given parameter as passed.
std::cout << prefix << prefix << "setPassed(params, \"" << d.name << "\")"
@@ -176,7 +190,7 @@ void PrintInputProcessing(
// Print function call to set the given parameter into the io.
std::cout << prefix << "gonumToArma" << GetType<T>(d)
<< "(params, \"" << d.name << "\", " << goParamName
<< ")" << std::endl;
<< transStrExtra << ")" << std::endl;
// Print function call to set the given parameter as passed.
std::cout << prefix << "setPassed(params, \"" << d.name << "\")"
@@ -196,6 +196,31 @@ func TestGonumUMatrix(t *testing.T) {
}
}
}
func TestGonumTransMatrix(t *testing.T) {
t.Log("Test transposed matrix input.")
x := mat.NewDense(3, 5, []float64{
1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12, 13, 14, 15,
})
x2 := mat.NewDense(3, 5, []float64{
1, 2, 3, 4, 5,
6, 7, 8, 9, 10,
11, 12, 13, 14, 15,
})
param := mlpack.TestGoBindingOptions()
param.MatrixIn = x
param.TmatrixIn = x2
d := 4.0
i := 12
s := "hello"
// The binding simply needs to run successfully (without exception) to
// succeed.
mlpack.TestGoBinding(d, i, s, param)
}
func TestGonumTransposeRow(t *testing.T) {
t.Log("Test a column vector input parameter.")
x := mat.NewDense(1, 9, []float64{
@@ -41,6 +41,7 @@ PARAM_FLAG("flag1", "Input flag, must be specified.", "f");
PARAM_FLAG("flag2", "Input flag, must not be specified.", "F");
PARAM_MATRIX_IN("matrix_in", "Input matrix.", "m");
PARAM_UMATRIX_IN("umatrix_in", "Input unsigned matrix.", "u");
PARAM_TMATRIX_IN("tmatrix_in", "Input matrix (transposed).", "");
PARAM_COL_IN("col_in", "Input column.", "c");
PARAM_UCOL_IN("ucol_in", "Input unsigned column.", "");
PARAM_ROW_IN("row_in", "Input row.", "");
@@ -92,6 +93,26 @@ void BINDING_FUNCTION(util::Params& params, util::Timers& /* timer */)
params.Get<double>("double_out") = 5.0;
}
// If a transposed input matrix is given, it is expected to be the same as the
// (now required) input matrix.
if (params.Has("tmatrix_in"))
{
if (!params.Has("matrix_in"))
{
throw std::runtime_error("If tmatrix_in is specified, matrix_in must be "
"specified!");
}
arma::mat tmat = params.Get<arma::mat>("tmatrix_in");
arma::mat mat = params.Get<arma::mat>("matrix_in");
if (!arma::approx_equal(tmat.t(), mat, "reldiff", 0.001))
{
throw std::runtime_error("Transposed tmatrix_in and matrix_in are not "
"equal!");
}
}
// Input matrices should be at least 5 rows; the 5th row will be dropped and
// the 3rd row will be multiplied by two.
if (params.Has("matrix_in"))