📄 decisiontable.cpp
字号:
// Get integral contents.
int value = GetEntry(object_no, attribute_no, masked);
// If we don't want to or cannot use the dictionary, return the integral contents themselves.
if (!HasDictionary() || !use_dictionary) {
if (value == Undefined::Integer())
return Undefined::String();
dummy = String::Format(value);
return dummy;
}
int unmasked;
if (masked)
unmasked = GetUnmaskedAttribute(attribute_no);
else
unmasked = attribute_no;
return GetDictionary()->GetEntry(unmasked, value);
}
//-------------------------------------------------------------------
// Method........: GetEntry
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Returns a requested table entry, mapped (both ways)
// through the associated dictionary.
//
// Ineffiecient (but occasionally convenient) way of
// getting an entry, allowing e.g. constructs like:
//
// if (table->GetEntry(4, "color") == "blue") {
// ...
// }
//
// Comments......: Could be made faster by eliminating the attribute
// index search by introducing an index cache.
// Revisions.....:
//===================================================================
const String &
DecisionTable::GetEntry(int object_no, const String &attribute_name, bool masked) const {
// Is a dictionary present?
if (dictionary_ == NULL)
return Undefined::String();
bool case_sensitive = true;
// Get the specified attribute. If names are non-unique, return the first match found.
int attribute_no = GetAttributeIndex(attribute_name, case_sensitive, masked);
// Was a matching attribute not found?
if (attribute_no == Undefined::Integer())
return Undefined::String();
// Get the integral table entry.
int entry = GetEntry(object_no, attribute_no, masked);
int unmasked;
if (masked)
unmasked = GetUnmaskedAttribute(attribute_no);
else
unmasked = attribute_no;
// Return the entry, mapped through the dictionary.
return dictionary_->GetEntry(unmasked, entry);
}
//-------------------------------------------------------------------
// Method........: SetEntry
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Sets a specified table entry, mapped through the
// associated dictionary.
//
// Inefficient (but occasionally convenient) way of
// setting an entry, allowing e.g. constructs like:
//
// table->SetEntry(4, "color", "blue");
//
// Comments......: Could be made faster by eliminating the attribute
// index search by introducing an index cache.
// Revisions.....:
//===================================================================
bool
DecisionTable::SetEntry(int object_no, const String &attribute_name, const String &value, bool masked) {
// Is a dictionary present?
if (dictionary_ == NULL)
return false;
bool case_sensitive = true;
// Get the specified attribute. If names are non-unique, return the first match found.
int attribute_no = GetAttributeIndex(attribute_name, case_sensitive, masked);
// Was a matching attribute not found?
if (attribute_no == Undefined::Integer())
return false;
// Is the entry deliberately set as undefined/missing?
if (value == Undefined::String())
return SetEntry(object_no, attribute_no, Undefined::Integer(), masked);
int unmasked;
if (masked)
unmasked = GetUnmaskedAttribute(attribute_no);
else
unmasked = attribute_no;
// Suggest an integral entry for the given textual value.
int entry = dictionary_->SuggestEntry(unmasked, value);
// Could a suggestion be made?
if (entry == Undefined::Integer())
return false;
// Set dictionary entry.
if (!dictionary_->SetEntry(unmasked, entry, value))
return false;
// Set integral table entry.
if (!SetEntry(object_no, attribute_no, entry, masked))
return false;
return true;
}
//-------------------------------------------------------------------
// Method........: GetEntries
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Returns (in-place) a vector representation of a
// table column. If specified, leaves out missing
// values.
// Comments......:
// Revisions.....:
//===================================================================
bool
DecisionTable::GetEntries(Vector(int) &entries, int attribute_no, bool masked, bool missing) const {
// Is the index in range?
if ((attribute_no < 0) || (attribute_no >= GetNoAttributes(masked)))
return false;
int i, no_objects = GetNoObjects(masked);
entries.erase(entries.begin(), entries.end());
entries.reserve(no_objects);
// Extract values.
for (i = 0; i < no_objects; i++) {
if (!missing && IsMissing(i, attribute_no, masked))
continue;
entries.push_back(GetEntry(i, attribute_no, masked));
}
return true;
}
//-------------------------------------------------------------------
// Method........: GetEntries
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Returns (in-place) vectors representation two table
// columns. If specified, leaves out values for objects
// that have a missing value for one of the columns
// specified.
// Comments......:
// Revisions.....:
//===================================================================
bool
DecisionTable::GetEntries(Vector(int) &entries1, Vector(int) &entries2, int attribute_no1, int attribute_no2, bool masked, bool missing) const {
// Is the index in range?
if ((attribute_no1 < 0) || (attribute_no1 >= GetNoAttributes(masked)))
return false;
if ((attribute_no2 < 0) || (attribute_no2 >= GetNoAttributes(masked)))
return false;
int i, no_objects = GetNoObjects(masked);
entries1.erase(entries1.begin(), entries1.end());
entries2.erase(entries2.begin(), entries2.end());
entries1.reserve(no_objects);
entries2.reserve(no_objects);
// Extract values.
for (i = 0; i < no_objects; i++) {
if (!missing && (IsMissing(i, attribute_no1, masked) || IsMissing(i, attribute_no2, masked)))
continue;
entries1.push_back(GetEntry(i, attribute_no1, masked));
entries2.push_back(GetEntry(i, attribute_no2, masked));
}
return true;
}
//-------------------------------------------------------------------
// Method........: GetEntries
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Returns (in-place) a vector representation of a
// table column. If specified, leaves out missing
// values and/or converts the value via a scaling
// exponent.
// Comments......:
// Revisions.....:
//===================================================================
bool
DecisionTable::GetEntries(Vector(float) &entries, int attribute_no, bool masked, bool missing, bool use_dictionary) const {
// Is the index in range?
if ((attribute_no < 0) || (attribute_no >= GetNoAttributes(masked)))
return false;
int i, no_objects = GetNoObjects(masked);
entries.erase(entries.begin(), entries.end());
entries.reserve(no_objects);
// Extract values.
for (i = 0; i < no_objects; i++) {
if (!missing && IsMissing(i, attribute_no, masked))
continue;
entries.push_back(GetEntry(i, attribute_no, masked));
}
// We're done if the specified attribute is not a float attribute, or conversion is not wanted.
if (!IsFloat(attribute_no, masked) || !use_dictionary)
return true;
return StaticRescaleEntries(entries, *this, attribute_no, masked);
}
//-------------------------------------------------------------------
// Method........: GetEntries
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Returns (in-place) vectors representation two table
// columns. If specified, leaves out values for objects
// that have a missing value for one of the columns
// specified. Value can be converted via scaling
// exponents.
// Comments......:
// Revisions.....:
//===================================================================
bool
DecisionTable::GetEntries(Vector(float) &entries1, Vector(float) &entries2, int attribute_no1, int attribute_no2, bool masked, bool missing, bool use_dictionary) const {
// Is the index in range?
if ((attribute_no1 < 0) || (attribute_no1 >= GetNoAttributes(masked)))
return false;
if ((attribute_no2 < 0) || (attribute_no2 >= GetNoAttributes(masked)))
return false;
int i, no_objects = GetNoObjects(masked);
entries1.erase(entries1.begin(), entries1.end());
entries2.erase(entries2.begin(), entries2.end());
entries1.reserve(no_objects);
entries2.reserve(no_objects);
// Extract values.
for (i = 0; i < no_objects; i++) {
if (!missing && (IsMissing(i, attribute_no1, masked) || IsMissing(i, attribute_no2, masked)))
continue;
entries1.push_back(GetEntry(i, attribute_no1, masked));
entries2.push_back(GetEntry(i, attribute_no2, masked));
}
// Rescale entries via dictionary?
if (IsFloat(attribute_no1, masked) && use_dictionary) {
if (!StaticRescaleEntries(entries1, *this, attribute_no1, masked))
return false;
}
if (IsFloat(attribute_no2, masked) && use_dictionary) {
if (!StaticRescaleEntries(entries2, *this, attribute_no2, masked))
return false;
}
return true;
}
//-------------------------------------------------------------------
// Method........: GetGeneralizedDecisions
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Returns (in-place) the generalized decision value
// for each object.
//
// Comments......: Slightly suboptimal, but code reuse is given a
// higher priority than a marginal speed gain.
//
// For some unknown reason, the current compiler
// complains (deep down in STL) if I use a reference
// instead of a pointer for the vector of generalized
// decisions... Hmmf.
// Revisions.....:
//===================================================================
bool
DecisionTable::GetGeneralizedDecisions(GeneralizedDecision::Handles &decisions, const Discerner &discerner, bool masked) const {
bool all = false;
int cardinality = 0;
int names = Undefined::Integer();
IndiscernibilityGraph graph;
return graph.Create(*this, masked, discerner, all, cardinality, names, &decisions);
}
//-------------------------------------------------------------------
// Row/column administration.
//===================================================================
//-------------------------------------------------------------------
// Method........: AppendObject
// Author........: Aleksander 豩rn
// Date..........:
// Description...:
// Comments......: Default implementation.
//
// Ignores the masking and appends to the very end
// of the table (the end is the end, regardless of
// the masking). The masking argument is for
// interface completeness/uniformity reasons.
// Revisions.....:
//===================================================================
bool
DecisionTable::AppendObject(bool /*masked*/) {
return InsertObject(GetNoObjects(false), false);
}
//-------------------------------------------------------------------
// Method........: SwapObjects
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Swaps objects i and j in the table. Swaps entries
// for all attributes (disabled or not) to avoid creating
// inconsistencies in the table.
// Comments......: Swapping of associated object masks not implemented.
// Revisions.....:
//===================================================================
bool
DecisionTable::SwapObjects(int i, int j, bool masked) {
if (i == j)
return true;
int no_attributes = GetNoAttributes(false);
int unmasked_i;
int unmasked_j;
if (masked) {
unmasked_i = GetUnmaskedObject(i);
unmasked_j = GetUnmaskedObject(j);
}
else {
unmasked_i = i;
unmasked_j = j;
}
int k;
// Swap table entries.
for (k = 0; k < no_attributes; k++) {
int tmp = GetEntry(unmasked_i, k, false);
if (!SetEntry(unmasked_i, k, GetEntry(unmasked_j, k, false), false))
return false;
if (!SetEntry(unmasked_j, k, tmp, false))
return false;
}
// Swap object masks.
// ...
return true;
}
//-------------------------------------------------------------------
// Method........: SortObjects
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Sorts the objects according to the integral value of
// the specified attribute.
// Comments......: Quick and dirty solution, very ineffiecient.
// Revisions.....:
//===================================================================
bool
DecisionTable::SortObjects(int attribute_no, bool masked) {
Message message;
int no_attributes = GetNoAttributes(masked);
int no_objects = GetNoObjects(masked);
// Check index validity.
if ((attribute_no < 0) || (attribute_no >= no_attributes)) {
Message::Error("Attribute index out of range.");
return false;
}
message.Notify("Sorting objects...");
int i, j;
// Do a dumb bubble sort.
for (i = 0; i < no_objects; i++) {
for (j = i + 1; j < no_objects; j++) {
if (GetEntry(i, attribute_no, masked) > GetEntry(j, attribute_no, masked)) {
if (!SwapObjects(i, j, masked))
return false;
}
}
}
return true;
}
//-------------------------------------------------------------------
// Method........: SwapAttributes
// Author........: Aleksander 豩rn
// Date..........:
// Description...: Swaps attributes i and j in the table, and in the
// dictionary if this is present. Swaps entries
// for all objects (disabled or not) to avoid creating
// inconsistencies in the table.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -