Skip to content

Commit

Permalink
Fix issue where python passed rounded UnitAlgebras through parameters (
Browse files Browse the repository at this point in the history
…#1024)

* Fix issue where python passed rounded UnitAlgebras through parameters
Add functions for pretty-printing UnitAlgebra
  • Loading branch information
gvoskuilen authored Dec 19, 2023
1 parent 31abc7d commit 56ad96c
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 61 deletions.
38 changes: 31 additions & 7 deletions src/sst/core/model/python/pymodel_unitalgebra.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,18 @@ extern "C" {
static int
unitAlgebraInit(UnitAlgebraPy_t* self, PyObject* args, PyObject* UNUSED(kwds))
{
char* init_str = NULL;
// PyObject* obj;
UnitAlgebraPy_t* new_obj;
PyObject* str_obj;

if ( PyArg_ParseTuple(args, "s", &init_str) ) {
self->obj = init_str;
if ( PyArg_ParseTuple(args, "O!", &PyModel_UnitAlgebraType, &new_obj) ) {
self->obj = new_obj->obj;
return 0;
}
PyErr_Clear();
if ( PyArg_ParseTuple(args, "O!", &PyModel_UnitAlgebraType, &new_obj) ) {
self->obj = new_obj->obj;
if ( PyArg_ParseTuple(args, "O", &str_obj) ) {
PyObject* vstr = PyObject_CallMethod(str_obj, (char*)"__str__", nullptr);
self->obj = SST_ConvertToCppString(vstr);
Py_XDECREF(vstr);
return 0;
}
PyErr_SetString(
Expand All @@ -64,7 +65,7 @@ static PyObject*
unitAlgebraStr(PyObject* self)
{
UnitAlgebraPy_t* ua = (UnitAlgebraPy_t*)self;
return SST_ConvertToPythonString(ua->obj.toStringBestSI().c_str());
return SST_ConvertToPythonString(ua->obj.toString(0).c_str());
}

static PyObject*
Expand Down Expand Up @@ -397,13 +398,36 @@ unitAlgebraInvert(PyObject* self, PyObject* UNUSED(args))
return ret;
}

static PyObject*
unitAlgebraBestSI(PyObject* self, PyObject* args)
{
int precision = 6;
if ( !PyArg_ParseTuple(args, "|i", &precision) ) return nullptr;

UnitAlgebraPy_t* ua = (UnitAlgebraPy_t*)self;
return SST_ConvertToPythonString(ua->obj.toStringBestSI(precision).c_str());
}

static PyObject*
unitAlgebraPrecision(PyObject* self, PyObject* args)
{
int precision = 6;
if ( !PyArg_ParseTuple(args, "|i", &precision) ) return nullptr;

UnitAlgebraPy_t* ua = (UnitAlgebraPy_t*)self;
return SST_ConvertToPythonString(ua->obj.toString(precision).c_str());
}

static PyMethodDef unitAlgebraMethods[] = {
{ "getRoundedValue", unitAlgebraGetRoundedValue, METH_NOARGS,
"Rounds value of UnitAlgebra to nearest whole number and returns a long" },
{ "getFloatValue", unitAlgebraGetFloatValue, METH_NOARGS, "Returns value portion of UnitAlgebra as a float" },
{ "isValueZero", unitAlgebraIsValueZero, METH_NOARGS, "Returns True if value is zero, false otherwise" },
{ "hasUnits", unitAlgebraHasUnits, METH_VARARGS, "Checks to see if the UnitAlgebra has the specified units" },
{ "invert", unitAlgebraInvert, METH_NOARGS, "Inverts the UnitAlgebra value and units" },
{ "bestSI", unitAlgebraBestSI, METH_VARARGS, "Returns a string representation of the UnitAlgebra using SI units" },
{ "precision", unitAlgebraPrecision, METH_VARARGS,
"Returns a string representation of the UnitAlgebra with the requested precision" },
{ NULL, NULL, 0, NULL }
};

Expand Down
16 changes: 8 additions & 8 deletions src/sst/core/unitAlgebra.cc
Original file line number Diff line number Diff line change
Expand Up @@ -374,27 +374,27 @@ UnitAlgebra::UnitAlgebra(const std::string& val)
}

void
UnitAlgebra::print(ostream& stream)
UnitAlgebra::print(ostream& stream, int32_t precision)
{
stream << value.toString() << " " << unit.toString() << endl;
stream << value.toString(precision) << " " << unit.toString() << endl;
}

void
UnitAlgebra::printWithBestSI(std::ostream& stream)
UnitAlgebra::printWithBestSI(std::ostream& stream, int32_t precision)
{
stream << toStringBestSI() << endl;
stream << toStringBestSI(precision) << endl;
}

string
UnitAlgebra::toString() const
UnitAlgebra::toString(int32_t precision) const
{
stringstream s;
s << value.toString() << " " << unit.toString();
s << value.toString(precision) << " " << unit.toString();
return s.str();
}

string
UnitAlgebra::toStringBestSI() const
UnitAlgebra::toStringBestSI(int32_t precision) const
{
stringstream s;
sst_big_num temp;
Expand All @@ -411,7 +411,7 @@ UnitAlgebra::toStringBestSI() const
break;
}
}
s << (found ? temp.toString() : value.toString()) << " " << si << unit.toString();
s << (found ? temp.toString(precision) : value.toString(precision)) << " " << si << unit.toString();
return s.str();
}

Expand Down
18 changes: 12 additions & 6 deletions src/sst/core/unitAlgebra.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,18 +138,24 @@ class UnitAlgebra :
/** Copy constructor */
UnitAlgebra(const UnitAlgebra&) = default;

/** Print to an ostream the value */
void print(std::ostream& stream);
/** Print to an ostream the value
* \param precision Number of digits to print. Default is 6. <= 0 is full precision.
*/
void print(std::ostream& stream, int32_t precision = 6);
/** Print to an ostream the value
* Formats the number using SI-prefixes
* \param precision Number of digits to print. Default is 6. <= 0 is full precision.
*/
void printWithBestSI(std::ostream& stream);
/** Return a string representation of this value */
std::string toString() const;
void printWithBestSI(std::ostream& stream, int32_t precision = 6);
/** Return a string representation of this value
* \param precision Number of digits to print. Default is 6. <= 0 is full precision.
*/
std::string toString(int32_t precision = 6) const;
/** Return a string representation of this value
* Formats the number using SI-prefixes
* \param precision Number of digits to print. Default is 6. <= 0 is full precision.
*/
std::string toStringBestSI() const;
std::string toStringBestSI(int32_t precision = 6) const;

UnitAlgebra& operator=(const std::string& v);

Expand Down
8 changes: 8 additions & 0 deletions tests/refFiles/test_UnitAlgebra.out
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,12 @@ hasUnits():
'10 ns'.hasUnits("ns") = True
'10 ns'.hasUnits("s") = True
'10 ns'.hasUnits("Hz") = False

Initialization from numeric arguments:
From int = 2: 2
From float = 9.443: 9.443

Printing:
1073741823 B = 1.07374e+09 B = 1.074e+09 B = 1.07374 GB = 1.1 GB = 1.073741823 GB

Simulation is complete, simulated time: 0 s
92 changes: 52 additions & 40 deletions tests/test_UnitAlgebra.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,19 @@

#addition
ua3 = ua1 + ua2
print("%s + %s = %s"%(ua1, ua2, ua3))
print("%s + %s = %s"%(ua1.bestSI(), ua2.bestSI(), ua3.bestSI()))

#subtraction
ua3 = ua1 - ua2
print("%s - %s = %s"%(ua1, ua2, ua3))
print("%s - %s = %s"%(ua1.bestSI(), ua2.bestSI(), ua3.bestSI()))

#multiplication
ua3 = ua1 * ua2
print("%s * %s = %s"%(ua1, ua2, ua3))
print("%s * %s = %s"%(ua1.bestSI(), ua2.bestSI(), ua3.bestSI()))

#division
ua3 = ua1 / ua2
print("%s / %s = %s"%(ua1, ua2, ua3))

print("%s / %s = %s"%(ua1.bestSI(), ua2.bestSI(), ua3.bestSI()))

# in-place functions
print("")
Expand Down Expand Up @@ -65,8 +64,8 @@
ua3 += ua2
if id(ua3) == ua3_id_before:
print("ERROR: += operator returned the same object")
print(ua3)
print(ua4)
print(ua3.bestSI())
print(ua4.bestSI())

print("Subtraction:")

Expand All @@ -76,8 +75,8 @@
ua3 -= ua2
if id(ua3) == ua3_id_before:
print("ERROR: -= operator returned the same object")
print(ua3)
print(ua4)
print(ua3.bestSI())
print(ua4.bestSI())

print("Multiplication:")

Expand All @@ -87,8 +86,8 @@
ua3 *= ua2
if id(ua3) == ua3_id_before:
print("ERROR: *= operator returned the same object")
print(ua3)
print(ua4)
print(ua3.bestSI())
print(ua4.bestSI())

print("Division:")

Expand All @@ -98,8 +97,8 @@
ua3 /= ua2
if id(ua3) == ua3_id_before:
print("ERROR: \= operator returned the same object")
print(ua3)
print(ua4)
print(ua3.bestSI())
print(ua4.bestSI())

# Check to see if exceptions are triggered as they should be if the
# operands aren't correct
Expand Down Expand Up @@ -136,19 +135,19 @@
print("Comparison functions:")
ua3 = UnitAlgebra("15ns")

print("%s > %s = %r"%(ua1,ua2,ua1 > ua2))
print("%s >= %s = %r"%(ua1,ua2,ua1 >= ua2))
print("%s < %s = %r"%(ua1,ua2,ua1 < ua2))
print("%s <= %s = %r"%(ua1,ua2,ua1 <= ua2))
print("%s == %s = %r"%(ua1,ua2,ua1 == ua2))
print("%s != %s = %r"%(ua1,ua2,ua1 != ua2))
print("%s > %s = %r"%(ua1.bestSI(),ua2.bestSI(),ua1 > ua2))
print("%s >= %s = %r"%(ua1.bestSI(),ua2.bestSI(),ua1 >= ua2))
print("%s < %s = %r"%(ua1.bestSI(),ua2.bestSI(),ua1 < ua2))
print("%s <= %s = %r"%(ua1.bestSI(),ua2.bestSI(),ua1 <= ua2))
print("%s == %s = %r"%(ua1.bestSI(),ua2.bestSI(),ua1 == ua2))
print("%s != %s = %r"%(ua1.bestSI(),ua2.bestSI(),ua1 != ua2))
print("")
print("%s > %s = %r"%(ua1,ua3,ua1 > ua3))
print("%s >= %s = %r"%(ua1,ua3,ua1 >= ua3))
print("%s < %s = %r"%(ua1,ua3,ua1 < ua3))
print("%s <= %s = %r"%(ua1,ua3,ua1 <= ua3))
print("%s == %s = %r"%(ua1,ua3,ua1 == ua3))
print("%s != %s = %r"%(ua1,ua3,ua1 != ua3))
print("%s > %s = %r"%(ua1.bestSI(),ua3.bestSI(),ua1 > ua3))
print("%s >= %s = %r"%(ua1.bestSI(),ua3.bestSI(),ua1 >= ua3))
print("%s < %s = %r"%(ua1.bestSI(),ua3.bestSI(),ua1 < ua3))
print("%s <= %s = %r"%(ua1.bestSI(),ua3.bestSI(),ua1 <= ua3))
print("%s == %s = %r"%(ua1.bestSI(),ua3.bestSI(),ua1 == ua3))
print("%s != %s = %r"%(ua1.bestSI(),ua3.bestSI(),ua1 != ua3))


# Check to make sure we get exceptions for invalid arguments. Since
Expand Down Expand Up @@ -238,47 +237,60 @@
print("")
print("Conversion to int:")
ua3 = UnitAlgebra("1GHz")
print("'%s' to long = %d"%(ua3,int(ua3)))
print("'%s'.getRoundedValue() = %d"%(ua3, ua3.getRoundedValue()))
print("'%s' to long = %d"%(ua3.bestSI(),int(ua3)))
print("'%s'.getRoundedValue() = %d"%(ua3.bestSI(), ua3.getRoundedValue()))

print("")
print("Conversion to float:")
ua3 = UnitAlgebra("1.77s")
print("'%s' to float = %f"%(ua3,float(ua3)))
print("'%s'.getFloatValue() = %f"%(ua3, ua3.getFloatValue()))
print("'%s' to float = %f"%(ua3.bestSI(),float(ua3)))
print("'%s'.getFloatValue() = %f"%(ua3.bestSI(), ua3.getFloatValue()))

print("")
print("Conversion to float:")
ua3 = UnitAlgebra("1.77s")
print("'%s' to float = %f"%(ua3,float(ua3)))
print("'%s'.getFloatValue() = %f"%(ua3, ua3.getFloatValue()))
print("'%s' to float = %f"%(ua3.bestSI(),float(ua3)))
print("'%s'.getFloatValue() = %f"%(ua3.bestSI(), ua3.getFloatValue()))

print("")
print("Conversion to bool:")
ua3 = UnitAlgebra("0ns")
print("bool(%s) = %r"%(ua3,bool(ua3)))
print("bool(%s) = %r"%(ua3.bestSI(),bool(ua3)))
ua3 = UnitAlgebra("5ns")
print("bool(%s) = %r"%(ua3,bool(ua3)))
print("bool(%s) = %r"%(ua3.bestSI(),bool(ua3)))

# Test the remaining functions that haven't been tested elsewhere
print("")
print("isValueZero():")
ua3 = UnitAlgebra("0ns")
print("'%s'.isValueZero() = %r"%(ua3,ua3.isValueZero()))
print("'%s'.isValueZero() = %r"%(ua3.bestSI(),ua3.isValueZero()))
ua3 = UnitAlgebra("5ns")
print("'%s'.isValueZero() = %r"%(ua3,ua3.isValueZero()))
print("'%s'.isValueZero() = %r"%(ua3.bestSI(),ua3.isValueZero()))

print("")
print("Negate:")
print("-%s = %s"%(ua1,-ua1))
print("-%s = %s"%(ua1.bestSI(),(-ua1).bestSI()))

print("")
print("Invert:")
print("'%s'.invert() = %s"%(ua1,ua1.invert()))
print("'%s'.invert() = %s"%(ua1.bestSI(),ua1.invert().bestSI()))

print("")
print("hasUnits():")
print("'%s'.hasUnits(\"ns\") = %r"%(ua1,ua1.hasUnits("ns")))
print("'%s'.hasUnits(\"s\") = %r"%(ua1,ua1.hasUnits("s")))
print("'%s'.hasUnits(\"Hz\") = %r"%(ua1,ua1.hasUnits("Hz")))
print("'%s'.hasUnits(\"ns\") = %r"%(ua1.bestSI(),ua1.hasUnits("ns")))
print("'%s'.hasUnits(\"s\") = %r"%(ua1.bestSI(),ua1.hasUnits("s")))
print("'%s'.hasUnits(\"Hz\") = %r"%(ua1.bestSI(),ua1.hasUnits("Hz")))

# Check creation from int and float types
print("")
print("Initialization from numeric arguments:")
ua3 = UnitAlgebra(2)
print("From int = 2: %s"%(ua3))
ua3 = UnitAlgebra(9.443)
print("From float = 9.443: %s"%(ua3))

print("")
print("Printing:")
ua3 = UnitAlgebra("1024MiB")
ua3 = ua3 - UnitAlgebra("1B")
print("%s = %s = %s = %s = %s = %s\n"%(ua3, ua3.precision(), ua3.precision(4), ua3.bestSI(), ua3.bestSI(2), ua3.bestSI(0)))

0 comments on commit 56ad96c

Please sign in to comment.