5 // Alexander Chebaturkin (chebaturkin@gmail.com)
7 // Copyright (C) 2012 Alexander Chebaturkin
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections.Generic;
34 using Mono.CodeContracts.Static.DataStructures;
36 namespace Mono.CodeContracts.Static.Analysis.Numerical {
37 struct Monomial<TVar> {
38 static readonly IComparer<TVar> Comparer = new ExpressionViaStringComparer<TVar> ();
40 readonly Rational coefficient;
42 readonly Sequence<TVar> variables;
44 public Rational Coeff { get { return coefficient; } }
46 public IEnumerable<TVar> Variables { get { return variables.AsEnumerable (); } }
48 public int Degree { get; private set; }
50 public bool IsLinear { get { return Degree <= 1; } }
52 public bool IsConstant { get { return Degree == 0; } }
54 Monomial (Rational coeff)
58 variables = Sequence<TVar>.Empty;
62 private Monomial (TVar x)
65 coefficient = Rational.One;
66 variables = Sequence<TVar>.Singleton (x);
70 private Monomial (Rational k, TVar x)
74 variables = k == Rational.Zero ? Sequence<TVar>.Empty : Sequence<TVar>.Singleton (x);
75 Degree = variables.Length ();
78 Monomial (Rational k, Sequence<TVar> vars)
82 variables = k == Rational.Zero ? Sequence<TVar>.Empty : vars;
83 Degree = variables.Length ();
86 public bool Contains (TVar var)
88 return variables.Any (v => v.Equals (var));
91 public bool IsSingleVariable (out TVar var)
94 return true.With (variables.Head, out var);
96 return false.Without (out var);
99 public Monomial<TVar> Rename (TVar x, TVar rename)
104 Func<TVar, TVar> renamer = v => v.Equals (x) ? rename : v;
106 return From (Coeff, variables.Select (renamer));
109 public Monomial<TVar> With (Rational coeff)
111 return new Monomial<TVar> (coeff, variables);
114 public Monomial<TVar> With (Func<Rational, Rational> func)
116 return new Monomial<TVar> (func (coefficient), variables);
119 public static Monomial<TVar> operator - (Monomial<TVar> m)
121 return m.With (-m.coefficient);
124 public static Monomial<TVar> From (Rational coeff)
126 return new Monomial<TVar> (coeff);
129 public static Monomial<TVar> From (Rational coeff, Sequence<TVar> vars)
131 return From (coeff, vars, seq => seq.AsEnumerable ());
134 public static Monomial<TVar> From (Rational coeff, IEnumerable<TVar> vars)
136 return From (coeff, vars, seq => seq);
139 static Monomial<TVar> From<T> (Rational coeff, T vars, Func<T, IEnumerable<TVar>> toEnumerable)
141 if (coeff == Rational.Zero)
142 return new Monomial<TVar> (coeff);
144 var list = toEnumerable (vars).ToList ();
145 list.Sort (Comparer);
147 return new Monomial<TVar> (coeff, Sequence<TVar>.From (list));
150 public override string ToString ()
152 return string.Format ("{0} * {1}", coefficient, VarsToString (variables));
155 static string VarsToString (Sequence<TVar> seq)
157 var len = seq.Length ();
158 var sb = new StringBuilder ();
162 sb.Append (seq.Head);
163 seq.Tail.ForEach (v => sb.AppendFormat (" * {0}", v));
166 return sb.ToString ();
169 public bool IsEquivalentTo (Monomial<TVar> that)
171 if (coefficient != that.coefficient || Degree != that.Degree)
175 return variables.Head.Equals (that.variables.Head);
177 foreach (var var in variables.AsEnumerable ()) {
178 if (!that.Contains (var))
185 public override bool Equals (object obj)
187 if (ReferenceEquals (obj, null))
190 if (obj is Monomial<TVar>)
191 return IsEquivalentTo ((Monomial<TVar>) obj);
195 public override int GetHashCode ()
198 variables.ForEach (v => res += v.GetHashCode ());
199 return res + coefficient.GetHashCode ();
202 public bool IsIntConstant (out long constant)
204 if (IsConstant && coefficient.IsInteger)
205 return true.With ((long) coefficient.NextInt64, out constant);
207 return false.Without (out constant);