20#include "absl/container/flat_hash_set.h"
21#include "absl/log/check.h"
22#include "absl/status/statusor.h"
23#include "absl/strings/escaping.h"
24#include "absl/strings/str_cat.h"
25#include "absl/strings/str_join.h"
26#include "absl/strings/string_view.h"
35absl::flat_hash_set<T> ToSet(
const std::vector<T>& vec) {
36 return absl::flat_hash_set<T>(vec.begin(), vec.end());
40std::vector<T> Sorted(absl::flat_hash_set<T> items) {
41 std::vector<T> result(items.begin(), items.end());
53 if (model_name_different_ || primary_objective_name_different_) {
74 result.primary_objective_name_different_ =
79 const absl::flat_hash_set<int64_t> first_elements =
81 const absl::flat_hash_set<int64_t> second_elements =
86 for (int64_t element :
IntersectSets(first_elements, second_elements)) {
87 absl::StatusOr<absl::string_view> first_name =
90 absl::StatusOr<absl::string_view> second_name =
94 CHECK_OK(second_name);
95 if (*first_name != *second_name) {
107 [&result, &first, &second]<
typename AttrType>(AttrType attr) {
111 const absl::flat_hash_set<Key> first_non_defaults =
113 const absl::flat_hash_set<Key> second_non_defaults =
131 const absl::StatusOr<absl::string_view> name =
134 return absl::StrCat(
id,
": (name: \"", absl::CEscape(*name),
"\")");
137template <
typename AttrType>
138std::string KeyDebugString(
const Elemental& elemental,
const AttrType attr,
140 std::vector<std::string> element_names;
141 for (
int i = 0; i < GetAttrKeySize<AttrType>(); ++i) {
145 element_names.push_back(absl::StrCat(
"\"", absl::CEscape(*name),
"\""));
147 element_names.push_back(
"__missing__");
150 return absl::StrCat(
"(", absl::StrJoin(element_names,
", "),
")");
158 if (difference.
Empty()) {
159 return "No difference";
161 std::vector<std::string> lines;
162 if (difference.model_name_different_) {
163 lines.push_back(
"model name disagrees:");
164 lines.push_back(absl::StrCat(
" first_name: \"",
166 lines.push_back(absl::StrCat(
" second_name: \"",
169 if (difference.primary_objective_name_different_) {
170 lines.push_back(
"primary objective name disagrees:");
171 lines.push_back(absl::StrCat(
" first_name: \"",
174 lines.push_back(absl::StrCat(
" second_name: \"",
180 if (!el_diff.
Empty()) {
181 lines.push_back(absl::StrCat(e,
":"));
184 lines.push_back(
" element ids in first but not second:");
187 absl::StrCat(
" ", ElementDebugString(first, e,
id)));
191 lines.push_back(
" element ids in second but not first:");
194 absl::StrCat(
" ", ElementDebugString(second, e,
id)));
199 lines.push_back(
" element ids with disagreeing names:");
201 absl::StatusOr<absl::string_view> first_name =
203 absl::StatusOr<absl::string_view> second_name =
205 CHECK_OK(first_name);
206 CHECK_OK(second_name);
207 lines.push_back(absl::StrCat(
208 " id: ",
id,
" first_name: \"", absl::CEscape(*first_name),
209 "\" second_name: \"", absl::CEscape(*second_name),
"\""));
213 lines.push_back(
" next_id does not agree:");
214 lines.push_back(absl::StrCat(
" first: ", first.
NextElementId(e)));
215 lines.push_back(absl::StrCat(
" second: ", second.
NextElementId(e)));
221 [&lines, &difference, &first, &second]<
typename AttrType>(AttrType attr) {
223 auto attr_value_str = [attr](
const Elemental& elemental,
227 return std::string(
"__missing__");
231 if (!attr_diff.Empty()) {
232 lines.push_back(absl::StrCat(
"For attribute ", attr,
233 " errors on the following keys:"));
235 lines.push_back(absl::StrCat(
237 " (name in first: ", KeyDebugString(first, attr, key),
238 ") value in first: ", attr_value_str(first, key),
239 " (name in second: ", KeyDebugString(second, attr, key),
240 ") value in second: ", attr_value_str(second, key)));
244 return absl::StrJoin(lines,
"\n");
const AttributeDifference< AttrType > & attr_difference(const AttrType a) const
AttributeDifference< AttrType > & mutable_attr_difference(const AttrType a)
static ElementalDifference Create(const Elemental &first, const Elemental &second, const ElementalDifferenceOptions &options={})
Returns the difference between two Elementals.
ElementDifference & mutable_element_difference(const ElementType e)
ElementalDifference()=default
const ElementDifference & element_difference(const ElementType e) const
static std::string Describe(const Elemental &first, const Elemental &second, const ElementalDifference &difference)
static std::string DescribeDifference(const Elemental &first, const Elemental &second, const ElementalDifferenceOptions &options={})
Returns a string describing the difference between two models.
absl::StatusOr< absl::string_view > GetElementNameUntyped(const ElementType e, const int64_t id) const
Type-erased version of GetElementName. Prefer the latter.
std::vector< AttrKeyFor< AttrType > > AttrNonDefaults(const AttrType a) const
Return the vector of attribute keys where a is non-default.
const std::string & primary_objective_name() const
The name of the primary objective of this optimization model.
std::vector< int64_t > AllElementsUntyped(const ElementType e) const
Type-erased version of AllElements. Prefer the latter.
const std::string & model_name() const
The name of this optimization model.
Policy::template Wrapped< ValueTypeFor< AttrType > > GetAttr(AttrType a, AttrKeyFor< AttrType > key) const
int64_t NextElementId(const ElementType e) const
An object oriented wrapper for quadratic constraints in ModelStorage.
AttrKey< AttrTypeDescriptorT< AttrType >::kNumKeyElements, typename AttrTypeDescriptorT< AttrType >::Symmetry > AttrKeyFor
The type of the AttrKey for attribute type AttrType.
absl::flat_hash_set< T > IntersectSets(const absl::flat_hash_set< T > &first, const absl::flat_hash_set< T > &second)
Returns the elements in both first and second.
constexpr std::array< ElementType, GetAttrKeySize< attr >()> GetElementTypes()
std::string FormatAttrValue(const ValueType v)
static void ForEachAttr(Fn &&fn)
AttrKeyFor< AttrType > Key
The difference for an ElementType.
bool next_id_different
The value of next_id for this ElementType differs.
bool Empty() const
Indicates there are no differences for this ElementType.
SymmetricDifference< int64_t > ids
Element ids in one elemental but not in the other.
absl::flat_hash_set< int64_t > different_names
Element ids in both elementals where the element names disagree.
absl::flat_hash_set< T > only_in_second
absl::flat_hash_set< T > only_in_first