You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmData/nmDataSensitive.cpp

435 lines
12 KiB
C++

#include "nmDataSensitive.h"
#include <cmath>
#include <limits>
nmDataSensitive::VariableSampling::VariableSampling()
: m_varGroup("")
, m_varName("")
, m_enabled(false)
, m_mode(MODE_AUTOMATIC)
, m_log(false)
, m_number(0)
{
m_modelValue = nmDataAttribute("Model value", "", "");
m_minValue = nmDataAttribute("Minimum", "", "");
m_maxValue = nmDataAttribute("Maximum", "", "");
m_values.clear();
}
// 序列化 VariableSampling 为 RapidJSON Value
rapidjson::Value nmDataSensitive::VariableSampling::ToJsonValue(
rapidjson::Document::AllocatorType& allocator) const
{
rapidjson::Value obj(rapidjson::kObjectType);
// 字符串字段
obj.AddMember("VarGroup",
rapidjson::Value(m_varGroup.toStdString().c_str(), allocator).Move(),
allocator);
obj.AddMember("VarName",
rapidjson::Value(m_varName.toStdString().c_str(), allocator).Move(),
allocator);
// 简单类型
obj.AddMember("Enabled", m_enabled, allocator);
obj.AddMember("Mode", static_cast<int>(m_mode), allocator);
obj.AddMember("Log", m_log, allocator);
obj.AddMember("Number", m_number, allocator);
// nmDataAttribute 成员
obj.AddMember("ModelValue", m_modelValue.ToJsonValue(allocator), allocator);
obj.AddMember("Minimum", m_minValue.ToJsonValue(allocator), allocator);
obj.AddMember("Maximum", m_maxValue.ToJsonValue(allocator), allocator);
// values 数组
rapidjson::Value arr(rapidjson::kArrayType);
for (int i = 0; i < m_values.size(); ++i) {
arr.PushBack(m_values.at(i), allocator);
}
obj.AddMember("Values", arr, allocator);
return obj;
}
// 从 RapidJSON Value 反序列化到 VariableSampling
void nmDataSensitive::VariableSampling::FromJsonValue(const rapidjson::Value& jsonValue)
{
if (jsonValue.HasMember("VarGroup") && jsonValue["VarGroup"].IsString()) {
m_varGroup = QString::fromUtf8(jsonValue["VarGroup"].GetString());
}
if (jsonValue.HasMember("VarName") && jsonValue["VarName"].IsString()) {
m_varName = QString::fromUtf8(jsonValue["VarName"].GetString());
}
if (jsonValue.HasMember("Enabled") && jsonValue["Enabled"].IsBool()) {
m_enabled = jsonValue["Enabled"].GetBool();
}
if (jsonValue.HasMember("Mode") && jsonValue["Mode"].IsInt()) {
int m = jsonValue["Mode"].GetInt();
m_mode = (m == MODE_MANUAL) ? MODE_MANUAL : MODE_AUTOMATIC;
}
if (jsonValue.HasMember("Log") && jsonValue["Log"].IsBool()) {
m_log = jsonValue["Log"].GetBool();
}
if (jsonValue.HasMember("Number") && jsonValue["Number"].IsInt()) {
m_number = jsonValue["Number"].GetInt();
}
if (jsonValue.HasMember("ModelValue") && jsonValue["ModelValue"].IsObject()) {
m_modelValue.FromJsonValue(jsonValue["ModelValue"]);
}
if (jsonValue.HasMember("Minimum") && jsonValue["Minimum"].IsObject()) {
m_minValue.FromJsonValue(jsonValue["Minimum"]);
}
if (jsonValue.HasMember("Maximum") && jsonValue["Maximum"].IsObject()) {
m_maxValue.FromJsonValue(jsonValue["Maximum"]);
}
m_values.clear();
if (jsonValue.HasMember("Values") && jsonValue["Values"].IsArray()) {
const rapidjson::Value& arr = jsonValue["Values"];
for (rapidjson::SizeType i = 0; i < arr.Size(); ++i) {
if (arr[i].IsNumber()) {
m_values.append(arr[i].GetDouble());
}
}
}
}
// varGroup
QString nmDataSensitive::VariableSampling::getVarGroup() const
{
return m_varGroup;
}
void nmDataSensitive::VariableSampling::setVarGroup(const QString& group)
{
m_varGroup = group;
}
// varName
QString nmDataSensitive::VariableSampling::getVarName() const
{
return m_varName;
}
void nmDataSensitive::VariableSampling::setVarName(const QString& name)
{
m_varName = name;
}
// enabled
bool nmDataSensitive::VariableSampling::getEnabled() const
{
return m_enabled;
}
void nmDataSensitive::VariableSampling::setEnabled(bool e)
{
m_enabled = e;
}
// mode
nmDataSensitive::VariableSampling::Mode
nmDataSensitive::VariableSampling::getMode() const
{
return m_mode;
}
void nmDataSensitive::VariableSampling::setMode(Mode m)
{
m_mode = m;
}
// log
bool nmDataSensitive::VariableSampling::getLog() const
{
return m_log;
}
void nmDataSensitive::VariableSampling::setLog(bool l)
{
m_log = l;
}
// number
int nmDataSensitive::VariableSampling::getNumber() const
{
return m_number;
}
void nmDataSensitive::VariableSampling::setNumber(int n)
{
m_number = n;
}
// modelValue
nmDataAttribute& nmDataSensitive::VariableSampling::getModelValue()
{
return m_modelValue;
}
void nmDataSensitive::VariableSampling::setModelValue(const nmDataAttribute& attr)
{
m_modelValue = attr;
}
// minValue
nmDataAttribute& nmDataSensitive::VariableSampling::getMinValue()
{
return m_minValue;
}
void nmDataSensitive::VariableSampling::setMinValue(const nmDataAttribute& attr)
{
m_minValue = attr;
}
// maxValue
nmDataAttribute& nmDataSensitive::VariableSampling::getMaxValue()
{
return m_maxValue;
}
void nmDataSensitive::VariableSampling::setMaxValue(const nmDataAttribute& attr)
{
m_maxValue = attr;
}
// values
QVector<double>& nmDataSensitive::VariableSampling::getValues()
{
return m_values;
}
void nmDataSensitive::VariableSampling::setValues(const QVector<double>& vals)
{
m_values = vals;
}
QVector<double> nmDataSensitive::VariableSampling::samplingValues() const
{
// 表格显示精度不参与采样,包含零或负数的对数范围按线性处理。
if (m_mode == MODE_MANUAL) return m_values;
QVector<double> values;
if (m_number <= 0) return values;
const double minimum = m_minValue.getValue().toDouble();
const double maximum = m_maxValue.getValue().toDouble();
const bool logarithmic = m_log && minimum > 0.0 && maximum > 0.0;
for (int i = 0; i < m_number; ++i) {
const double t = m_number == 1 ? 0.0 : double(i) / (m_number - 1);
double value = logarithmic
? std::exp((1.0 - t) * std::log(minimum) + t * std::log(maximum))
: (1.0 - t) * minimum + t * maximum;
if (m_number == 1) value = m_modelValue.getValue().toDouble();
else if (i == 0) value = minimum;
else if (i == m_number - 1) value = maximum;
values.append(value);
}
return values;
}
nmDataSensitive::nmDataSensitive()
: m_calcType(CALC_DETERMINISTIC)
, m_totalModelCount(0)
, m_usesBaseUnits(false)
, m_variables()
{
}
// 拷贝构造
nmDataSensitive::nmDataSensitive(const nmDataSensitive& other)
{
*this = other;
}
// 赋值运算符
nmDataSensitive& nmDataSensitive::operator=(const nmDataSensitive& other)
{
if (this != &other) {
m_calcType = other.m_calcType;
m_totalModelCount = other.m_totalModelCount;
m_usesBaseUnits = other.m_usesBaseUnits;
m_variables = other.m_variables;
}
return *this;
}
nmDataSensitive::~nmDataSensitive()
{
}
// 序列化 nmDataSensitive 为 RapidJSON Value
rapidjson::Value nmDataSensitive::ToJsonValue(
rapidjson::Document::AllocatorType& allocator) const
{
rapidjson::Value root(rapidjson::kObjectType);
// 旧配置中的采样值是显示单位,新配置统一保存业务基准单位。
root.AddMember("UsesBaseUnits", m_usesBaseUnits, allocator);
// 顶部 Calculation type
root.AddMember("CalculationType",
static_cast<int>(m_calcType),
allocator);
// 总模型数
root.AddMember("TotalModelCount",
m_totalModelCount,
allocator);
// 变量数组
rapidjson::Value arr(rapidjson::kArrayType);
for (int i = 0; i < m_variables.size(); ++i) {
arr.PushBack(m_variables.at(i).ToJsonValue(allocator), allocator);
}
root.AddMember("Variables", arr, allocator);
return root;
}
// 从 RapidJSON Value 反序列化数据到 nmDataSensitive
void nmDataSensitive::FromJsonValue(const rapidjson::Value& jsonValue)
{
m_usesBaseUnits = jsonValue.HasMember("UsesBaseUnits") &&
jsonValue["UsesBaseUnits"].IsBool() && jsonValue["UsesBaseUnits"].GetBool();
if (jsonValue.HasMember("CalculationType") && jsonValue["CalculationType"].IsInt()) {
int t = jsonValue["CalculationType"].GetInt();
if (t == CALC_DETERMINISTIC_MULTIVARIATE)
m_calcType = CALC_DETERMINISTIC_MULTIVARIATE;
else
m_calcType = CALC_DETERMINISTIC;
}
if (jsonValue.HasMember("TotalModelCount") && jsonValue["TotalModelCount"].IsUint64()) {
m_totalModelCount = jsonValue["TotalModelCount"].GetUint64();
}
m_variables.clear();
if (jsonValue.HasMember("Variables") && jsonValue["Variables"].IsArray()) {
const rapidjson::Value& arr = jsonValue["Variables"];
for (rapidjson::SizeType i = 0; i < arr.Size(); ++i) {
if (!arr[i].IsObject())
continue;
VariableSampling vs;
vs.FromJsonValue(arr[i]);
m_variables.append(vs);
}
}
}
// === Calculation type ===
nmDataSensitive::CalculationType nmDataSensitive::getCalculationType() const
{
return m_calcType;
}
void nmDataSensitive::setCalculationType(CalculationType type)
{
m_calcType = type;
}
// === 总模型数 ===
quint64 nmDataSensitive::getTotalModelCount() const
{
return m_totalModelCount;
}
void nmDataSensitive::setTotalModelCount(quint64 count)
{
m_totalModelCount = count;
}
quint64 nmDataSensitive::calculateModelCount(bool* overflow) const
{
// 未选择变量时为零;两种确定性方法分别累计和、积。
if (overflow) *overflow = false;
quint64 count = 0;
bool selected = false;
for (int i = 0; i < m_variables.size(); ++i) {
const VariableSampling& variable = m_variables[i];
if (!variable.m_enabled) continue;
const quint64 number = variable.m_number > 0 ? variable.m_number : 0;
if (!number) return 0;
const quint64 limit = (std::numeric_limits<quint64>::max)();
if (m_calcType == CALC_DETERMINISTIC) {
if (count > limit - number) { if (overflow) *overflow = true; return 0; }
count += number;
} else {
if (!selected) count = 1;
if (count > limit / number) { if (overflow) *overflow = true; return 0; }
count *= number;
}
selected = true;
}
return count;
}
bool nmDataSensitive::getRunValues(quint64 runIndex, QVector<double>& values) const
{
// 按编号解码组合,不预先展开笛卡尔积,也不删除重复的基准组合。
bool overflow = false;
const quint64 count = calculateModelCount(&overflow);
if (overflow || runIndex >= count) return false;
values.clear();
for (int i = 0; i < m_variables.size(); ++i)
values.append(m_variables[i].m_modelValue.getValue().toDouble());
if (m_calcType == CALC_DETERMINISTIC) {
for (int i = 0; i < m_variables.size(); ++i) {
const VariableSampling& variable = m_variables[i];
if (!variable.m_enabled) continue;
const QVector<double> samples = variable.samplingValues();
if (samples.size() != variable.m_number) return false;
if (runIndex < quint64(samples.size())) {
values[i] = samples[int(runIndex)];
return true;
}
runIndex -= samples.size();
}
} else {
// Saphir 按第一个选中参数最快变化的顺序列出多变量组合。
for (int i = 0; i < m_variables.size(); ++i) {
const VariableSampling& variable = m_variables[i];
if (!variable.m_enabled) continue;
const QVector<double> samples = variable.samplingValues();
if (samples.isEmpty() || samples.size() != variable.m_number) return false;
values[i] = samples[int(runIndex % samples.size())];
runIndex /= samples.size();
}
return true;
}
return false;
}
bool nmDataSensitive::usesBaseUnits() const
{
return m_usesBaseUnits;
}
void nmDataSensitive::setUsesBaseUnits(bool enabled)
{
// 单位标记随配置保存,避免再次打开时重复转换。
m_usesBaseUnits = enabled;
}
// === 变量列表 ===
QList<nmDataSensitive::VariableSampling>& nmDataSensitive::getVariables()
{
return m_variables;
}
void nmDataSensitive::setVariables(const QList<VariableSampling>& vars)
{
m_variables = vars;
}
int nmDataSensitive::getVariableCount() const
{
return m_variables.size();
}
nmDataSensitive::VariableSampling& nmDataSensitive::getVariable(int index)
{
return m_variables[index];
}