-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathVariableProduct.cs
146 lines (131 loc) · 5.33 KB
/
VariableProduct.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
namespace LazyMathInstructor
{
/// <summary>
/// Represents a product of 0 or more variables, each with an exponent.
/// For example one <see cref="VariableProduct"/> would be "a^3 b^4 c"
/// </summary>
public class VariableProduct : IComparable
{
/// <summary>
/// Maps all variables appearing in this variable product to their respective exponents.
/// Variables with exponent 0 do not appear in the dictionary.
/// </summary>
public SortedDictionary<Variable, int> Exponents { get; }
/// <summary>
/// Construct a <see cref="VariableProduct"/> with no variables.
/// </summary>
public VariableProduct()
{
Exponents = new SortedDictionary<Variable, int>();
}
/// <summary>
/// Construct a <see cref="VariableProduct"/> with one variable <paramref name="v"/>
/// that has an exponent of 1.
/// </summary>
public VariableProduct(Variable v)
{
Exponents = new SortedDictionary<Variable, int>()
{
{ v, 1 }
};
}
/// <summary>
/// Construct a <see cref="VariableProduct"/> that copies the exponents from the
/// existing dictionary <paramref name="exponents"/> (of another <see cref="VariableProduct"/>).
/// </summary>
private VariableProduct(SortedDictionary<Variable, int> exponents)
{
Exponents = new SortedDictionary<Variable, int>(exponents);
}
/// <summary>
/// Operator for multiplication of two variable products.
/// <paramref name="first"/> * <paramref name="second"/> is calculated by
/// adding the exponents of all variables in the product (i.e. ab * b^2 = a b^3).
/// </summary>
public static VariableProduct operator *(VariableProduct first, VariableProduct second)
{
var result = new VariableProduct(first.Exponents);
foreach (var x in second.Exponents)
{
if (result.Exponents.ContainsKey(x.Key))
{
result.Exponents[x.Key] += x.Value;
}
else
{
result.Exponents.Add(x.Key, x.Value);
}
}
return result;
}
/// <summary>
/// Overloaded method to get hash code based solely on the content of the <see cref="Exponents"/>,
/// since two <see cref="VariableProduct"/>s with matching <see cref="Exponents"/> are considered equal.
/// </summary>
public override int GetHashCode()
{
var hash = new HashCode();
foreach (var exponent in Exponents)
{
hash.Add((exponent.Key, exponent.Value));
}
return hash.ToHashCode();
}
/// <summary>
/// Overloaded equality check based solely on the content of the <see cref="Exponents"/>.
/// If all entries in the <see cref="Exponents"/> dictionary match,
/// the <see cref="VariableProduct"/>s are considered to be equal.
/// This is needed to use and compare them, e.g. as a key in Dictionaries.
/// </summary>
public override bool Equals(object obj)
{
if (obj is not VariableProduct other) return false;
if (this.Exponents.Count != other.Exponents.Count) return false;
var thisEnum = this.Exponents.GetEnumerator();
var otherEnum = other.Exponents.GetEnumerator();
while (thisEnum.MoveNext())
{
otherEnum.MoveNext();
if (thisEnum.Current.Key != otherEnum.Current.Key || thisEnum.Current.Value != otherEnum.Current.Value)
return false;
}
return true;
}
/// <summary>
/// Pretty-Printing for debugging purposes / verbose output.
/// </summary>
public override string ToString()
{
string result = "";
foreach (var varTerm in Exponents.OrderBy(x => x.Key))
{
var exponent = varTerm.Value switch
{
1 => "",
< 10 => $"^{varTerm.Value}",
_ => $"^({varTerm.Value})",
};
result += varTerm.Key.ToString().ToLower() + exponent;
}
return result;
}
/// <summary>
/// Compares two <see cref="VariableProduct"/>s to establish an ordering.
/// Earlier letters and higher exponents are ordered before later letters and smaller exponents:
/// a^3 < a^2 < ab < b^2 < c
/// </summary>
public int CompareTo(object obj)
{
if (obj is not VariableProduct other)
throw new ArgumentException("Can't compare variable product to object of different type!");
for (Variable v = Variable.A; v <= Variable.Z; v++)
{
int thisExponent = Exponents.GetValueOrDefault(v);
int otherExponent = other.Exponents.GetValueOrDefault(v);
if (thisExponent != otherExponent)
return otherExponent - thisExponent; // Greater exponent precedes smaller exponent in ordering
}
return 0;
}
}
}