├── .gitignore ├── CastExtensions.cs ├── DictionaryExtensions.cs ├── DotNetExtensions.csproj ├── DotNetExtensions.sln ├── DotNetExtensionsTestProject1 ├── DictionaryExtensionsTests.cs ├── DotNetExtensionsTests.csproj └── Properties │ └── AssemblyInfo.cs ├── EnumerableExtensions.cs ├── Numerics.cs ├── Properties └── AssemblyInfo.cs ├── README.md ├── Viterbi ├── FunctionBasedViterbi.cs ├── Properties │ └── AssemblyInfo.cs ├── Viterbi.csproj ├── contractsUserdoc.pdf └── contractsUserdoc.txt ├── ViterbiTests ├── Properties │ └── AssemblyInfo.cs ├── ViterbiTest1.cs ├── ViterbiTests.csproj └── bin │ ├── Debug │ ├── System.CoreEx.dll │ ├── System.Interactive.dll │ └── System.Reactive.dll │ └── Release │ ├── System.CoreEx.dll │ ├── System.Interactive.dll │ └── System.Reactive.dll └── iSynapticSubset ├── IMaybe.cs ├── Maybe.cs ├── State.cs ├── TrySelector.cs └── Unit.cs /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | *.user 3 | *.vs10x 4 | *.docstates 5 | *.dotcover 6 | bin/ 7 | obj/ 8 | Build/ 9 | _ReSharper.*/ 10 | TestResults/ -------------------------------------------------------------------------------- /CastExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Experimental.DotNetExtensions 7 | { 8 | public static class CastExtensions 9 | { 10 | public static T MustBe(this object self) 11 | where T : class 12 | { 13 | var that = self as T; 14 | if (that == null) 15 | { 16 | throw new InvalidOperationException( 17 | string.Format( 18 | "Expected object {0} to have type {1}", 19 | self.ToString(), 20 | typeof(T).ToString())); 21 | } 22 | return that; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /DictionaryExtensions.cs: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | 3 | // Portions Copyright (c) 2011 Jordan E. Terrell, licensed to 4 | // Microsoft Corporation under the MIT license (copied below). 5 | // 6 | // Portions Copyright (c) 2011 Microsoft Corporation 7 | 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Diagnostics.Contracts; 30 | using System.Linq; 31 | using Experimental.DotNetExtensions.iSynaptic; 32 | 33 | namespace Experimental.DotNetExtensions 34 | { 35 | /// 36 | /// Extensions to the IDictionary interface, supporting chainable dictionary combinators. 37 | /// 38 | public static class IDictionary 39 | { 40 | /// 41 | /// Creation through explicitly supplied first values. 42 | /// 43 | /// The type of keys in the dictionary. 44 | /// The type of values in the dictionary. 45 | /// A value of type K. 46 | /// A value of type V. 47 | /// The IDictionary interface of a new dictionary. 48 | public static IDictionary AddUnconditionally(K key, V value) 49 | { 50 | return new Dictionary() 51 | .AddUnconditionally(key, value); 52 | } 53 | 54 | /// 55 | /// Creation through explicitly supplied first values. 56 | /// 57 | /// The type of keys in the dictionary. 58 | /// The type of values in the dictionary. 59 | /// A value of type K. 60 | /// A value of type V. 61 | /// The IDictionary interface of a new dictionary. 62 | public static IDictionary AddConditionally(K key, V value) 63 | { 64 | return new Dictionary() 65 | .AddConditionally(key, value); 66 | } 67 | 68 | /// 69 | /// Creation based on types of ignored values. Recommended usage IDictionary.Create(default(K), default(V)). 70 | /// 71 | /// The type of keys in the dictionary. 72 | /// The type of values in the dictionary. 73 | /// A value of type K to assist type inference; ignored. 74 | /// A value of type V to assist type inference; ignored. 75 | /// The IDictionary interface of a new dictionary. 76 | public static IDictionary Create(K key, V value) 77 | { 78 | return new Dictionary(); 79 | } 80 | 81 | /// 82 | /// Creation based on explicitly supplied type arguments. 83 | /// 84 | /// The type of keys in the dictionary. 85 | /// The type of values in the dictionary. 86 | /// The IDictionary interface of a new dictionary. 87 | public static IDictionary Create() 88 | { 89 | return new Dictionary(); 90 | } 91 | 92 | /// 93 | /// Returns a Maybe instance encapsulating a potentially absent value. 94 | /// 95 | /// The type of keys in the dictionary. 96 | /// The type of values in the dictionary. 97 | /// The input dictionary. 98 | /// The key to try. 99 | /// The potentially absent value encapsulated in a Maybe. 100 | public static Maybe TryGetValue( 101 | this IDictionary theDictionary, 102 | K key) 103 | { 104 | //Contract.Requires(null != theDictionary, "theDictionary"); 105 | 106 | V retrieved = default(V); 107 | 108 | return theDictionary.TryGetValue(key, out retrieved) 109 | ? new Maybe(retrieved) 110 | : Maybe.NoValue; 111 | } 112 | 113 | /// 114 | /// Add whether the key is present or not. 115 | /// 116 | /// The type of keys in the dictionary. 117 | /// The type of values in the dictionary. 118 | /// The input dictionary. 119 | /// The input key-value pair. 120 | /// The modified dictionary. 121 | public static IDictionary AddUnconditionally( 122 | this IDictionary theDictionary, 123 | KeyValuePair keyValuePair) 124 | { 125 | Contract.Requires(theDictionary != null); 126 | 127 | #if (false) 128 | theDictionary[keyValuePair.Key] = keyValuePair.Value; 129 | return theDictionary; 130 | #else 131 | // Take the kvp . . . 132 | return keyValuePair 133 | // Bring it into the state monad with the IDictionary as state 134 | // and the default propagator that does nothing to the state . . . 135 | .ToState, KeyValuePair>() 136 | // Shove this through a transformer that produces a bool and state . . . 137 | .Bind, KeyValuePair, bool>( 138 | // From the provided kvp . . . 139 | kvp => new State, bool>( 140 | // with a propagator that UNCONDITIONALLY puts the kvp in 141 | // the dictionary, and reports whether the key was already 142 | // present . . . 143 | #if (false) 144 | propagator: dict => ValueStatePair.Create(dict 145 | // TODO: Investigate intermittent stress failure of the Maybe monad! 146 | // via the Maybe monad . . . 147 | .TryGetValue(kvp.Key) 148 | // if the value was not in the dictionary, add it . . . 149 | .OnNoValue(() => dict.Add(key: kvp.Key, value: kvp.Value)) 150 | // if the value was in the dictionary, replace it . . . 151 | .OnValue(_ => dict[kvp.Key] = kvp.Value) 152 | // be thread-safe . . . 153 | .Synchronize(dict) 154 | // provide the bool . . . 155 | .HasValue, 156 | // and the original dictionary. 157 | dict))) 158 | #else 159 | propagator: dict => 160 | { 161 | var value = default(V); 162 | var hasValue = dict.TryGetValue(kvp.Key, out value); 163 | if (hasValue) 164 | dict[kvp.Key] = kvp.Value; 165 | else 166 | dict.Add(key: kvp.Key, value: kvp.Value); 167 | 168 | return ValueStatePair.Create(hasValue, dict); 169 | })) 170 | #endif 171 | // Apply the newly bound state to the input dictionary . . . 172 | .Propagator(theDictionary) 173 | // Extract the dictionary from the tuple and return it: 174 | .State 175 | ; 176 | 177 | // Sadly, the bool info about whether the key was in the dictionary 178 | // is lost, the price we pay to thread the dictionary out. 179 | #endif 180 | } 181 | 182 | /// 183 | /// Add whether the key is present or not. 184 | /// 185 | /// The type of keys in the dictionary. 186 | /// The type of values in the dictionary. 187 | /// The input dictionary. 188 | /// The key to install. 189 | /// The value to install. 190 | /// The modified dictionary. 191 | public static IDictionary AddUnconditionally( 192 | this IDictionary theDictionary, 193 | K key, 194 | V value) 195 | { 196 | return theDictionary 197 | .AddUnconditionally( 198 | new KeyValuePair(key: key, value: value)); 199 | } 200 | 201 | /// 202 | /// Add only if key is NOT already present. 203 | /// 204 | /// The type of keys in the dictionary. 205 | /// The type of values in the dictionary. 206 | /// The input dictionary. 207 | /// The input key-value pair. 208 | /// The modified dictionary. 209 | public static IDictionary AddConditionally( 210 | this IDictionary theDictionary, 211 | KeyValuePair kvpInput) 212 | { 213 | Contract.Requires(theDictionary != null); 214 | 215 | #if (false) 216 | var value = default(V); 217 | var hasValue = theDictionary.TryGetValue(kvpInput.Key, out value); 218 | if (!hasValue) 219 | theDictionary[kvpInput.Key] = kvpInput.Value; 220 | return theDictionary; 221 | #else 222 | 223 | // Take the kvp . . . 224 | return kvpInput 225 | // Bring it into the state monad with the IDictionary as state 226 | // and the default propagator that does nothing to the state . . . 227 | .ToState, KeyValuePair>() 228 | // Shove this through a transformer that produces a bool and state . . . 229 | .Bind, KeyValuePair, bool>( 230 | // From the provided kvp . . . 231 | kvp => new State, bool>( 232 | // with a propagator that CONDITIONALLY puts the kvp in 233 | // the dictionary, and reports whether the key was already 234 | // present . . . 235 | #if (false) 236 | propagator: dict => ValueStatePair.Create(dict 237 | // TODO: investigate failure of the Maybe monad! 238 | // via the Maybe monad . . . 239 | .TryGetValue(kvp.Key) 240 | // if the value was not in the dictionary, add it . . . 241 | .OnNoValue(() => dict.Add(key: kvp.Key, value: kvp.Value)) 242 | // be thread safe . . . 243 | .Synchronize(dict) 244 | // provide the bool . . . 245 | .HasValue, 246 | // and the original dictionary. 247 | dict))) 248 | #else 249 | propagator: dict => 250 | { 251 | var value = default(V); 252 | var hasValue = dict.TryGetValue(kvp.Key, out value); 253 | if (!hasValue) 254 | dict.Add(key: kvp.Key, value: kvp.Value); 255 | return ValueStatePair.Create(hasValue, dict); 256 | })) 257 | #endif 258 | // Apply the newly bound state to the input dictionary . . . 259 | .Propagator(theDictionary) 260 | // Extract the dictionary from the tuple and return it: 261 | .State 262 | ; 263 | 264 | // Sadly, the info about whether the key was in the dictionary 265 | // is lost, the price we pay to thread the dictionary through. 266 | #endif 267 | } 268 | 269 | public static IDictionary AddConditionally( 270 | this IDictionary theDictionary, 271 | K key, 272 | V value) 273 | { 274 | return theDictionary 275 | .AddConditionally( 276 | new KeyValuePair(key: key, value: value)); 277 | } 278 | 279 | /// 280 | /// Look up the value, and return the default of type 'Value' if the key is not present. 281 | /// 282 | /// The type of keys. 283 | /// The type of values. 284 | /// The dictionary in which to look up values. 285 | /// They key to look up. 286 | /// The value of type T corresponding to the key if the key is present in the dictionary, otherwise, the defined default value for the type T of all values. 287 | public static V GetValueOrDefault( 288 | this IDictionary theDictionary, 289 | K key) 290 | where V : class 291 | { 292 | V result; 293 | var foundP = theDictionary.TryGetValue(key, out result); 294 | Contract.Assert(foundP == true || result == null); 295 | return result ?? default(V); 296 | } 297 | 298 | public static V GetValueOrDefaultValueType( 299 | this IDictionary theDictionary, 300 | K key) 301 | where V : struct 302 | { 303 | V result; 304 | var foundP = theDictionary.TryGetValue(key, out result); 305 | Contract.Assert(foundP == true || result.Equals(default(V))); 306 | return result; // lapses automatically to default(T) if TryGetValue returns false 307 | } 308 | 309 | /// 310 | /// Look up the value, and return an empty IEnumerable of the specified type if the key is not present. 311 | /// 312 | /// The type of keys. 313 | /// The type of values. 314 | /// The dictionary in which to look up values. 315 | /// They key to look up. 316 | /// The value of type T corresponding to the key if the key is present in the dictionary, otherwise, an empty enumerable of V's. 317 | public static IEnumerable GetValueOrEmpty( 318 | this IDictionary> theDictionary, 319 | K key) 320 | { 321 | IEnumerable result; 322 | var foundP = theDictionary.TryGetValue(key, out result); 323 | Contract.Assert(foundP == true || result == null); // null is the default for IEnumerable 324 | var result2 = result ?? Enumerable.Empty(); 325 | return result2; 326 | } 327 | 328 | /// 329 | /// Look up the value, and return the specified value if the key is not present. 330 | /// 331 | /// The type of keys. 332 | /// The type of values. 333 | /// The dictionary in which to look up values. 334 | /// They key to look up. 335 | /// The specified value to return if the key is not present. 336 | /// The value of type T corresponding to the key if the key is present in the dictionary, otherwise, the specified value of type V. 337 | public static V GetValueOrSpecified( 338 | this IDictionary theDictionary, 339 | K key, 340 | V specified) 341 | where V : class 342 | { 343 | V result; 344 | var foundP = theDictionary.TryGetValue(key, out result); 345 | Contract.Assert(foundP == true || result == null); 346 | var result2 = result ?? specified; 347 | return result2; 348 | } 349 | 350 | /// 351 | /// Look up the value, and return the specified value if the key is not present. 352 | /// 353 | /// The type of keys. 354 | /// The type of values. 355 | /// The dictionary in which to look up values. 356 | /// They key to look up. 357 | /// The specified value to return if the key is not present. 358 | /// The value of type T corresponding to the key if the key is present in the dictionary, otherwise, the specified value of type V. 359 | public static V GetValueOrSpecifiedValueType( 360 | this IDictionary theDictionary, 361 | K key, 362 | V specified) 363 | where V : struct 364 | { 365 | V result; 366 | var foundP = theDictionary.TryGetValue(key, out result); 367 | Contract.Assert(foundP == true || result.Equals(default(V))); 368 | return result; 369 | } 370 | 371 | /// 372 | /// Increases the tally count for the given key in the dictionary.. 373 | /// 374 | /// The type of keys. 375 | /// The dictionary in which to tally keys. 376 | /// The key to tally. 377 | public static IDictionary Tally( 378 | this IDictionary theDictionary, 379 | K key) 380 | { 381 | return theDictionary.AddUnconditionally( 382 | key, 383 | theDictionary.GetValueOrDefaultValueType(key) + 1); 384 | } 385 | 386 | /// 387 | /// (Overload that creates the dictionary) Increases the tally count for the given key in the dictionary.. 388 | /// 389 | /// The type of keys. 390 | /// The key to tally. 391 | public static IDictionary Tally( 392 | K key) 393 | { 394 | return IDictionary.Create(key, 1L); 395 | } 396 | } 397 | } 398 | -------------------------------------------------------------------------------- /DotNetExtensions.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {929C6B38-22D8-42EC-8D24-03678DFAF228} 9 | Library 10 | Properties 11 | Monza.DotNetExtensions 12 | DotNetExtensions 13 | v4.0 14 | 512 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 0 24 | 25 | 26 | true 27 | full 28 | false 29 | bin\Debug\ 30 | DEBUG;TRACE 31 | prompt 32 | 4 33 | True 34 | False 35 | True 36 | True 37 | False 38 | True 39 | True 40 | True 41 | True 42 | True 43 | True 44 | True 45 | False 46 | False 47 | True 48 | 49 | 50 | 51 | 52 | 53 | 54 | False 55 | Full 56 | Build 57 | 0 58 | 59 | 60 | pdbonly 61 | true 62 | bin\Release\ 63 | TRACE 64 | prompt 65 | 4 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 96 | -------------------------------------------------------------------------------- /DotNetExtensions.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetExtensions", "DotNetExtensions.csproj", "{929C6B38-22D8-42EC-8D24-03678DFAF228}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetExtensionsTests", "DotNetExtensionsTestProject1\DotNetExtensionsTests.csproj", "{FACE70D1-ED03-498F-95ED-673E514229DE}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{60A996A6-0AE6-4C49-94FF-094A3B3A1B61}" 9 | ProjectSection(SolutionItems) = preProject 10 | README.md = README.md 11 | EndProjectSection 12 | EndProject 13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Viterbi", "Viterbi\Viterbi.csproj", "{021A5039-3860-49DB-9D6F-B2B8C14497A8}" 14 | EndProject 15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ViterbiTests", "ViterbiTests\ViterbiTests.csproj", "{CF26536C-4497-4760-914E-4FCA8F57A283}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {929C6B38-22D8-42EC-8D24-03678DFAF228}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {929C6B38-22D8-42EC-8D24-03678DFAF228}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {929C6B38-22D8-42EC-8D24-03678DFAF228}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {929C6B38-22D8-42EC-8D24-03678DFAF228}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {FACE70D1-ED03-498F-95ED-673E514229DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {FACE70D1-ED03-498F-95ED-673E514229DE}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {FACE70D1-ED03-498F-95ED-673E514229DE}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {FACE70D1-ED03-498F-95ED-673E514229DE}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {021A5039-3860-49DB-9D6F-B2B8C14497A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {021A5039-3860-49DB-9D6F-B2B8C14497A8}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {021A5039-3860-49DB-9D6F-B2B8C14497A8}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {021A5039-3860-49DB-9D6F-B2B8C14497A8}.Release|Any CPU.Build.0 = Release|Any CPU 35 | {CF26536C-4497-4760-914E-4FCA8F57A283}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 36 | {CF26536C-4497-4760-914E-4FCA8F57A283}.Debug|Any CPU.Build.0 = Debug|Any CPU 37 | {CF26536C-4497-4760-914E-4FCA8F57A283}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {CF26536C-4497-4760-914E-4FCA8F57A283}.Release|Any CPU.Build.0 = Release|Any CPU 39 | EndGlobalSection 40 | GlobalSection(SolutionProperties) = preSolution 41 | HideSolutionNode = FALSE 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /DotNetExtensionsTestProject1/DictionaryExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Text; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Microsoft.VisualStudio.TestTools.UnitTesting; 7 | using Experimental.DotNetExtensions; 8 | using System.Collections; 9 | using System.Diagnostics; 10 | 11 | namespace DotNetExtensionsTestProject1 12 | { 13 | [TestClass()] 14 | public class DictionaryExtensionsTests 15 | { 16 | /// 17 | ///Gets or sets the test context which provides 18 | ///information about and functionality for the current test run. 19 | /// 20 | public TestContext TestContext { get; set; } 21 | public static Dictionary TestDictionary; 22 | 23 | #region Additional test attributes 24 | // 25 | //You can use the following additional attributes as you write your tests: 26 | // 27 | //Use ClassInitialize to run code before running the first test in the class 28 | [ClassInitialize()] 29 | public static void DictionaryTestClassInitialize(TestContext testContext) 30 | { 31 | TestDictionary = new Dictionary(); 32 | } 33 | 34 | //Use ClassCleanup to run code after all tests in a class have run 35 | //[ClassCleanup()] 36 | //public static void MyClassCleanup() 37 | //{ 38 | //} 39 | // 40 | //Use TestInitialize to run code before running each test 41 | [TestInitialize()] 42 | public void DictionaryTestInitialize() 43 | { 44 | TestDictionary.Clear(); 45 | 46 | TestDictionary[1] = "a"; 47 | TestDictionary[2] = "b"; 48 | TestDictionary[3] = "c"; 49 | } 50 | 51 | //Use TestCleanup to run code after each test has run 52 | //[TestCleanup()] 53 | //public void MyTestCleanup() 54 | //{ 55 | //} 56 | // 57 | #endregion 58 | 59 | private static void AssertDictionaryInitialized() 60 | { 61 | Assert.AreEqual(TestDictionary[1], "a"); 62 | Assert.AreEqual(TestDictionary[2], "b"); 63 | Assert.AreEqual(TestDictionary[3], "c"); 64 | Assert.IsFalse(TestDictionary.Values.Contains("d")); 65 | Assert.IsFalse(TestDictionary.Values.Contains("e")); 66 | Assert.IsFalse(TestDictionary.Values.Contains("f")); 67 | } 68 | 69 | //[TestMethod()] 70 | //public void TestAddUnconditionally() 71 | //{ 72 | // AssertDictionaryInitialized(); 73 | 74 | // Assert.IsFalse(TestDictionary.AddUnconditionally(5, "e")); 75 | // Assert.IsTrue(TestDictionary.Values.Contains("e")); 76 | // Assert.AreEqual(TestDictionary[5], "e"); 77 | 78 | // Assert.IsTrue(TestDictionary.AddUnconditionally(5, "f")); 79 | // Assert.IsFalse(TestDictionary.Values.Contains("e")); 80 | // Assert.AreEqual(TestDictionary[5], "f"); 81 | //} 82 | 83 | [TestMethod()] 84 | public void TestAddConditionally() 85 | { 86 | AssertDictionaryInitialized(); 87 | 88 | var dict = TestDictionary 89 | .AddConditionally(4, "d") 90 | .AddConditionally(3, "e") 91 | ; 92 | 93 | Assert.IsNotNull(dict); 94 | Assert.ReferenceEquals(dict, TestDictionary); 95 | 96 | Assert.AreEqual(dict[3], "c"); 97 | Assert.AreEqual(dict[4], "d"); 98 | 99 | Assert.IsFalse(dict.Values.Contains("e")); 100 | 101 | var maybe = TestDictionary.TryGetValue(3); 102 | Assert.IsTrue(maybe.HasValue); 103 | Assert.AreEqual(maybe.Value, "c"); 104 | 105 | maybe = TestDictionary.TryGetValue(5); 106 | Assert.IsFalse(maybe.HasValue); 107 | 108 | dict.Clear(); 109 | Assert.AreEqual(0, dict.Values.Count()); 110 | Assert.AreEqual(0, dict.Keys.Count()); 111 | 112 | const int range = 1280; 113 | var kvps = Enumerable 114 | .Range(0, range) 115 | .Select(i => new KeyValuePair(i, Convert.ToChar(i).ToString())) 116 | ; 117 | 118 | dict = kvps.Aggregate(dict, (d, kvp) => d.AddConditionally(kvp)); 119 | 120 | Assert.AreEqual(range, dict.Count()); 121 | 122 | var cc = new CollectionComparer>(); 123 | Assert.IsTrue(cc.Equals(kvps, dict)); 124 | 125 | CollectionAssert.AreEquivalent(kvps.ToList(), dict.ToList()); 126 | 127 | kvps = Enumerable 128 | .Range(0, range) 129 | .Select(i => new KeyValuePair(i, Convert.ToChar(3 * i + 7).ToString())) 130 | ; 131 | 132 | dict = kvps.Aggregate(dict, (d, kvp) => d.AddConditionally(kvp)); 133 | 134 | CollectionAssert.AreNotEquivalent(kvps.ToList(), dict.ToList()); 135 | } 136 | 137 | [TestMethod()] 138 | public void TestAddUnConditionally() 139 | { 140 | AssertDictionaryInitialized(); 141 | 142 | var dict = TestDictionary 143 | .AddUnconditionally(4, "d") 144 | .AddUnconditionally(3, "e") 145 | ; 146 | 147 | Assert.IsNotNull(dict); 148 | Assert.ReferenceEquals(dict, TestDictionary); 149 | 150 | Assert.AreEqual(dict[3], "e"); 151 | Assert.AreEqual(dict[4], "d"); 152 | 153 | Assert.IsFalse(dict.Values.Contains("c")); 154 | 155 | var maybe = TestDictionary.TryGetValue(3); 156 | Assert.IsTrue(maybe.HasValue); 157 | Assert.AreEqual(maybe.Value, "e"); 158 | 159 | maybe = TestDictionary.TryGetValue(5); 160 | Assert.IsFalse(maybe.HasValue); 161 | 162 | dict.Clear(); 163 | Assert.AreEqual(0, dict.Values.Count()); 164 | Assert.AreEqual(0, dict.Keys.Count()); 165 | 166 | const int range = 1280; 167 | var kvps = Enumerable 168 | .Range(0, range) 169 | .Select(i => new KeyValuePair(i, Convert.ToChar(i).ToString())) 170 | ; 171 | 172 | dict = kvps.Aggregate(dict, (d, kvp) => d.AddUnconditionally(kvp)); 173 | 174 | Assert.AreEqual(range, dict.Count()); 175 | 176 | var cc = new CollectionComparer>(); 177 | Assert.IsTrue(cc.Equals(kvps, dict)); 178 | 179 | CollectionAssert.AreEquivalent(kvps.ToList(), dict.ToList()); 180 | 181 | kvps = Enumerable 182 | .Range(0, range) 183 | .Select(i => new KeyValuePair(i, Convert.ToChar(3 * i + 7).ToString())) 184 | ; 185 | 186 | dict = kvps.Aggregate(dict, (d, kvp) => d.AddUnconditionally(kvp)); 187 | 188 | CollectionAssert.AreEquivalent(kvps.ToList(), dict.ToList()); 189 | } 190 | 191 | [TestMethod()] 192 | public void TestExPerf() 193 | { 194 | const int repetitions = 10000; 195 | AssertDictionaryInitialized(); 196 | 197 | TestDictionary = new Dictionary(); 198 | var random = new Random(); 199 | var stopwatch = new Stopwatch(); 200 | var kvps = Enumerable 201 | .Range(0, repetitions) 202 | .Select(_ => random.Next()) 203 | .Select(i => new KeyValuePair( 204 | i, 205 | i.GetHashCode().ToString())) 206 | .ToList() 207 | ; 208 | 209 | 210 | 211 | stopwatch.Start(); 212 | 213 | 214 | 215 | var dict = kvps.Aggregate( 216 | TestDictionary as IDictionary, 217 | (d, kvp) => d.AddUnconditionally(kvp)); 218 | Trace.WriteLine(string.Format( 219 | "MONADIC UNCONDITIONAL DICTIONARY COUNT: {0}", 220 | dict.Count())); 221 | var dict1 = dict.ToList(); 222 | var ticks = stopwatch.ElapsedTicks; 223 | 224 | 225 | 226 | stopwatch.Reset(); 227 | 228 | 229 | 230 | Trace.WriteLine(string.Format( 231 | "MONADIC UNCONDITIONAL DICTIONARY PERF: Milliseconds to insert {0} items = {1} monadically", 232 | repetitions, 233 | Math.Round(ticks / 1.0e4, 3))); 234 | 235 | 236 | 237 | dict = new Dictionary(); 238 | stopwatch.Start(); 239 | 240 | 241 | 242 | foreach (var kvp in kvps) 243 | dict[kvp.Key] = kvp.Value; 244 | Trace.WriteLine(string.Format( 245 | "NON-MONADIC UNCONDITIONAL DICTIONARY COUNT: {0}", 246 | dict.Count())); 247 | var dict2 = dict.ToList(); 248 | ticks = stopwatch.ElapsedTicks; 249 | 250 | 251 | 252 | stopwatch.Reset(); 253 | 254 | 255 | 256 | Trace.WriteLine(string.Format( 257 | "NON-MONADIC UNCONDITIONAL DICTIONARY PERF: Milliseconds to insert {0} items = {1} NON-monadically", 258 | repetitions, 259 | Math.Round(ticks / 1.0e4, 3))); 260 | 261 | 262 | CollectionAssert.AreEquivalent(dict1, dict2); 263 | 264 | 265 | 266 | dict = new Dictionary(); 267 | stopwatch.Start(); 268 | 269 | 270 | 271 | dict = kvps.Aggregate( 272 | TestDictionary as IDictionary, 273 | (d, kvp) => d.AddConditionally(kvp)); 274 | Trace.WriteLine(string.Format( 275 | "MONADIC CONDITIONAL DICTIONARY COUNT: {0}", 276 | dict.Count())); 277 | dict1 = dict.ToList(); 278 | ticks = stopwatch.ElapsedTicks; 279 | 280 | 281 | 282 | stopwatch.Reset(); 283 | 284 | 285 | 286 | Trace.WriteLine(string.Format( 287 | "MONADIC CONDITIONAL DICTIONARY PERF: Milliseconds to insert {0} items = {1} monadically", 288 | repetitions, 289 | Math.Round(ticks / 1.0e4, 3))); 290 | 291 | 292 | 293 | dict = new Dictionary(); 294 | stopwatch.Start(); 295 | 296 | 297 | 298 | foreach (var kvp in kvps) 299 | { 300 | string value; 301 | if (!dict.TryGetValue(kvp.Key, out value)) 302 | dict[kvp.Key] = kvp.Value; 303 | } 304 | Trace.WriteLine(string.Format( 305 | "NON-MONADIC CONDITIONAL DICTIONARY COUNT: {0}", 306 | dict.Count())); 307 | dict2 = dict.ToList(); 308 | ticks = stopwatch.ElapsedTicks; 309 | 310 | 311 | 312 | stopwatch.Reset(); 313 | 314 | 315 | 316 | Trace.WriteLine(string.Format( 317 | "NON-MONADIC CONDITIONAL DICTIONARY PERF: Milliseconds to insert {0} items = {1} NON-monadically", 318 | repetitions, 319 | Math.Round(ticks / 1.0e4, 3))); 320 | 321 | 322 | 323 | CollectionAssert.AreEquivalent(dict1, dict2); 324 | } 325 | } 326 | 327 | public class CollectionComparer : IEqualityComparer> 328 | { 329 | public bool Equals(IEnumerable first, IEnumerable second) 330 | { 331 | if ((first == null) != (second == null)) 332 | return false; 333 | // At this point, either both null or both not null. 334 | if (!object.ReferenceEquals(first, second) && (first != null)) 335 | { 336 | // At this point, both not null. 337 | if (first.Count() != second.Count()) 338 | return false; 339 | if ((first.Count() != 0) && HaveMismatchedElement(first, second)) 340 | return false; 341 | } 342 | return true; 343 | } 344 | 345 | private static bool HaveMismatchedElement(IEnumerable first, IEnumerable second) 346 | { 347 | int firstCount; 348 | int secondCount; 349 | 350 | var firstTallies = GetElementTally(first, out firstCount); 351 | var secondTallies = GetElementTally(second, out secondCount); 352 | // Number of nulls doesn't match 353 | if (firstCount != secondCount) 354 | return true; 355 | 356 | foreach (var kvp in firstTallies) 357 | { 358 | firstCount = kvp.Value; 359 | secondTallies.TryGetValue(kvp.Key, out secondCount); 360 | // Some element tally doesn't match 361 | if (firstCount != secondCount) 362 | return true; 363 | } 364 | // All element tallies match 365 | return false; 366 | } 367 | private static Dictionary GetElementTally( 368 | IEnumerable enumerable, 369 | out int nullTally) 370 | { 371 | var dictionary = new Dictionary(); 372 | nullTally = 0; 373 | foreach (T element in enumerable) 374 | { 375 | if (element == null) 376 | { 377 | nullTally++; 378 | } 379 | else 380 | { 381 | int num; 382 | dictionary.TryGetValue(element, out num); 383 | num++; 384 | dictionary[element] = num; 385 | } 386 | } 387 | return dictionary; 388 | } 389 | public int GetHashCode(IEnumerable enumerable) 390 | { 391 | int hash = 17; 392 | foreach (T val in enumerable.OrderBy(x => x)) 393 | hash = hash * 23 + val.GetHashCode(); 394 | return hash; 395 | } 396 | } 397 | } 398 | 399 | -------------------------------------------------------------------------------- /DotNetExtensionsTestProject1/DotNetExtensionsTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 7 | 8 | 2.0 9 | {FACE70D1-ED03-498F-95ED-673E514229DE} 10 | Library 11 | Properties 12 | DotNetExtensionsTestProject1 13 | DotNetExtensionsTestProject1 14 | v4.0 15 | 512 16 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | true 28 | full 29 | false 30 | bin\Debug\ 31 | DEBUG;TRACE 32 | prompt 33 | 4 34 | 35 | 36 | pdbonly 37 | true 38 | bin\Release\ 39 | TRACE 40 | prompt 41 | 4 42 | 43 | 44 | 45 | 46 | 47 | 3.5 48 | 49 | 50 | 51 | 52 | False 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | {929C6B38-22D8-42EC-8D24-03678DFAF228} 62 | DotNetExtensions 63 | 64 | 65 | 66 | 73 | -------------------------------------------------------------------------------- /DotNetExtensionsTestProject1/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DotNetExtensionsTestProject1")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("DotNetExtensionsTestProject1")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f3f22c33-ec3f-4ec1-8021-3bfa6c7e8b62")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | 3 | // Portions Copyright (c) 2011 Jordan E. Terrell, licensed to 4 | // Microsoft Corporation under the MIT license (copied below). 5 | // 6 | // Portions Copyright (c) 2011 Microsoft Corporation 7 | // 8 | // Portions adapted from http://northhorizon.net/ under the 9 | // Creative Commons Attribution license 10 | // http://creativecommons.org/licenses/by/3.0/us/) 11 | 12 | // Permission is hereby granted, free of charge, to any person obtaining 13 | // a copy of this software and associated documentation files (the 14 | // "Software"), to deal in the Software without restriction, including 15 | // without limitation the rights to use, copy, modify, merge, publish, 16 | // distribute, sublicense, and/or sell copies of the Software, and to 17 | // permit persons to whom the Software is furnished to do so, subject to 18 | // the following conditions: 19 | 20 | // The above copyright notice and this permission notice shall be 21 | // included in all copies or substantial portions of the Software. 22 | 23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | using System; 31 | using System.Collections.Generic; 32 | using System.Diagnostics.Contracts; 33 | using System.Linq; 34 | 35 | namespace Experimental.DotNetExtensions 36 | { 37 | /// 38 | /// Provides extension methods for and . 39 | /// 40 | public static class IEnumerable 41 | { 42 | /// 43 | /// The standard monadic "Return" operation. 44 | /// 45 | /// The type of the thing to lift into the monad. 46 | /// The sone value to lift into the monad. 47 | /// An IEnumerable containing a single item of type T. 48 | public static IEnumerable Return(this T singleValue) 49 | { 50 | return new[] { singleValue } as IEnumerable; 51 | } 52 | 53 | /// 54 | /// Constructs the outer product (outer join) of two IEnumerables, as an IEnumerable of Tuples. 55 | /// 56 | /// The first IEnumerable. 57 | /// The second IEnumerable. 58 | /// The IEnumerable of pairs (as Tuples) of the inputs. 59 | public static IEnumerable> Outer( 60 | this IEnumerable these, 61 | IEnumerable those) 62 | { 63 | Contract.Requires(these != null); 64 | Contract.Requires(those != null); 65 | 66 | return from a in these 67 | from b in those 68 | select Tuple.Create(a, b); 69 | } 70 | 71 | /// 72 | /// Gets the input argument that produces the maximum value of the specified function. 73 | /// 74 | /// The type of items in the collection. 75 | /// The type of the value yielded from the specified function. 76 | /// The target collection. 77 | /// The function used to produce values. 78 | /// The argument that produces the highest value. 79 | public static A ArgMax( 80 | this IEnumerable collection, 81 | Func function) 82 | where V : IComparable 83 | { 84 | Contract.Requires(collection != null); 85 | Contract.Requires(function != null); 86 | return ArgComp(collection, function, GreaterThan); 87 | } 88 | 89 | private static bool GreaterThan(A first, A second) where A : IComparable 90 | { 91 | return first.CompareTo(second) > 0; 92 | } 93 | 94 | /// 95 | /// Gets the intput argument that produces the minimum value of the specified function. 96 | /// 97 | /// The type of items in the collection. 98 | /// The type of the value yielded from the specified function. 99 | /// The target collection. 100 | /// The function used to produce values. 101 | /// The argument that produces the least value. 102 | public static A ArgMin( 103 | this IEnumerable collection, 104 | Func function) 105 | where V : IComparable 106 | { 107 | Contract.Requires(collection != null); 108 | Contract.Requires(function != null); 109 | return ArgComp(collection, function, LessThan); 110 | } 111 | 112 | private static bool LessThan(A first, A second) where A : IComparable 113 | { 114 | return first.CompareTo(second) < 0; 115 | } 116 | 117 | private static A ArgComp( 118 | IEnumerable collection, 119 | Func function, 120 | Func accept) 121 | 122 | where V : IComparable 123 | { 124 | Contract.Requires(collection != null); 125 | Contract.Requires(function != null); 126 | Contract.Requires(accept != null); 127 | 128 | var isSet = false; 129 | var maxArg = default(A); 130 | var extremeValue = default(V); 131 | 132 | foreach (var item in collection) 133 | { 134 | var value = function(item); 135 | if (!isSet || accept(value, extremeValue)) 136 | { 137 | maxArg = item; 138 | extremeValue = value; 139 | isSet = true; 140 | } 141 | } 142 | 143 | return maxArg; 144 | } 145 | 146 | /// 147 | /// Encapsulates returned argument-and-value pairs from ArgAndMax and ArgAndMin. 148 | /// 149 | /// The argument at which the IEnumerable has its extreme value. 150 | /// The extreme value. 151 | public class ArgumentValuePair 152 | { 153 | public A Argument { get; set; } 154 | public V Value { get; set; } 155 | } 156 | 157 | /// 158 | /// Gets the argument that produces the maximum value and the maximum value produced by the specified function. 159 | /// 160 | /// The type of items in the collection. 161 | /// The type of the value yielded from the specified function. 162 | /// The target collection. 163 | /// The function used to produce values. 164 | /// Instance of an anonymous type with properties "Argument" and "Value" for the argument producing the maximum value and the minimum value. 165 | public static ArgumentValuePair ArgAndMax( 166 | this IEnumerable collection, 167 | Func function) 168 | where V : IComparable 169 | { 170 | Contract.Requires(collection != null); 171 | Contract.Requires(function != null); 172 | 173 | return ArgAndComp(collection, function, GreaterThan); 174 | } 175 | 176 | /// 177 | /// Gets the argument that produces the minimum value and the minimum value produced by the specified function. 178 | /// 179 | /// The type of items in the collection. 180 | /// The type of the value yielded from the specified function. 181 | /// The target collection. 182 | /// The function used to produce values. 183 | /// Instance of a dynamic type with properties "Argument" and "Value" for the argument producing the minimum value and the minimum value. 184 | public static ArgumentValuePair ArgAndMin( 185 | this IEnumerable collection, 186 | Func function) 187 | where V : IComparable 188 | { 189 | Contract.Requires(collection != null); 190 | Contract.Requires(function != null); 191 | 192 | return ArgAndComp(collection, function, LessThan); 193 | } 194 | 195 | private static ArgumentValuePair ArgAndComp( 196 | IEnumerable collection, 197 | Func function, 198 | Func accept) 199 | where V : IComparable 200 | { 201 | Contract.Requires(collection != null); 202 | Contract.Requires(function != null); 203 | Contract.Requires(accept != null); 204 | 205 | var isSet = false; 206 | var maxArg = default(A); 207 | var extremeValue = default(V); 208 | 209 | foreach (var item in collection) 210 | { 211 | var value = function(item); 212 | if (!isSet || accept(value, extremeValue)) 213 | { 214 | maxArg = item; 215 | extremeValue = value; 216 | isSet = true; 217 | } 218 | } 219 | 220 | return new ArgumentValuePair { Argument = maxArg, Value = extremeValue }; 221 | } 222 | 223 | /// 224 | /// Perform an action for side effect pairwise on elements of a pair of IEnumerables. 225 | /// 226 | /// The type of elements in the first IEnumerable. 227 | /// The type of elements in the second IEnumerable. 228 | /// The first IEnumerable. 229 | /// The second IEnumerable. 230 | /// The action to perform on pairs of elements. 231 | public static void ZipDo( 232 | this IEnumerable first, 233 | IEnumerable second, 234 | Action action) 235 | { 236 | Contract.Requires(first != null); 237 | Contract.Requires(second != null); 238 | Contract.Requires(action != null); 239 | 240 | using (IEnumerator firstEnumerator = first.GetEnumerator()) 241 | using (IEnumerator secondEnumerator = second.GetEnumerator()) 242 | while (firstEnumerator.MoveNext() && secondEnumerator.MoveNext()) 243 | action(firstEnumerator.Current, secondEnumerator.Current); 244 | } 245 | 246 | /// 247 | /// Perform an action for side effect pairwise on adjacent members of an IEnumerable. 248 | /// 249 | /// The type of elements in the input enumerable. 250 | /// The input enumerable. 251 | /// The action to perform on pairs of adjacent elements. 252 | public static IEnumerable PairwiseDo( 253 | this IEnumerable enumerable, 254 | Action action) 255 | { 256 | Contract.Requires(enumerable != null); 257 | Contract.Requires(action != null); 258 | Contract.Requires(enumerable.First() != null); 259 | 260 | enumerable.ZipDo(enumerable.Skip(1), action); 261 | 262 | return enumerable; 263 | } 264 | 265 | /// 266 | /// Map a binary function over all adjacent pairs in the input enumerable. 267 | /// 268 | /// The type of elements in the input enumerable. 269 | /// The type of element in the returned enumerable. 270 | /// The input enumerable. 271 | /// The function to map. 272 | /// An enumerable of results of mapping the function over the input enumerable, two adjacent elements at a time. 273 | public static IEnumerable Pairwise( 274 | this IEnumerable enumerable, 275 | Func resultSelector) 276 | { 277 | Contract.Requires(enumerable != null); 278 | Contract.Requires(resultSelector != null); 279 | Contract.Requires(enumerable.First() != null); 280 | 281 | return enumerable.Zip(enumerable.Skip(1), resultSelector); 282 | } 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /Numerics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics.Contracts; 6 | using Experimental.DotNetExtensions.iSynaptic; 7 | 8 | namespace Experimental.DotNetExtensions 9 | { 10 | public struct DoubleComponents 11 | { 12 | public double Datum { get; set; } 13 | public bool IsNaN { get; set; } 14 | public bool Negative { get; set; } 15 | public int MathematicalBase2Exponent { get; set; } 16 | public long MathematicalBase2Mantissa { get; set; } 17 | public int RawExponentInt { get; set; } 18 | public long RawMantissaLong { get; set; } 19 | // TODO: Memoize these 20 | public long FloorLog10 { get { return Log10.Floor(); } } 21 | public double FracLog10 { get { return Log10 - FloorLog10; } } 22 | public double Log10 { get { return Datum.Log10(); } } 23 | public byte[] ExponentBits { get { return BitConverter.GetBytes(RawExponentInt); } } 24 | public byte[] MantissaBits { get { return BitConverter.GetBytes(RawMantissaLong); } } 25 | } 26 | /// 27 | /// Numerical routines. 28 | /// 29 | public static class Numerics 30 | { 31 | public static double Log10(this double d) { return Math.Log10(d); } 32 | public static double Exp10(this double d) { return Math.Pow(10d, d); } 33 | public static double LogB(this double d, double @base) { return Math.Log(d, @base); } 34 | public static double Log(this double d) { return Math.Log(d); } 35 | public static double Exp(this double d) { return Math.Exp(d); } 36 | public static double ExpB(this double d, double @base) { return Math.Pow(@base, d); } 37 | public static double Pow(this double d, double exponent) { return Math.Pow(d, exponent); } 38 | public static long Floor(this double d) { return ((long)(Math.Floor(d))); } 39 | public static long Ceiling(this double d) { return ((long)(Math.Ceiling(d))); } 40 | public static double DFloor(this double d) { return ((long)(Math.Floor(d))); } 41 | public static double DCeiling(this double d) { return ((long)(Math.Ceiling(d))); } 42 | public static double Round(this double d, int digits = 4) { return Math.Round(d, digits); } 43 | 44 | public static DoubleComponents Decompose(this double d) 45 | { 46 | // See http://msdn.microsoft.com/en-us/library/aa691146(VS.71).aspx 47 | // and Steve Hollasch's http://steve.hollasch.net/cgindex/coding/ieeefloat.html 48 | // and PremK's http://blogs.msdn.com/b/premk/archive/2006/02/25/539198.aspx 49 | 50 | var result = new DoubleComponents { Datum = d }; 51 | 52 | long bits = BitConverter.DoubleToInt64Bits(d); 53 | bool fNegative = (bits < 0); 54 | int exponent = (int)((bits >> 52) & 0x7ffL); 55 | long mantissa = (bits & 0xfffffffffffffL); 56 | 57 | result.Negative = fNegative; 58 | result.RawExponentInt = exponent; 59 | result.RawMantissaLong = mantissa; 60 | 61 | if (exponent == 0x7ffL && mantissa != 0) 62 | { 63 | Contract.Assert(double.IsNaN(d)); 64 | 65 | // The number is an NaN. Client must interpret. 66 | result.IsNaN = true; 67 | return result; 68 | } 69 | 70 | // The first bit of the mathematical mantissaBits is always 1, and it is not 71 | // represented in the stored mantissaBits bits. The following logic accounts for 72 | // this and restores the mantissaBits to its mathematical value. 73 | 74 | if (exponent == 0) 75 | { 76 | if (mantissa == 0) 77 | { 78 | // Returning either +0 or -0. 79 | return result; 80 | } 81 | // Denormalized: A fool-proof detector for denormals is a zero exponentBits. 82 | // Mantissae for denormals do not have an assumed leading 1-bit. Bump the 83 | // exponentBits by one so that when we re-bias it by -1023, we have actually 84 | // brought it back down by -1022, the way it should be. This increment merges 85 | // the logic for normals and denormals. 86 | exponent++; 87 | } 88 | else 89 | { 90 | // Normalized: radix point (the binary point) is after the first non-zero digit (bit). 91 | // Or-in the *assumed* leading 1 bit to restore the mathematical mantissaBits. 92 | mantissa = mantissa | (1L << 52); 93 | } 94 | 95 | // Re-bias the exponentBits by the IEEE 1023, which treats the mathematical mantissaBits 96 | // as a pure fraction, minus another 52, because we treat the mathematical mantissaBits 97 | // as a pure integer. 98 | exponent -= 1075; 99 | 100 | // Produce form with lowest possible whole-number mantissaBits. 101 | while ((mantissa & 1) == 0) 102 | { 103 | mantissa >>= 1; 104 | exponent++; 105 | } 106 | 107 | result.MathematicalBase2Exponent = exponent; 108 | result.MathematicalBase2Mantissa = mantissa; 109 | return result; 110 | } 111 | 112 | /// 113 | /// Compares two doubles for nearness in the absolute value within a given delta, also a double. Not realiable for infinities, epsilon, max_value, min_value, and NaNs. 114 | /// 115 | /// The first double. 116 | /// The second double. 117 | /// The allowable absolute difference. 118 | /// 119 | public static bool DoublesWithinAbsoluteDifference(double d1, double d2, double delta) 120 | { 121 | return (Math.Abs(d1 - d2) <= Math.Abs(delta)); 122 | } 123 | 124 | /// 125 | /// Return the bits of a double as a twos-complement long integer. IEEE 745 doubles are 126 | /// lexicographically ordered in this representation. 127 | /// 128 | /// The double to convert. 129 | /// A long containing the bits of the double in twos-complement. 130 | private static long TwosComplementBits(double d) 131 | { 132 | long bits = BitConverter.DoubleToInt64Bits(d); 133 | // Convert to 2-s complement, which are lexicographically ordered. 134 | if (bits < 0) 135 | bits = unchecked((long)(0x8000000000000000 - (ulong)bits)); 136 | return bits; 137 | } 138 | 139 | /// 140 | /// Returns the number of IEEE 754 double-precision values separating a pair of doubles. Adjacent doubles 141 | /// will have a quanta-difference of 1. Returns -1L if either number is NaN. Reports that double.MaxValue 142 | /// is adjacent to double.PositiveInfinity and likewise for double.MinValue and double.NegativeInfinity. 143 | /// 144 | /// The first double to compare. 145 | /// The second double to compare. 146 | /// The number of IEEE 745 doubles separating the pair. 147 | public static long LexicographicQuantaDifference(double d1, double d2) 148 | { 149 | if (double.IsNaN(d1) || double.IsNaN(d2)) 150 | return -1L; 151 | 152 | // See Bruce Dawson's http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm 153 | // The major limitation of this technique is that double.MaxValue and double.PostiveInfinity will 154 | // report almost equal. See the paper for mitigations. 155 | 156 | // Extract bits from the doubles. 157 | long bits1 = TwosComplementBits(d1); 158 | long bits2 = TwosComplementBits(d2); 159 | 160 | long diff = bits1 - bits2; 161 | if (diff < 0) 162 | diff = -diff; 163 | 164 | return diff; 165 | } 166 | 167 | /// 168 | /// Compare doubles for equality within a given number of possible discrete double-precision values. 169 | /// Produces false if either number is NaN. Reports that double.MaxValue is almost equal to 170 | /// double.PositiveInfinity; likewise for double.MinValue and double.NegativeInfinity. 171 | /// 172 | /// The first double. 173 | /// The second double. 174 | /// The number of discrete double-precision values permitted between d1 and d2. Must be >= 0. 175 | /// 176 | public static bool DoublesNearlyEqual(double d1, double d2, int nQuanta) 177 | { 178 | Contract.Assert(nQuanta >= 0, "nUnits"); 179 | 180 | if (double.IsNaN(d1) || double.IsNaN(d2)) 181 | return false; 182 | 183 | return LexicographicQuantaDifference(d1, d2) <= nQuanta; 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Experimental.DotNetExtensions")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Experimental.DotNetExtensions")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("05ea01b1-14e9-4dbe-be76-fbf1a879fb3e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository contains some dot net extensions to the dictionary type, 2 | some numerical convenience functions, a couple of combinators for ArgMax. 3 | 4 | People to whom I am indebted are acknowledge in comments in the code, but 5 | include Jordan E. Terrell (see his extensive iSynaptic project in GitHub), 6 | and Daniel Moore via northhorizon.net. 7 | 8 | Licenses invoked include the MIT license and the Creative-Commons 9 | Attribution 3.0 United States License. 10 | 11 | // The MIT License 12 | 13 | // Portions Copyright (c) 2011 Jordan E. Terrell, licensed to 14 | // Microsoft Corporation under the MIT license (copied below). 15 | // 16 | // Portions Copyright (c) 2011 Microsoft Corporation 17 | // 18 | // Portions adapted from http://northhorizon.net/ under the 19 | // Creative Commons Attribution license 20 | // http://creativecommons.org/licenses/by/3.0/us/) 21 | 22 | // Permission is hereby granted, free of charge, to any person obtaining 23 | // a copy of this software and associated documentation files (the 24 | // "Software"), to deal in the Software without restriction, including 25 | // without limitation the rights to use, copy, modify, merge, publish, 26 | // distribute, sublicense, and/or sell copies of the Software, and to 27 | // permit persons to whom the Software is furnished to do so, subject to 28 | // the following conditions: 29 | 30 | // The above copyright notice and this permission notice shall be 31 | // included in all copies or substantial portions of the Software. 32 | 33 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 34 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 35 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 36 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 37 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 38 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 39 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Viterbi/FunctionBasedViterbi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Diagnostics.Contracts; 5 | using Experimental.DotNetExtensions; 6 | 7 | namespace Experimental.MachineLearning.Viterbi 8 | { 9 | // TODO: write contract reference assemblies 10 | 11 | // TODO: optimize to only call probability functions for domain 12 | // values guaranteed to return non-zero probabilities 13 | 14 | /// 15 | /// A reactive type of Viterbi algorithm ( 16 | /// http://en.wikipedia.org/wiki/Viterbi_algorithm ), suitable for 17 | /// on-line or off-line application. Requires user-supplied 18 | /// functions to express the model (state-to-state transition 19 | /// probabilities and state-to-observation probabilities) 20 | /// 21 | /// The type of states. 22 | /// The type of observations. 23 | public class FunctionBasedDoubleViterbi : IObserver>> 24 | { 25 | /// 26 | /// The TargetStates are the states the system might transition TO in response to an observation. 27 | /// 28 | private IEnumerable TargetStates { get; set; } 29 | 30 | /// 31 | /// The SourceStates are the states the system might transition FROM to EMIT an observation. 32 | /// 33 | private IEnumerable SourceStates { get; set; } 34 | 35 | /// 36 | /// Function that computes probabilities of occurrence of the initial states; for bootstrapping the model. 37 | /// 38 | public Func StartingProbabilities { get; private set; } 39 | 40 | /// 41 | /// Transition probabilities from state-to-state; part of the Hidden Markov Model. 42 | /// 43 | public Func TransitionProbabilities { get; private set; } 44 | 45 | /// 46 | /// Probabilities of observing outcome (observation) O given 47 | /// that the system is in state S; part of the Hidden Markov 48 | /// Model. 49 | /// 50 | public Func EmissionProbabilities { get; private set; } 51 | 52 | /// 53 | /// After the current observation is processed, _V.Last() 54 | /// contains the probabilities of the most probable paths 55 | /// leading to each state. Each element of _V is a map from 56 | /// state to probability of most-probable-path. _V keeps the 57 | /// entire history of such probability maps. 58 | /// 59 | private List> _V; 60 | 61 | /// 62 | /// At any time t and for any state s, V[t][s] is the 63 | /// probability of the most probable path ending in state s. 64 | /// The times are implicitly 0, 1, ...; that is, the indices 65 | /// of the IEnumerable. 66 | /// 67 | public IEnumerable> V { get { return _V; } } 68 | 69 | /// 70 | /// For any state, the most probable path through all prior 71 | /// states leading to that state, given all the observations 72 | /// seen so far. "Path" only keeps the LAST map from state to 73 | /// list of states, unlike V, which keeps the entire history 74 | /// of maps from states to probabilities of 75 | /// most-probable-paths. 76 | /// 77 | public Dictionary> Path { get; private set; } 78 | 79 | /// 80 | /// The constructor requires functions for computing probabilities. 81 | /// 82 | /// Initial probabilities, one for each state. 83 | /// Probabilities for transition from a state to any other state. 84 | /// Probabilities of seeing observation O given state S. 85 | public FunctionBasedDoubleViterbi 86 | ( 87 | Func startingProbabilities, 88 | Func transitionProbabilities, 89 | Func emissionProbabilities) 90 | { 91 | Contract.Requires(startingProbabilities != null); 92 | Contract.Requires(transitionProbabilities != null); 93 | Contract.Requires(emissionProbabilities != null); 94 | 95 | // TODO: Require that probabilities sum APPROXIMATELY to one. 96 | 97 | StartingProbabilities = startingProbabilities; 98 | TransitionProbabilities = transitionProbabilities; 99 | EmissionProbabilities = emissionProbabilities; 100 | } 101 | 102 | /// 103 | /// Do nothing on completed. 104 | /// 105 | public void OnCompleted() 106 | { 107 | } 108 | 109 | /// 110 | /// Re-throw on error. 111 | /// 112 | public void OnError(Exception error) 113 | { 114 | throw error; 115 | } 116 | 117 | /// 118 | /// Static helper function. 119 | /// 120 | private static bool Implies(bool A, bool B) 121 | { 122 | return ((!A) || B); 123 | } 124 | 125 | /// 126 | /// Static helper function. 127 | /// 128 | private static bool Iff(bool A, bool B) 129 | { 130 | return Implies(A, B) && Implies(B, A); 131 | } 132 | 133 | /// 134 | /// LastV contains the mapping from state to probability 135 | /// of most-probable-paths-to-the-state that was produced 136 | /// by the prior observation. 137 | /// 138 | private Dictionary LastV { get; set; } 139 | 140 | /// 141 | /// OnNext takes a tuple of an observation and a sequence of 142 | /// states that might have emitted this observation (the 143 | /// FROM states). The name of the tuple is "value". The 144 | /// observation is in "value.Item1" and the sequence of 145 | /// states is in "value.Item2". 146 | /// 147 | public void OnNext(Tuple> value) 148 | { 149 | Contract.Requires(value.Item2 != null); 150 | // Contract.Requires fails here due to visibility of the properties. 151 | Contract.Assert(Iff(TargetStates == null, LastV == null)); 152 | 153 | // True only first time around -- at bootstrapping time. 154 | if (TargetStates == null) 155 | { 156 | // Initialize the HISTORY LIST of maps from state to 157 | // probability-of-most-probable-path. 158 | _V = new List>(); 159 | 160 | // Initialize the map from state to 161 | // most-probable-path-leading-to-state. 162 | Path = new Dictionary>(); 163 | 164 | // Initialize the FIRST map from state to probability 165 | // of most-probable-path leading to the state. 166 | var firstV = new Dictionary(); 167 | 168 | // value.Item2 contains the FROM states: the states 169 | // that might have emitted this observation. Now 170 | // compute the probabilities for transition to all the 171 | // TO states. In this bootstrapping case, the 172 | // probabilities are simply the emission 173 | // probabilities -- the probabilities that the state 174 | // produced this observation -- times the probability 175 | // that the system was in that state. 176 | foreach (var state in value.Item2) 177 | { 178 | // The probability of the most probable path 179 | // leading to "state" given observation is the 180 | // a-priori probability of state times the 181 | // conditional probability of observation given 182 | // the state. Observation is in the slot 183 | // "value.Item1." 184 | firstV[state] = 185 | StartingProbabilities(state) * 186 | EmissionProbabilities(state, value.Item1); 187 | 188 | // The state that yielded the transition to this 189 | // most probable path is just "state" itself. 190 | Path[state] = new List(); 191 | Path[state].Add(state); 192 | } 193 | // The possible targets for the next transition are in 194 | // the states, in-turn in slot "value.Item2." 195 | TargetStates = value.Item2; 196 | _V.Add(firstV); 197 | LastV = firstV; 198 | return; 199 | } 200 | 201 | // The source states for this observation are the target 202 | // states from the last observation (Viterbi, strictly 203 | // speaking, has a memory of ONE transition). In case of 204 | // the first observation -- the bootstrapping case, this 205 | // is also true, it just so happens that the source and 206 | // target states are the same during bootstrapping. 207 | SourceStates = TargetStates; 208 | 209 | // The target states for this observation are in the input 210 | // to OnNext. 211 | TargetStates = value.Item2; 212 | 213 | // Space for the new probabilities of the 214 | // most-probable-paths leading to each state. 215 | var nextV = new Dictionary(); 216 | 217 | // and for each candidate target state . . . 218 | foreach (var target in TargetStates) 219 | { 220 | // . . . find the SOURCE state that leads to the most 221 | // probable path to the target. 222 | // 223 | // Maximize over the prior states: the transition 224 | // probabilities from the source state, times the 225 | // conditional probabilities of seeing the actual 226 | // observation given the candidate source state, times 227 | // the probability of the most-probable-path leading 228 | // to the source state. Use the LINQ non-standard 229 | // query operator "ArgAndMax," which, for any 230 | // IEnumerable, finds the input (the arg or "source") 231 | // that produces the maximum value of its given 232 | // function (lambda expression), and also that maximum 233 | // value, returning both the argument and the maximum 234 | // in an instance of class ArgumentValuePair. 235 | // 236 | // In this lambda expression, "target" is fixed 237 | // (closed over). 238 | var maxStateAndProb = SourceStates.ArgAndMax(source => 239 | { 240 | // probability of the most probable path that led 241 | // to source 242 | var a = LastV[source]; 243 | 244 | // transition probability from source to target 245 | var b = TransitionProbabilities(source, target); 246 | 247 | // probability of seeing actual observation if we 248 | // are in the target state; observation is stored 249 | // in value.Item1. 250 | var c = EmissionProbabilities(target, value.Item1); 251 | 252 | return a * b * c; 253 | }); 254 | 255 | // After this point, we have found the SOURCE state 256 | // that produces the most probable path to the given 257 | // target state and yielding the given observation. 258 | // Save the probability of that most-probable-path. 259 | nextV[target] = maxStateAndProb.Value; 260 | 261 | // Copy the most probable path that led to the source 262 | // state that yields the maximum probability. I must 263 | // copy it because this path might be the same for 264 | // multiple targets, and each target will need its own 265 | // copy of the prior path to append itself to. 266 | var newpath = new List(Path[maxStateAndProb.Argument]); 267 | 268 | // Append the current state. 269 | newpath.Add(target); 270 | 271 | // Replace the path to the current target with the 272 | // refreshed one. 273 | Path[target] = newpath; 274 | } 275 | _V.Add(nextV); 276 | LastV = nextV; 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /Viterbi/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Experimental.MachineLearning.Viterbi")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("Experimental.MachineLearning.Viterbi")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("450f652c-1f1f-40bd-9ace-caea681ca90d")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Viterbi/Viterbi.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {021A5039-3860-49DB-9D6F-B2B8C14497A8} 9 | Library 10 | Properties 11 | Monza.MachineLearning.Viterbi 12 | Viterbi 13 | v4.0 14 | 512 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 0 24 | 25 | 26 | true 27 | full 28 | false 29 | bin\Debug\ 30 | DEBUG;TRACE 31 | prompt 32 | 4 33 | True 34 | False 35 | True 36 | True 37 | True 38 | True 39 | True 40 | True 41 | True 42 | True 43 | True 44 | False 45 | True 46 | 47 | 48 | 49 | 50 | 51 | 52 | True 53 | Full 54 | Build 55 | False 56 | False 57 | 0 58 | 59 | 60 | pdbonly 61 | true 62 | bin\Release\ 63 | TRACE 64 | prompt 65 | 4 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | {929C6B38-22D8-42EC-8D24-03678DFAF228} 83 | DotNetExtensions 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 100 | -------------------------------------------------------------------------------- /Viterbi/contractsUserdoc.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebcabin/DotNetExtensionsImproved/ff493b09393da1ed1fd01c8a85aea2178179dfee/Viterbi/contractsUserdoc.pdf -------------------------------------------------------------------------------- /Viterbi/contractsUserdoc.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebcabin/DotNetExtensionsImproved/ff493b09393da1ed1fd01c8a85aea2178179dfee/Viterbi/contractsUserdoc.txt -------------------------------------------------------------------------------- /ViterbiTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ViterbiTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("ViterbiTests")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2011")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("ae4ec75e-0414-4879-9395-db7c5c4557a0")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /ViterbiTests/ViterbiTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using Experimental.DotNetExtensions; 6 | using Experimental.MachineLearning.Viterbi; 7 | 8 | namespace ViterbiTests 9 | { 10 | [TestClass] 11 | public class ViterbiTest1 12 | { 13 | [TestMethod] 14 | public void WikipediaUnitTest() 15 | { 16 | var Rainy = "Rainy"; 17 | var Sunny = "Sunny"; 18 | 19 | var Walk = "Walk"; 20 | var Shop = "Shop"; 21 | var Clean = "Clean"; 22 | 23 | var states = new[] { Rainy, Sunny }; 24 | var observations = new[] { Walk, Shop, Clean }; 25 | 26 | const double RainyProb = 0.6D; 27 | const double SunnyProb = 1D - RainyProb; 28 | 29 | const double RainyToRainyProb = 0.7D; 30 | const double RainyToSunnyProb = 1D - RainyToRainyProb; 31 | 32 | const double SunnyToRainyProb = 0.4D; 33 | const double SunnyToSunnyProb = 1D - SunnyToRainyProb; 34 | 35 | const double RainyWalkProb = 0.1D; 36 | const double RainyShopProb = 0.4D; 37 | const double RainyCleanProb = 1D - RainyWalkProb - RainyShopProb; 38 | 39 | const double SunnyWalkProb = 0.6D; 40 | const double SunnyShopProb = 0.3D; 41 | const double SunnyCleanProb = 1 - SunnyWalkProb - SunnyShopProb; 42 | 43 | var startingProbabilitiesDict = IDictionary 44 | .AddUnconditionally(Rainy, RainyProb) 45 | .AddUnconditionally(Sunny, SunnyProb); 46 | 47 | var transitionProbabilitiesDict = IDictionary 48 | .AddUnconditionally(Rainy, IDictionary 49 | .AddUnconditionally(Rainy, RainyToRainyProb) 50 | .AddUnconditionally(Sunny, RainyToSunnyProb)) 51 | .AddUnconditionally(Sunny, IDictionary 52 | .AddUnconditionally(Rainy, SunnyToRainyProb) 53 | .AddUnconditionally(Sunny, SunnyToSunnyProb)); 54 | 55 | var emissionProbabilitiesDict = IDictionary 56 | .AddUnconditionally(Rainy, IDictionary 57 | .AddUnconditionally(Walk, RainyWalkProb) 58 | .AddUnconditionally(Shop, RainyShopProb) 59 | .AddUnconditionally(Clean, RainyCleanProb)) 60 | .AddUnconditionally(Sunny, IDictionary 61 | .AddUnconditionally(Walk, SunnyWalkProb) 62 | .AddUnconditionally(Shop, SunnyShopProb) 63 | .AddUnconditionally(Clean, SunnyCleanProb)); 64 | 65 | try 66 | { 67 | var fbv = new FunctionBasedDoubleViterbi 68 | (startingProbabilities: (s => startingProbabilitiesDict[s]) 69 | , transitionProbabilities: ((sOut, sIn) => transitionProbabilitiesDict[sOut][sIn]) 70 | , emissionProbabilities: ((s, o) => emissionProbabilitiesDict[s][o]) 71 | ); 72 | 73 | var obsStates = observations 74 | .Zip( 75 | new[] { states }.Repeat(), 76 | (o, ss) => Tuple.Create(o, (IEnumerable)ss)) 77 | .ToObservable() 78 | ; 79 | 80 | obsStates.Subscribe(fbv); 81 | 82 | var finalProbabilities = fbv.V.Last(); 83 | 84 | Assert.AreEqual(Math.Round(finalProbabilities[Rainy], 6), 0.013440d); 85 | Assert.AreEqual(Math.Round(finalProbabilities[Sunny], 6), 0.002592d); 86 | 87 | var mostProbableState = states.ArgMax(y => finalProbabilities[y]); 88 | 89 | Assert.AreEqual(mostProbableState, Rainy); 90 | } 91 | catch (Exception ex) 92 | { 93 | throw ex; 94 | } 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /ViterbiTests/ViterbiTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 7 | 8 | 2.0 9 | {CF26536C-4497-4760-914E-4FCA8F57A283} 10 | Library 11 | Properties 12 | ViterbiTests 13 | ViterbiTests 14 | v4.0 15 | 512 16 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | true 28 | full 29 | false 30 | bin\Debug\ 31 | DEBUG;TRACE 32 | prompt 33 | 4 34 | 35 | 36 | pdbonly 37 | true 38 | bin\Release\ 39 | TRACE 40 | prompt 41 | 4 42 | 43 | 44 | 45 | 46 | 47 | 3.5 48 | 49 | 50 | ..\..\..\..\Main\Monza\Published\ReactiveFramework\System.CoreEx.dll 51 | 52 | 53 | ..\..\..\..\Main\Monza\Published\ReactiveFramework\System.Interactive.dll 54 | 55 | 56 | ..\..\..\..\Main\Monza\Published\ReactiveFramework\System.Reactive.dll 57 | 58 | 59 | 60 | 61 | False 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | {929C6B38-22D8-42EC-8D24-03678DFAF228} 71 | DotNetExtensions 72 | 73 | 74 | {021A5039-3860-49DB-9D6F-B2B8C14497A8} 75 | Viterbi 76 | 77 | 78 | 79 | 86 | -------------------------------------------------------------------------------- /ViterbiTests/bin/Debug/System.CoreEx.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebcabin/DotNetExtensionsImproved/ff493b09393da1ed1fd01c8a85aea2178179dfee/ViterbiTests/bin/Debug/System.CoreEx.dll -------------------------------------------------------------------------------- /ViterbiTests/bin/Debug/System.Interactive.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebcabin/DotNetExtensionsImproved/ff493b09393da1ed1fd01c8a85aea2178179dfee/ViterbiTests/bin/Debug/System.Interactive.dll -------------------------------------------------------------------------------- /ViterbiTests/bin/Debug/System.Reactive.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebcabin/DotNetExtensionsImproved/ff493b09393da1ed1fd01c8a85aea2178179dfee/ViterbiTests/bin/Debug/System.Reactive.dll -------------------------------------------------------------------------------- /ViterbiTests/bin/Release/System.CoreEx.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebcabin/DotNetExtensionsImproved/ff493b09393da1ed1fd01c8a85aea2178179dfee/ViterbiTests/bin/Release/System.CoreEx.dll -------------------------------------------------------------------------------- /ViterbiTests/bin/Release/System.Interactive.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebcabin/DotNetExtensionsImproved/ff493b09393da1ed1fd01c8a85aea2178179dfee/ViterbiTests/bin/Release/System.Interactive.dll -------------------------------------------------------------------------------- /ViterbiTests/bin/Release/System.Reactive.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebcabin/DotNetExtensionsImproved/ff493b09393da1ed1fd01c8a85aea2178179dfee/ViterbiTests/bin/Release/System.Reactive.dll -------------------------------------------------------------------------------- /iSynapticSubset/IMaybe.cs: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | 3 | // Portions Copyright (c) 2011 Jordan E. Terrell, licensed to 4 | // Microsoft Corporation under the MIT license (copied below). 5 | // 6 | // Portions Copyright (c) 2011 Microsoft Corporation 7 | 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | using System; 28 | 29 | // Adapted under terms of the MIT attribution-only license from Jordan E. Terrell. 30 | 31 | namespace Experimental.DotNetExtensions.iSynaptic 32 | { 33 | public interface IMaybe : IMaybe 34 | { 35 | new T Value { get; } 36 | } 37 | 38 | public interface IMaybe 39 | { 40 | object Value { get; } 41 | bool HasValue { get; } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /iSynapticSubset/Maybe.cs: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | 3 | // Portions Copyright (c) 2011 Jordan E. Terrell, licensed to 4 | // Microsoft Corporation under the MIT license (copied below). 5 | // 6 | // Portions Copyright (c) 2011 Microsoft Corporation 7 | 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.ComponentModel; 30 | using System.Diagnostics.Contracts; 31 | using System.Linq; 32 | using System.Threading; 33 | using System.Threading.Tasks; 34 | 35 | namespace Experimental.DotNetExtensions.iSynaptic 36 | { 37 | // Implementation of the Maybe monad. http://en.wikipedia.org/wiki/Monad_%28functional_programming%29#Maybe_monad 38 | // Thanks to Brian Beckman for his suggestions and assistance. 39 | // Don't Fear the Monad! http://channel9.msdn.com/shows/Going+Deep/Brian-Beckman-Dont-fear-the-Monads/ 40 | public struct Maybe : IMaybe, IEquatable>, IEquatable 41 | { 42 | public static readonly Maybe NoValue; 43 | 44 | private readonly T _Value; 45 | private readonly bool _HasValue; 46 | 47 | private readonly Func> _Computation; 48 | 49 | public Maybe(T value) 50 | : this() 51 | { 52 | _Value = value; 53 | _HasValue = value != null; 54 | } 55 | 56 | public Maybe(Func> computation) 57 | : this() 58 | { 59 | var cachedComputation = computation; //Guard.NotNull(computation, "computation"); 60 | var memoizedResult = default(Maybe); 61 | var resultComputed = false; 62 | 63 | _Computation = () => 64 | { 65 | if (resultComputed) 66 | return memoizedResult; 67 | 68 | memoizedResult = cachedComputation(); 69 | resultComputed = true; 70 | cachedComputation = null; 71 | 72 | return memoizedResult; 73 | }; 74 | } 75 | 76 | public T Value 77 | { 78 | get 79 | { 80 | if (_Computation != null) 81 | return _Computation().Value; 82 | 83 | if (typeof(T) == typeof(Unit) || _HasValue) 84 | return _Value; 85 | 86 | throw new InvalidOperationException("No value can be computed."); 87 | } 88 | } 89 | 90 | object IMaybe.Value 91 | { 92 | get { return Value; } 93 | } 94 | 95 | public bool HasValue 96 | { 97 | get 98 | { 99 | if (_Computation != null) 100 | return _Computation().HasValue; 101 | 102 | return typeof(T) == typeof(Unit) || 103 | _HasValue; 104 | } 105 | } 106 | 107 | public bool Equals(T other) 108 | { 109 | return Equals(other, EqualityComparer.Default); 110 | } 111 | 112 | public bool Equals(T other, IEqualityComparer comparer) 113 | { 114 | return Equals(new Maybe(other), comparer); 115 | } 116 | 117 | public bool Equals(Maybe other) 118 | { 119 | return Equals(other, EqualityComparer.Default); 120 | } 121 | 122 | public bool Equals(Maybe other, IEqualityComparer comparer) 123 | { 124 | //Guard.NotNull(comparer, "comparer"); 125 | 126 | if (!HasValue) 127 | return !other.HasValue; 128 | 129 | return other.HasValue && comparer.Equals(Value, other.Value); 130 | } 131 | 132 | public override bool Equals(object obj) 133 | { 134 | if (obj is Maybe) 135 | return Equals((Maybe)obj); 136 | 137 | if (obj is T) 138 | return Equals(new Maybe((T)obj)); 139 | 140 | return false; 141 | } 142 | 143 | public override int GetHashCode() 144 | { 145 | return GetHashCode(EqualityComparer.Default); 146 | } 147 | 148 | public int GetHashCode(IEqualityComparer comparer) 149 | { 150 | // Guard.NotNull(comparer, "comparer"); 151 | 152 | return HasValue 153 | ? comparer.GetHashCode(Value) 154 | : 0; 155 | } 156 | 157 | public static bool operator ==(Maybe left, Maybe right) 158 | { 159 | return left.Equals(right); 160 | } 161 | 162 | public static bool operator !=(Maybe left, Maybe right) 163 | { 164 | return !(left == right); 165 | } 166 | 167 | public static bool operator ==(Maybe left, T right) 168 | { 169 | return left.Equals(right); 170 | } 171 | 172 | public static bool operator !=(Maybe left, T right) 173 | { 174 | return !(left == right); 175 | } 176 | 177 | public static bool operator ==(T left, Maybe right) 178 | { 179 | return right.Equals(left); 180 | } 181 | 182 | public static bool operator !=(T left, Maybe right) 183 | { 184 | return !(left == right); 185 | } 186 | 187 | public static explicit operator T(Maybe value) 188 | { 189 | return value.Value; 190 | } 191 | 192 | public static implicit operator Maybe(Maybe value) 193 | { 194 | return new Maybe(); 195 | } 196 | } 197 | 198 | public static class Maybe 199 | { 200 | #region Defer Operator 201 | 202 | public static Maybe Defer(Func computation) 203 | { 204 | //Guard.NotNull(computation, "computation"); 205 | 206 | return new Maybe(() => new Maybe(computation())); 207 | } 208 | 209 | public static Maybe Defer(Func computation) where T : struct 210 | { 211 | //Guard.NotNull(computation, "computation"); 212 | 213 | return new Maybe(() => Return(computation())); 214 | } 215 | 216 | public static Maybe Defer(Func> computation) 217 | { 218 | return new Maybe(computation); 219 | } 220 | 221 | #endregion 222 | 223 | #region If Operator 224 | 225 | public static Maybe If(bool predicate, Maybe thenValue) 226 | { 227 | return predicate ? thenValue : NoValue; 228 | } 229 | 230 | public static Maybe If(bool predicate, Maybe thenValue, Maybe elseValue) 231 | { 232 | return predicate ? thenValue : elseValue; 233 | } 234 | 235 | public static Maybe If(Func predicate, Maybe thenValue) 236 | { 237 | //Guard.NotNull(predicate, "predicate"); 238 | return new Maybe(() => predicate() ? thenValue : NoValue); 239 | } 240 | 241 | public static Maybe If(Func predicate, Maybe thenValue, Maybe elseValue) 242 | { 243 | //Guard.NotNull(predicate, "predicate"); 244 | return new Maybe(() => predicate() ? thenValue : elseValue); 245 | } 246 | 247 | #endregion 248 | 249 | #region Using Operator 250 | 251 | public static Maybe Using(Func resourceFactory, Func> selector) where TResource : IDisposable 252 | { 253 | //Guard.NotNull(resourceFactory, "resourceFactory"); 254 | //Guard.NotNull(selector, "selector"); 255 | 256 | return new Maybe(() => 257 | { 258 | using (var resource = resourceFactory()) 259 | return selector(resource); 260 | }); 261 | } 262 | 263 | public static Maybe Using(this Maybe @this, Func resourceSelector, Func> selector) where TResource : IDisposable 264 | { 265 | //Guard.NotNull(resourceSelector, "resourceSelector"); 266 | //Guard.NotNull(selector, "selector"); 267 | 268 | return @this.SelectMaybe(x => 269 | { 270 | using (var resource = resourceSelector(x)) 271 | return selector(resource); 272 | }); 273 | } 274 | 275 | #endregion 276 | 277 | #region ValueOrDefault Operator 278 | 279 | public static T ValueOrDefault(this Maybe @this, Func @default) 280 | { 281 | return @this.HasValue 282 | ? @this.Value 283 | : @default(); 284 | } 285 | 286 | public static T ValueOrDefault(this Maybe @this, T @default) 287 | { 288 | return @this.HasValue 289 | ? @this.Value 290 | : @default; 291 | } 292 | 293 | public static T ValueOrDefault(this Maybe @this) 294 | { 295 | return @this.ValueOrDefault(default(T)); 296 | } 297 | 298 | #endregion 299 | 300 | #region Or Operator 301 | 302 | public static Maybe Or(this Maybe @this, T value) 303 | { 304 | var self = @this; 305 | return new Maybe(() => self.HasValue ? self : new Maybe(value)); 306 | } 307 | 308 | public static Maybe Or(this Maybe @this, Func valueFactory) 309 | { 310 | //Guard.NotNull(valueFactory, "valueFactory"); 311 | 312 | var self = @this; 313 | return new Maybe(() => self.HasValue ? self : new Maybe(valueFactory())); 314 | } 315 | 316 | public static Maybe Or(this Maybe @this, Func> valueFactory) 317 | { 318 | //Guard.NotNull(valueFactory, "valueFactory"); 319 | 320 | var self = @this; 321 | return new Maybe(() => self.HasValue ? self : valueFactory()); 322 | } 323 | 324 | public static Maybe Or(this Maybe @this, Maybe other) 325 | { 326 | var self = @this; 327 | return new Maybe(() => self.HasValue ? self : other); 328 | } 329 | 330 | #endregion 331 | 332 | #region With Operator 333 | 334 | public static Maybe With(this Maybe @this, Func selector, Action action) 335 | { 336 | //Guard.NotNull(selector, "selector"); 337 | //Guard.NotNull(action, "action"); 338 | 339 | var self = @this; 340 | 341 | return new Maybe(() => 342 | { 343 | if (self.HasValue) 344 | action(selector(self.Value)); 345 | 346 | return self; 347 | }); 348 | } 349 | 350 | public static Maybe With(this Maybe @this, Func> selector, Action action) 351 | { 352 | //Guard.NotNull(selector, "selector"); 353 | //Guard.NotNull(action, "action"); 354 | 355 | var self = @this; 356 | 357 | return new Maybe(() => 358 | { 359 | if (self.HasValue) 360 | { 361 | var selected = selector(self.Value); 362 | if (selected.HasValue) 363 | action(selected.Value); 364 | } 365 | 366 | return self; 367 | }); 368 | } 369 | 370 | #endregion 371 | 372 | #region When Operator 373 | 374 | public static Maybe When(this Maybe @this, T value, Action action) 375 | { 376 | //Guard.NotNull(action, "action"); 377 | 378 | var self = @this; 379 | return new Maybe(() => 380 | { 381 | if (self.HasValue && EqualityComparer.Default.Equals(self.Value, value)) 382 | action(self.Value); 383 | 384 | return self; 385 | }); 386 | } 387 | 388 | public static Maybe When(this Maybe @this, T value, Maybe newValue) 389 | { 390 | var self = @this; 391 | return new Maybe(() => 392 | { 393 | if (self.HasValue && EqualityComparer.Default.Equals(self.Value, value)) 394 | return newValue; 395 | 396 | return self; 397 | }); 398 | } 399 | 400 | public static Maybe When(this Maybe @this, Func predicate, Action action) 401 | { 402 | //Guard.NotNull(predicate, "predicate"); 403 | //Guard.NotNull(action, "action"); 404 | 405 | var self = @this; 406 | return new Maybe(() => 407 | { 408 | if (self.HasValue && predicate(self.Value)) 409 | action(self.Value); 410 | 411 | return self; 412 | }); 413 | } 414 | 415 | public static Maybe When(this Maybe @this, Func predicate, Maybe newValue) 416 | { 417 | //Guard.NotNull(predicate, "predicate"); 418 | 419 | var self = @this; 420 | return new Maybe(() => 421 | { 422 | if (self.HasValue && predicate(self.Value)) 423 | return newValue; 424 | 425 | return self; 426 | }); 427 | } 428 | 429 | public static Maybe When(this Maybe @this, Func predicate, Func> selector) 430 | { 431 | //Guard.NotNull(predicate, "predicate"); 432 | //Guard.NotNull(selector, "selector"); 433 | 434 | var self = @this; 435 | return new Maybe(() => 436 | { 437 | if (self.HasValue && predicate(self.Value)) 438 | return selector(self.Value); 439 | 440 | return self; 441 | }); 442 | } 443 | 444 | #endregion 445 | 446 | #region Suppress Operator 447 | 448 | public static Maybe Suppress(this Maybe @this, Action action = null) 449 | { 450 | var self = @this; 451 | return new Maybe(() => 452 | { 453 | try 454 | { 455 | return self.HasValue 456 | ? self 457 | : self; 458 | } 459 | catch (Exception ex) 460 | { 461 | if (action != null) 462 | action(ex); 463 | 464 | return NoValue; 465 | } 466 | }); 467 | } 468 | 469 | public static Maybe Suppress(this Maybe @this, Func predicate) 470 | { 471 | //Guard.NotNull(predicate, "predicate"); 472 | 473 | var self = @this; 474 | return new Maybe(() => 475 | { 476 | try 477 | { 478 | return self.HasValue 479 | ? self 480 | : self; 481 | } 482 | catch (Exception ex) 483 | { 484 | if (predicate(ex)) 485 | return NoValue; 486 | 487 | throw; 488 | } 489 | }); 490 | } 491 | 492 | public static Maybe Suppress(this Maybe @this, T value) 493 | { 494 | var self = @this; 495 | return new Maybe(() => 496 | { 497 | try 498 | { 499 | return self.HasValue 500 | ? self 501 | : self; 502 | } 503 | catch 504 | { 505 | return new Maybe(value); 506 | } 507 | }); 508 | } 509 | 510 | public static Maybe Suppress(this Maybe @this, Func predicate, T value) 511 | { 512 | //Guard.NotNull(predicate, "predicate"); 513 | 514 | var self = @this; 515 | return new Maybe(() => 516 | { 517 | try 518 | { 519 | return self.HasValue 520 | ? self 521 | : self; 522 | } 523 | catch (Exception ex) 524 | { 525 | if (predicate(ex)) 526 | return new Maybe(value); 527 | 528 | throw; 529 | } 530 | }); 531 | } 532 | 533 | public static Maybe Suppress(this Maybe @this, Func predicate, Func> selector) 534 | { 535 | //Guard.NotNull(predicate, "predicate"); 536 | //Guard.NotNull(selector, "selector"); 537 | 538 | var self = @this; 539 | return new Maybe(() => 540 | { 541 | try 542 | { 543 | return self.HasValue 544 | ? self 545 | : self; 546 | } 547 | catch (Exception ex) 548 | { 549 | if (predicate(ex)) 550 | return selector(ex); 551 | 552 | throw; 553 | } 554 | }); 555 | } 556 | 557 | 558 | #endregion 559 | 560 | #region Join Operator 561 | 562 | public static Maybe> Join(this Maybe @this, Maybe other) 563 | { 564 | var self = @this; 565 | return new Maybe>(() => self.HasValue && other.HasValue 566 | ? new Maybe>(Tuple.Create(self.Value, other.Value)) 567 | : NoValue); 568 | } 569 | 570 | public static Maybe Join(this Maybe @this, Maybe other, Func selector) 571 | { 572 | //Guard.NotNull(selector, "selector"); 573 | 574 | var self = @this; 575 | return new Maybe(() => self.HasValue && other.HasValue 576 | ? new Maybe(selector(self.Value, other.Value)) 577 | : NoValue); 578 | } 579 | 580 | public static Maybe Join(this Maybe @this, Maybe other, Func selector) where TResult : struct 581 | { 582 | //Guard.NotNull(selector, "selector"); 583 | 584 | var self = @this; 585 | return new Maybe(() => self.HasValue && other.HasValue 586 | ? Return(selector(self.Value, other.Value)) 587 | : NoValue); 588 | } 589 | 590 | public static Maybe Join(this Maybe @this, Maybe other, Func> selector) 591 | { 592 | //Guard.NotNull(selector, "selector"); 593 | 594 | var self = @this; 595 | return new Maybe(() => self.HasValue && other.HasValue 596 | ? selector(self.Value, other.Value) 597 | : NoValue); 598 | } 599 | 600 | #endregion 601 | 602 | #region ThrowOnNoValue Operator 603 | 604 | public static Maybe ThrowOnNoValue(this Maybe @this, Exception exception) 605 | { 606 | //Guard.NotNull(exception, "exception"); 607 | 608 | var self = @this; 609 | return new Maybe(() => 610 | { 611 | if (self.HasValue != true) 612 | throw exception; 613 | 614 | return self; 615 | }); 616 | } 617 | 618 | public static Maybe ThrowOnNoValue(this Maybe @this, Func exceptionFactory) 619 | { 620 | //Guard.NotNull(exceptionFactory, "exceptionFactory"); 621 | 622 | var self = @this; 623 | return new Maybe(() => 624 | { 625 | if (self.HasValue != true) 626 | throw exceptionFactory(); 627 | 628 | return self; 629 | }); 630 | } 631 | 632 | #endregion 633 | 634 | #region ThrowOn Operator 635 | 636 | public static Maybe ThrowOn(this Maybe @this, T value, Exception exception) 637 | { 638 | //Guard.NotNull(exception, "exception"); 639 | 640 | var self = @this; 641 | return new Maybe(() => 642 | { 643 | if (self.HasValue && EqualityComparer.Default.Equals(self.Value, value)) 644 | throw exception; 645 | 646 | return self; 647 | }); 648 | } 649 | 650 | public static Maybe ThrowOn(this Maybe @this, Func, Exception> exceptionSelector) 651 | { 652 | //Guard.NotNull(exceptionSelector, "exceptionSelector"); 653 | 654 | var self = @this; 655 | return new Maybe(() => 656 | { 657 | var ex = exceptionSelector(self); 658 | if (ex != null) 659 | throw ex; 660 | 661 | return self; 662 | }); 663 | } 664 | 665 | #endregion 666 | 667 | #region ToEnumerable Operator 668 | 669 | public static IEnumerable ToEnumerable(this Maybe @this) 670 | { 671 | if (@this.HasValue) 672 | yield return @this.Value; 673 | } 674 | 675 | public static IEnumerable ToEnumerable(params Maybe[] values) 676 | { 677 | //Guard.NotNull(values, "values"); 678 | return values 679 | .Where(x => x.HasValue) 680 | .Select(x => x.Value); 681 | } 682 | 683 | public static IEnumerable ToEnumerable(this Maybe @this, IEnumerable> others) 684 | { 685 | //Guard.NotNull(others, "others"); 686 | 687 | return new[] { @this }.Concat(others) 688 | .Where(x => x.HasValue) 689 | .Select(x => x.Value); 690 | } 691 | 692 | #endregion 693 | 694 | #region Squash Operator 695 | 696 | public static Maybe Squash(this IMaybe> @this) 697 | { 698 | var self = @this; 699 | return new Maybe(() => 700 | { 701 | if (self == null) 702 | return NoValue; 703 | 704 | return self.HasValue 705 | ? self.Value.Cast() 706 | : NoValue; 707 | }); 708 | } 709 | 710 | public static IEnumerable Squash(this IMaybe> @this) 711 | { 712 | if (@this == null || @this.HasValue != true || @this.Value == null) 713 | yield break; 714 | 715 | foreach (var item in @this.Value) 716 | yield return item; 717 | } 718 | 719 | public static Maybe Squash(this Maybe> @this) 720 | { 721 | var self = @this; 722 | 723 | return new Maybe(() => self.HasValue 724 | ? self.Value 725 | : NoValue); 726 | } 727 | 728 | public static IEnumerable Squash(this Maybe> @this) 729 | { 730 | foreach (var item in @this.ValueOrDefault(Enumerable.Empty())) 731 | yield return item; 732 | } 733 | 734 | #endregion 735 | 736 | public static Maybe NoValue 737 | { 738 | get { return new Maybe(); } 739 | } 740 | 741 | public static Maybe Return(T value) 742 | { 743 | return new Maybe(value); 744 | } 745 | 746 | public static Maybe Return(T? value) where T : struct 747 | { 748 | return value.HasValue 749 | ? new Maybe(value.Value) 750 | : NoValue; 751 | } 752 | 753 | public static Maybe Bind(this Maybe @this, Func> selector) 754 | { 755 | return SelectMaybe(@this, selector); 756 | } 757 | 758 | public static Maybe Let(this Maybe @this, Func, Maybe> func) 759 | { 760 | //Guard.NotNull(func, "func"); 761 | 762 | var self = @this; 763 | return new Maybe(() => func(self)); 764 | } 765 | 766 | public static Maybe Select(this Maybe @this, Func selector) 767 | { 768 | //Guard.NotNull(selector, "selector"); 769 | 770 | var self = @this; 771 | 772 | return new Maybe(() => self.HasValue ? new Maybe(selector(self.Value)) : NoValue); 773 | } 774 | 775 | public static Maybe Select(this Maybe @this, Func selector) where TResult : struct 776 | { 777 | //Guard.NotNull(selector, "selector"); 778 | 779 | var self = @this; 780 | 781 | return new Maybe(() => self.HasValue ? Return(selector(self.Value)) : NoValue); 782 | } 783 | 784 | public static Maybe TrySelect(TrySelector selector) 785 | { 786 | //Guard.NotNull(selector, "selector"); 787 | 788 | return new Maybe(() => 789 | { 790 | TResult result = default(TResult); 791 | 792 | return selector(out result) 793 | ? new Maybe(result) 794 | : NoValue; 795 | }); 796 | } 797 | 798 | public static Maybe TrySelect(this Maybe @this, TrySelector selector) 799 | { 800 | //Guard.NotNull(selector, "selector"); 801 | 802 | var self = @this; 803 | 804 | return new Maybe(() => 805 | { 806 | if (!self.HasValue) 807 | return NoValue; 808 | 809 | TResult result = default(TResult); 810 | 811 | return selector(self.Value, out result) 812 | ? new Maybe(result) 813 | : NoValue; 814 | }); 815 | } 816 | 817 | // This functionally is the same as Bind and SelectMany. Since SelectMany doesn't make sense (because there is at most one value), 818 | // the name SelectMaybe communicates better than Bind or SelectMany the semantics of the function. 819 | public static Maybe SelectMaybe(this Maybe @this, Func> selector) 820 | { 821 | //Guard.NotNull(selector, "selector"); 822 | 823 | var self = @this; 824 | 825 | return new Maybe(() => self.HasValue ? selector(self.Value) : NoValue); 826 | } 827 | 828 | public static Maybe Throw(Exception exception) 829 | { 830 | //Guard.NotNull(exception, "exception"); 831 | return new Maybe(() => { throw exception; }); 832 | } 833 | 834 | public static Maybe Throw(Exception exception) 835 | { 836 | //Guard.NotNull(exception, "exception"); 837 | return new Maybe(() => { throw exception; }); 838 | } 839 | 840 | public static Maybe Finally(this Maybe @this, Action finallyAction) 841 | { 842 | //Guard.NotNull(finallyAction, "finallyAction"); 843 | 844 | var self = @this; 845 | return new Maybe(() => 846 | { 847 | try 848 | { 849 | return self.HasValue ? self : self; 850 | } 851 | finally 852 | { 853 | finallyAction(); 854 | } 855 | }); 856 | } 857 | 858 | public static Maybe OnValue(this Maybe @this, Action action) 859 | { 860 | //Guard.NotNull(action, "action"); 861 | 862 | var self = @this; 863 | return new Maybe(() => 864 | { 865 | if (self.HasValue) 866 | action(self.Value); 867 | 868 | return self; 869 | }); 870 | } 871 | 872 | public static Maybe OnNoValue(this Maybe @this, Action action) 873 | { 874 | //Guard.NotNull(action, "action"); 875 | 876 | var self = @this; 877 | return new Maybe(() => 878 | { 879 | if (self.HasValue != true) 880 | action(); 881 | 882 | return self; 883 | }); 884 | } 885 | 886 | public static Maybe OnException(this Maybe @this, Action handler) 887 | { 888 | //Guard.NotNull(handler, "handler"); 889 | var self = @this; 890 | 891 | return new Maybe(() => 892 | { 893 | try 894 | { 895 | return self.HasValue 896 | ? self 897 | : self; 898 | } 899 | catch (Exception ex) 900 | { 901 | handler(ex); 902 | throw; 903 | } 904 | }); 905 | } 906 | 907 | public static Maybe Where(this Maybe @this, Func predicate) 908 | { 909 | //Guard.NotNull(predicate, "predicate"); 910 | var self = @this; 911 | 912 | return new Maybe(() => 913 | { 914 | if (self.HasValue) 915 | { 916 | var value = self.Value; 917 | 918 | if (predicate(value)) 919 | return self; 920 | } 921 | 922 | return NoValue; 923 | }); 924 | } 925 | 926 | public static Maybe Unless(this Maybe @this, Func predicate) 927 | { 928 | //Guard.NotNull(predicate, "predicate"); 929 | var self = @this; 930 | 931 | return new Maybe(() => 932 | { 933 | if (self.HasValue) 934 | { 935 | var value = self.Value; 936 | 937 | if (!predicate(value)) 938 | return self; 939 | } 940 | 941 | return NoValue; 942 | }); 943 | } 944 | 945 | public static Maybe Assign(this Maybe @this, ref T target) 946 | { 947 | if (@this.HasValue) 948 | target = @this.Value; 949 | 950 | return @this; 951 | } 952 | 953 | public static Maybe Run(this Maybe @this, Action action = null) 954 | { 955 | // Getting HasValue forces evaluation 956 | if (@this.HasValue && action != null) 957 | action(@this.Value); 958 | 959 | return @this; 960 | } 961 | 962 | public static Maybe RunAsync(this Maybe @this, Action action = null, CancellationToken cancellationToken = default(CancellationToken), TaskCreationOptions taskCreationOptions = TaskCreationOptions.None, TaskScheduler taskScheduler = default(TaskScheduler)) 963 | { 964 | var self = @this; 965 | var task = Task.Factory.StartNew(() => self.Run(action), cancellationToken, taskCreationOptions, taskScheduler ?? TaskScheduler.Current); 966 | 967 | return new Maybe(() => 968 | { 969 | task.Wait(cancellationToken); 970 | return task.IsCanceled ? NoValue : self; 971 | }); 972 | } 973 | 974 | public static Maybe Synchronize(this Maybe @this) 975 | { 976 | return Synchronize(@this, new object()); 977 | } 978 | 979 | public static Maybe Synchronize(this Maybe @this, object gate) 980 | { 981 | //Guard.NotNull(gate, "gate"); 982 | 983 | var self = @this; 984 | return new Maybe(() => 985 | { 986 | lock (gate) 987 | { 988 | return self.Run(); 989 | } 990 | }); 991 | } 992 | 993 | public static Maybe Cast(this IMaybe @this) 994 | { 995 | if (@this == null) 996 | return NoValue; 997 | 998 | if (@this is Maybe) 999 | return (Maybe)@this; 1000 | 1001 | return new Maybe(() => @this.HasValue 1002 | ? new Maybe((TResult)@this.Value) 1003 | : NoValue); 1004 | } 1005 | 1006 | public static Maybe OfType(this IMaybe @this) 1007 | { 1008 | if (@this == null) 1009 | return NoValue; 1010 | 1011 | if (@this is Maybe) 1012 | return (Maybe)@this; 1013 | 1014 | return new Maybe(() => 1015 | { 1016 | if (@this.HasValue != true) 1017 | return NoValue; 1018 | 1019 | return @this.Value is TResult 1020 | ? new Maybe((TResult)@this.Value) 1021 | : NoValue; 1022 | }); 1023 | } 1024 | 1025 | public static T? ToNullable(this Maybe @this) where T : struct 1026 | { 1027 | return @this.HasValue ? (T?)@this.Value : null; 1028 | } 1029 | 1030 | public static T? ToNullable(this Maybe @this) where T : struct 1031 | { 1032 | return @this.HasValue ? @this.Value : null; 1033 | } 1034 | 1035 | // Conventionally, in LINQ, the monadic "return" operator is written "To...," 1036 | // as in "ToList," "ToArray," etc. These are synonyms for Return. 1037 | public static Maybe ToMaybe(this T @this) 1038 | { 1039 | return new Maybe(@this); 1040 | } 1041 | 1042 | public static Maybe ToMaybe(this T? @this) where T : struct 1043 | { 1044 | return @this.HasValue 1045 | ? new Maybe(@this.Value) 1046 | : NoValue; 1047 | } 1048 | 1049 | public static Maybe ToMaybe(this object @this) 1050 | { 1051 | if (@this is T) 1052 | return new Maybe((T)@this); 1053 | 1054 | if (@this == null && typeof(T).IsValueType != true) 1055 | return new Maybe(default(T)); 1056 | 1057 | return NoValue; 1058 | } 1059 | 1060 | public static Maybe AsMaybe(this IMaybe value) 1061 | { 1062 | return value.OfType(); 1063 | } 1064 | 1065 | public static Maybe AsMaybe(this IMaybe value) 1066 | { 1067 | return value.OfType(); 1068 | } 1069 | } 1070 | } 1071 | -------------------------------------------------------------------------------- /iSynapticSubset/State.cs: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | 3 | // Portions Copyright (c) 2011 Jordan E. Terrell, licensed to 4 | // Microsoft Corporation under the MIT license (copied below). 5 | // 6 | // Portions Copyright (c) 2011 Microsoft Corporation 7 | 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | using System; 28 | using System.ComponentModel; 29 | using System.Diagnostics.Contracts; 30 | 31 | namespace Experimental.DotNetExtensions 32 | { 33 | 34 | /// 35 | /// Factory class for ValueStatePair objects 36 | /// 37 | public static class ValueStatePair 38 | { 39 | /// 40 | /// Creates a value-state pair 41 | /// 42 | /// The type of the value object. 43 | /// The type of the state object. 44 | /// The value object to store in the pair. 45 | /// The state object to store in the pair. 46 | /// The newly created value-state pair. 47 | public static ValueStatePair Create(T value, S state) 48 | { 49 | return new ValueStatePair(value, state); 50 | } 51 | } 52 | /// 53 | /// Represents a tuple of a value and state. 54 | /// 55 | /// The type of the value object. 56 | /// The type of the state object. 57 | public struct ValueStatePair 58 | { 59 | /// 60 | /// Constructor 61 | /// 62 | /// The value object to store in the pair. 63 | /// The state object to store in the pair. 64 | public ValueStatePair(T value, S state) 65 | : this() 66 | { 67 | Value = value; 68 | State = state; 69 | } 70 | 71 | public T Value { get; private set; } 72 | public S State { get; private set; } 73 | } 74 | 75 | /// 76 | /// Encapsulates a propagator transform that combines a mutable state object 77 | /// with a value, usually via closure. 78 | /// 79 | /// The type of state object to propagate. 80 | /// The type of values included with propagated state. 81 | public struct State 82 | { 83 | // Haskell does not require a name for the function "inside" the 84 | // state monad that moves the state along, but we do. Let's call it 85 | // a Propagator: 86 | 87 | /// 88 | /// The content of a State is the propagator function that combines a 89 | /// mutable state object with a value. 90 | /// 91 | public readonly Func> Propagator; 92 | 93 | /// 94 | /// Constructor. 95 | /// 96 | /// The input propagator. 97 | public State(Func> propagator) 98 | : this() 99 | { 100 | Contract.Requires(null != propagator, "propagator"); 101 | Contract.Ensures(Propagator != null, "Propagator"); 102 | Propagator = propagator; 103 | } 104 | } 105 | 106 | /// 107 | /// Encapsulates a propagator transform that combines a mutable state object 108 | /// with a value, usually via closure. 109 | /// 110 | public static class State 111 | { 112 | /// 113 | /// Produces a State with a trivial propagator: a closure over the given value. 114 | /// 115 | /// The type of state object to propagate. 116 | /// The type of values included with propagated state. 117 | /// The value to include with the propagated state. 118 | /// A State encapsulating the propagator closure. 119 | public static State Return(T value) 120 | { 121 | // value is allowed to be null, but it's better if it's a Maybe (TODO)! 122 | return new State(propagator: s => ValueStatePair.Create(value, s)); 123 | } 124 | 125 | // Conventionally, in LINQ, the monadic "return" operator is written "To...," 126 | // as in "ToList," "ToArray," etc. These are synonyms for Return. 127 | 128 | /// 129 | /// Converts a value int a State with a trivial propagator: a closure over the given value. 130 | /// 131 | /// The type of state object to propagate. 132 | /// The type of values included with propagated state. 133 | /// The value to include with the propagated state. 134 | /// A State encapsulating the propagator closure. 135 | public static State ToState( 136 | this T value) 137 | { 138 | // value is allowed to be null, but it's better if it's a Maybe (TODO)! 139 | return State.Return(value); 140 | } 141 | 142 | /// 143 | /// Produces a State that chains an input propagator through a transform 144 | /// that produces a second propagator. 145 | /// 146 | /// The type of state object to propagate through the chain. 147 | /// The type of value included with propagated state in the first link of the chain. 148 | /// The type of value included with propagated state in the second link of the chain. 149 | /// A State whose propagator includes values of type T. 150 | /// A function that converts values of type T to States whose propagators include values of type U. 151 | /// A State whose propagator includes values of type U. 152 | public static State Bind( 153 | this State st, 154 | Func> t2su) 155 | { 156 | Contract.Requires(null != st.Propagator, "mt.Propagator"); 157 | Contract.Requires(null != t2su, "t2mu"); 158 | 159 | var self = st; 160 | 161 | return new State( 162 | propagator: s => 163 | { 164 | var intermediate = self.Propagator(s); 165 | var tNuValue = intermediate.Value; 166 | var sNuState = intermediate.State; 167 | 168 | return t2su(tNuValue).Propagator(sNuState); 169 | }); 170 | } 171 | 172 | #region SelectMany Operator 173 | 174 | // This operator is implemented only to satisfy C#'s LINQ comprehension syntax. 175 | // The name "SelectMany" is confusing as there is only one value to "select". 176 | [EditorBrowsable(EditorBrowsableState.Never)] 177 | public static State SelectMany( 178 | this State mt, 179 | Func> t2mu) 180 | { 181 | Contract.Requires(null != mt.Propagator, "mt.Propagator"); 182 | Contract.Requires(null != t2mu, "t2mu"); 183 | 184 | return mt.Bind(t2mu); 185 | } 186 | 187 | // This operator is implemented only to satisfy C#'s LINQ comprehension syntax. 188 | // The name "SelectMany" is confusing as there is only one value to "select". 189 | [EditorBrowsable(EditorBrowsableState.Never)] 190 | public static State SelectMany( 191 | this State mt, 192 | Func> t2mu, 193 | Func t2u2v) 194 | { 195 | Contract.Requires(null != t2mu, "t2mu"); 196 | Contract.Requires(null != t2u2v, "t2u2v"); 197 | 198 | return mt.Bind(t => t2mu(t).Bind(u => t2u2v(t, u).ToState())); 199 | } 200 | 201 | #endregion 202 | } 203 | } -------------------------------------------------------------------------------- /iSynapticSubset/TrySelector.cs: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | 3 | // Portions Copyright (c) 2011 Jordan E. Terrell, licensed to 4 | // Microsoft Corporation under the MIT license (copied below). 5 | // 6 | // Portions Copyright (c) 2011 Microsoft Corporation 7 | 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | using System; 28 | using System.Collections.Generic; 29 | using System.Linq; 30 | using System.Text; 31 | 32 | namespace Experimental.DotNetExtensions.iSynaptic 33 | { 34 | public delegate bool TrySelector(out TResult result); 35 | public delegate bool TrySelector(T input, out TResult result); 36 | } 37 | -------------------------------------------------------------------------------- /iSynapticSubset/Unit.cs: -------------------------------------------------------------------------------- 1 | // The MIT License 2 | 3 | // Portions Copyright (c) 2011 Jordan E. Terrell, licensed to 4 | // Microsoft Corporation under the MIT license (copied below). 5 | // 6 | // Portions Copyright (c) 2011 Microsoft Corporation 7 | 8 | // Permission is hereby granted, free of charge, to any person obtaining 9 | // a copy of this software and associated documentation files (the 10 | // "Software"), to deal in the Software without restriction, including 11 | // without limitation the rights to use, copy, modify, merge, publish, 12 | // distribute, sublicense, and/or sell copies of the Software, and to 13 | // permit persons to whom the Software is furnished to do so, subject to 14 | // the following conditions: 15 | 16 | // The above copyright notice and this permission notice shall be 17 | // included in all copies or substantial portions of the Software. 18 | 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | 27 | using System; 28 | 29 | namespace Experimental.DotNetExtensions.iSynaptic 30 | { 31 | public struct Unit : IEquatable 32 | { 33 | public bool Equals(Unit other) 34 | { 35 | return true; 36 | } 37 | 38 | public override bool Equals(object obj) 39 | { 40 | if (ReferenceEquals(obj, null)) 41 | return false; 42 | 43 | return obj is Unit; 44 | } 45 | 46 | public override int GetHashCode() 47 | { 48 | return 0; 49 | } 50 | 51 | public static bool operator ==(Unit left, Unit right) 52 | { 53 | return left.Equals(right); 54 | } 55 | 56 | public static bool operator !=(Unit left, Unit right) 57 | { 58 | return !(left == right); 59 | } 60 | } 61 | } --------------------------------------------------------------------------------