/* Copyright (c) Microsoft Corporation All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. */ // // � Microsoft Corporation. All rights reserved. // using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Globalization; using System.Reflection; using System.Linq.Expressions; using System.Linq; using Microsoft.Research.DryadLinq.Internal; namespace Microsoft.Research.DryadLinq { /// /// This provides some useful classes and operators that are commonly used /// in applications. The operators are defined using DryadLINQ operators. /// [Serializable] public struct Pair : IEquatable> { private T1 m_key; private T2 m_value; [FieldMapping("x", "Key")] [FieldMapping("y", "Value")] public Pair(T1 x, T2 y) { this.m_key = x; this.m_value = y; } public T1 Key { get { return this.m_key; } } public T2 Value { get { return this.m_value; } } public override bool Equals(Object obj) { if (!(obj is Pair)) return false; Pair pair = (Pair)obj; return this.m_key.Equals(pair.Key) && this.m_value.Equals(pair.Value); } public bool Equals(Pair val) { return this.m_key.Equals(val.Key) && this.m_value.Equals(val.Value); } public static bool Equals(Pair a, Pair b) { return a.Equals(b); } public static bool operator ==(Pair a, Pair b) { return a.Equals(b); } public static bool operator !=(Pair a, Pair b) { return !a.Equals(b); } public override int GetHashCode() { return (-1521134295 * this.m_key.GetHashCode()) + this.m_value.GetHashCode(); } public override string ToString() { return "<" + this.Key + ", " + this.Value + ">"; } } public static class HpcLinqExtension { /// /// The standard MapReduce. /// /// The type of the records of input dataset /// The type of the resulting records of mapper /// The type of the keys for hash exchange /// The type of the resulting records of reducer /// The input dataset /// The map function /// The key extraction function /// The reduce function /// The result dataset of MapReduce public static IQueryable MapReduce( this IQueryable source, Expression>> mapper, Expression> keySelector, Expression, TResult>> reducer) { return source.SelectMany(mapper).GroupBy(keySelector, reducer); } /// /// Compute the cross product of two datasets. The function procFunc is applied to each /// pair of the cross product to form the output dataset. /// /// The type of the records of dataset source1 /// The type of the records of dataset source2 /// The type of the records of the result dataset /// The first input dataset /// The second input dataset /// The function to apply to each pair of the cross product /// The output dataset public static IQueryable CrossProduct(this IQueryable source1, IQueryable source2, Expression> procFunc) { return source1.ApplyPerPartition(source2, (x_1, y_1) => HpcLinqHelper.Cross(x_1, y_1, procFunc), true); } /// /// Conditional DoWhile loop. /// /// The type of the input records /// The input dataset /// The code body of the DoWhile loop /// The termination condition of the DoWhile loop /// The output dataset public static IQueryable DoWhile(this IQueryable source, Func, IQueryable> body, Func, IQueryable, IQueryable> cond, Int32 count) { if (count < 0) { throw new ArgumentOutOfRangeException("count"); } if (count == 0) return source; IQueryable before = source; while (true) { IQueryable after = before; for (int i = 0; i < count; i++) { after = body(after); } var more = cond(before, after); HpcLinqQueryable.SubmitAndWait(after, more); if (!more.Single()) return after; before = after; } } /// /// Conditional DoWhile loop. /// /// The type of the input records /// The input dataset /// The code body of the DoWhile loop /// The termination condition of the DoWhile loop /// The output dataset public static IQueryable DoWhile(this IQueryable source, Func, IQueryable> body, Func, IQueryable, IQueryable> cond) { IQueryable before = source; while (true) { IQueryable after = body(before); var more = cond(before, after); HpcLinqQueryable.SubmitAndWait(after, more); if (!more.Single()) return after; before = after; } } /// /// Broadcast a dataset to multiple partitions /// /// The type of the input records /// The input dataset /// The output dataset, which consists of multiple copies of source public static IQueryable BroadCast(this IQueryable source) { return source.ApplyPerPartition(source, (x, y) => HpcLinqHelper.SelectSecond(x, y), true); } /// /// Broadcast a dataset to n partitions. /// /// The type of the input records /// The input dataset /// The output dataset, each partition of which is a copy of source public static IQueryable BroadCast(this IQueryable source, int n) { var dummy = source.ApplyPerPartition(x => HpcLinqHelper.ValueZero(x)) .HashPartition(x => x, n); return dummy.ApplyPerPartition(source, (x, y) => HpcLinqHelper.SelectSecond(x, y), true); } /// /// Check if each partition of the input dataset is ordered. /// /// The type of the records of the input dataset /// The type of the keys on which ordering is based /// The input dataset /// The key extraction function /// A Comparer on TKey to compare records /// True if the check is for descending /// The same dataset as the input public static IQueryable CheckOrderBy(this IQueryable source, Expression> keySelector, IComparer comparer, bool isDescending) { return source.ApplyPerPartition(x_1 => HpcLinqHelper.CheckSort(x_1, keySelector, comparer, isDescending)); } } }