private void SearchVariableAttributes(Variable variable) { foreach (var attr in variable.GetAttributes <ICompilerAttribute>()) { if (attr is ValueRange vr) { SearchRange(vr.Range); } else if (attr is DistributedCommunication dc) { toSearch.Push(dc.arrayIndicesToSendExpression); toSearch.Push(dc.arrayIndicesToReceiveExpression); var attr2 = new DistributedCommunicationExpression(dc.arrayIndicesToSendExpression.GetExpression(), dc.arrayIndicesToReceiveExpression.GetExpression()); // find the base variable Variable parent = variable; while (parent.ArrayVariable != null) { parent = (Variable)parent.ArrayVariable; } var parentDecl = parent.GetDeclaration(); if (Attributes.Has <DistributedCommunicationExpression>(parentDecl)) { throw new Exception($"{parent} has multiple DistributedCommunication attributes"); } Attributes.Set(parentDecl, attr2); } } }
protected override IExpression ConvertMethodInvoke(IMethodInvokeExpression imie) { // Insert an Increment statement to support Sequential loops // if we find the pattern: // forwardExpr = ReplicateOp_Divide.UsesAverageConditional(backwardExpr[index], marginalExpr, index, forwardExpr) // then when backwardExpr is updated, we insert the following statement: // MarginalIncrement(marginalExpr, forwardExpr, backwardExpr[index]); if (Recognizer.IsStaticMethod(imie, typeof(ReplicateOp_Divide), "UsesAverageConditional")) { IExpression backwardExpr = imie.Arguments[0]; object backwardDecl = Recognizer.GetArrayDeclaration(backwardExpr); IExpression marginalExpr = imie.Arguments[1]; IExpression indexExpr = imie.Arguments[2]; IVariableDeclaration indexVar = Recognizer.GetVariableDeclaration(indexExpr); IExpression forwardExpr = imie.Arguments[3]; if (indexVar != null && context.InputAttributes.Has <Sequential>(indexVar)) { if (!compiler.UseSerialSchedules) { context.Warning(indexVar.Name + " is marked Sequential but engine.Compiler.UseSerialSchedules = false"); } IMethodReferenceExpression imre = imie.Method; ITypeReference itr = ((ITypeReferenceExpression)imre.Target).Type; MethodInfo method = itr.DotNetType.GetMethod("MarginalIncrement"); method = method.MakeGenericMethod(imre.Method.MethodInfo.GetGenericArguments()); IExpression rhs = Builder.StaticGenericMethod(method, marginalExpr, forwardExpr, backwardExpr); IStatement increment = Builder.AssignStmt(marginalExpr, rhs); var seq = context.InputAttributes.Get <Sequential>(indexVar); var attr = new IncrementStatement(indexVar, seq.BackwardPass); context.OutputAttributes.Set(increment, attr); onUpdate[backwardDecl] = increment; } } // if we find the pattern: // forwardExpr = Replicate2BufferOp.UsesAverageConditional(backwardExpr, *, marginalExpr, index, forwardExpr) // then when backwardExpr is updated, we insert the following statement: // marginalExpr = MarginalIncrement(marginalExpr, forwardExpr, backwardExpr[index]); if (Recognizer.IsStaticMethod(imie, typeof(Replicate2BufferOp), "UsesAverageConditional")) { IExpression backwardExpr = imie.Arguments[0]; object backwardDecl = Recognizer.GetArrayDeclaration(backwardExpr); IExpression marginalExpr = imie.Arguments[2]; IExpression indexExpr = imie.Arguments[3]; IVariableDeclaration indexVar = Recognizer.GetVariableDeclaration(indexExpr); IExpression forwardExpr = imie.Arguments[4]; if (indexVar != null && context.InputAttributes.Has <Sequential>(indexVar)) { if (!compiler.UseSerialSchedules) { context.Warning(indexVar.Name + " is marked Sequential but engine.Compiler.UseSerialSchedules = false"); } IMethodReferenceExpression imre = imie.Method; ITypeReference itr = ((ITypeReferenceExpression)imre.Target).Type; MethodInfo method = itr.DotNetType.GetMethod("MarginalIncrement"); method = method.MakeGenericMethod(imre.Method.MethodInfo.GetGenericArguments()); IExpression rhs = Builder.StaticGenericMethod(method, marginalExpr, forwardExpr, Builder.ArrayIndex(backwardExpr, indexExpr)); IStatement increment = Builder.AssignStmt(marginalExpr, rhs); var seq = context.InputAttributes.Get <Sequential>(indexVar); var attr = new IncrementStatement(indexVar, seq.BackwardPass); context.OutputAttributes.Set(increment, attr); onUpdate[backwardDecl] = increment; } } // if we find the pattern: // forwardExpr = JaggedSubarrayOp<>.ItemsAverageConditional(backwardExpr[index], *, marginalExpr, indices, index, forwardExpr) // then when backwardExpr is updated, we insert the following statement: // MarginalIncrement(marginalExpr, forwardExpr, backwardExpr[index], indices, index) if (Recognizer.IsStaticGenericMethod(imie, typeof(JaggedSubarrayOp <>), "ItemsAverageConditional")) { IExpression backwardExpr = imie.Arguments[0]; object backwardDecl = Recognizer.GetArrayDeclaration(backwardExpr); IExpression marginalExpr = imie.Arguments[2]; IExpression indicesExpr = imie.Arguments[3]; IExpression indexExpr = imie.Arguments[4]; IVariableDeclaration indexVar = Recognizer.GetVariableDeclaration(indexExpr); IExpression forwardExpr = imie.Arguments[5]; if (indexVar != null && context.InputAttributes.Has <Sequential>(indexVar)) { if (!compiler.UseSerialSchedules) { context.Warning(indexVar.Name + " is marked Sequential but engine.Compiler.UseSerialSchedules = false"); } IMethodReferenceExpression imre = imie.Method; ITypeReference itr = ((ITypeReferenceExpression)imre.Target).Type; IExpression[] args2 = new IExpression[] { marginalExpr, forwardExpr, backwardExpr, indicesExpr, indexExpr }; Type[] argTypes = Array.ConvertAll(args2, e => e.GetExpressionType()); Exception exception; MethodInfo method = (MethodInfo)Reflection.Invoker.GetBestMethod(itr.DotNetType, "MarginalIncrement", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy, null, argTypes, out exception); if (method == null) { Error("Cannot find a compatible MarginalIncrement method for JaggedSubarrayOp", exception); } else { IExpression rhs = Builder.StaticGenericMethod(method, args2); IStatement increment = Builder.AssignStmt(marginalExpr, rhs); var seq = context.InputAttributes.Get <Sequential>(indexVar); var attr = new IncrementStatement(indexVar, seq.BackwardPass); context.OutputAttributes.Set(increment, attr); onUpdate[backwardDecl] = increment; } } } // if we find the pattern: // forwardExpr = JaggedSubarrayWithMarginalOp<>.ItemsAverageConditional(backwardExpr[index], *, marginalExpr, indices, index, forwardExpr) // then when backwardExpr is updated, we insert the following statement: // MarginalIncrementItems(backwardExpr[index], forwardExpr, indices, index, marginalExpr) if (Recognizer.IsStaticGenericMethod(imie, typeof(JaggedSubarrayWithMarginalOp <>), "ItemsAverageConditional")) { IExpression backwardExpr = imie.Arguments[0]; IExpression marginalExpr = imie.Arguments[2]; IExpression indicesExpr = imie.Arguments[3]; IExpression indexExpr = imie.Arguments[4]; IVariableDeclaration indexVar = Recognizer.GetVariableDeclaration(indexExpr); IExpression forwardExpr = imie.Arguments[5]; if (indexVar != null && context.InputAttributes.Has <Sequential>(indexVar)) { if (!compiler.UseSerialSchedules) { context.Warning(indexVar.Name + " is marked Sequential but engine.Compiler.UseSerialSchedules = false"); } IMethodReferenceExpression imre = imie.Method; ITypeReference itr = ((ITypeReferenceExpression)imre.Target).Type; IExpression[] args2 = new IExpression[] { backwardExpr, forwardExpr, indicesExpr, indexExpr, marginalExpr }; Type[] argTypes = Array.ConvertAll(args2, e => e.GetExpressionType()); Exception exception; MethodInfo method = (MethodInfo)Reflection.Invoker.GetBestMethod(itr.DotNetType, "MarginalIncrementItems", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy, null, argTypes, out exception); if (method == null) { Error("Cannot find a compatible MarginalIncrementItems method for JaggedSubarrayWithMarginalOp", exception); } else { IExpression rhs = Builder.StaticGenericMethod(method, args2); IStatement increment = Builder.AssignStmt(marginalExpr, rhs); var seq = context.InputAttributes.Get <Sequential>(indexVar); var attr = new IncrementStatement(indexVar, seq.BackwardPass); context.OutputAttributes.Set(increment, attr); object backwardDecl = Recognizer.GetArrayDeclaration(backwardExpr); onUpdate[backwardDecl] = increment; IVariableDeclaration marginalVar = Recognizer.GetVariableDeclaration(marginalExpr); suppressUpdate[marginalVar] = attr; } var indicesVar = Recognizer.GetDeclaration(indicesExpr); if (indicesVar != null) { DistributedCommunicationExpression dce = context.GetAttribute <DistributedCommunicationExpression>(indicesVar); if (dce != null) { context.OutputAttributes.Set(imie, dce); } } } } // if we find the pattern: // backwardExpr = JaggedSubarrayWithMarginalOp<>.ArrayAverageConditional(forwardExpr, marginalExpr, backwardExpr) // then when forwardExpr is updated, we insert the following statement: // MarginalIncrementArray if (Recognizer.IsStaticGenericMethod(imie, typeof(JaggedSubarrayWithMarginalOp <>), "ArrayAverageConditional")) { IExpression forwardExpr = imie.Arguments[0]; IExpression marginalExpr = imie.Arguments[1]; IExpression backwardExpr = imie.Arguments[2]; if (true) { IMethodReferenceExpression imre = imie.Method; ITypeReference itr = ((ITypeReferenceExpression)imre.Target).Type; IExpression[] args2 = new IExpression[] { forwardExpr, backwardExpr, marginalExpr }; Type[] argTypes = Array.ConvertAll(args2, e => e.GetExpressionType()); Exception exception; MethodInfo method = (MethodInfo)Reflection.Invoker.GetBestMethod(itr.DotNetType, "MarginalIncrementArray", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy, null, argTypes, out exception); if (method == null) { Error("Cannot find a compatible MarginalIncrementArray method for JaggedSubarrayWithMarginalOp", exception); } else { IExpression rhs = Builder.StaticGenericMethod(method, args2); IStatement increment = Builder.AssignStmt(marginalExpr, rhs); var attr = new IncrementStatement(null, false); context.OutputAttributes.Set(increment, attr); object forwardDecl = Recognizer.GetArrayDeclaration(forwardExpr); onUpdate[forwardDecl] = increment; } IVariableDeclaration marginalVar = Recognizer.GetVariableDeclaration(marginalExpr); // only suppress when we also have MarginalIncrementItems //suppressUpdate.Add(marginalVar); } } // if we find the pattern: // forwardExpr = GetItemsOp<>.ItemsAverageConditional(backwardExpr[index], *, marginalExpr, indices, index, forwardExpr) // then when backwardExpr is updated, we insert the following statement: // MarginalIncrement(marginalExpr, forwardExpr, backwardExpr[index], indices, index) if (Recognizer.IsStaticGenericMethod(imie, typeof(GetItemsOp <>), "ItemsAverageConditional") || Recognizer.IsStaticGenericMethod(imie, typeof(GetJaggedItemsOp <>), "ItemsAverageConditional") || Recognizer.IsStaticGenericMethod(imie, typeof(GetDeepJaggedItemsOp <>), "ItemsAverageConditional")) { IExpression backwardExpr = imie.Arguments[0]; object backwardDecl = Recognizer.GetArrayDeclaration(backwardExpr); IExpression marginalExpr = imie.Arguments[2]; IExpression indicesExpr = imie.Arguments[3]; IExpression indexExpr = imie.Arguments[4]; IVariableDeclaration indexVar = Recognizer.GetVariableDeclaration(indexExpr); IExpression forwardExpr = imie.Arguments[5]; if (indexVar != null && context.InputAttributes.Has <Sequential>(indexVar)) { if (!compiler.UseSerialSchedules) { context.Warning(indexVar.Name + " is marked Sequential but engine.Compiler.UseSerialSchedules = false"); } IMethodReferenceExpression imre = imie.Method; ITypeReference itr = ((ITypeReferenceExpression)imre.Target).Type; MethodInfo method = itr.GenericType.DotNetType.GetMethod("MarginalIncrement"); method = method.MakeGenericMethod(imre.Method.MethodInfo.GetGenericArguments()); IExpression rhs = Builder.StaticGenericMethod(method, marginalExpr, forwardExpr, backwardExpr, indicesExpr, indexExpr); //IStatement increment = Builder.ExprStatement(rhs); IStatement increment = Builder.AssignStmt(marginalExpr, rhs); var seq = context.InputAttributes.Get <Sequential>(indexVar); var attr = new IncrementStatement(indexVar, seq.BackwardPass); context.OutputAttributes.Set(increment, attr); onUpdate[backwardDecl] = increment; } } // if we find the pattern: // forwardExpr = GetItemsOp<>.ItemsAverageConditional(backwardExpr[index], *, marginalExpr, indices, index, forwardExpr) // then when backwardExpr is updated, we insert the following statement: // MarginalIncrement(marginalExpr, forwardExpr, backwardExpr[index], indices, index) if (Recognizer.IsStaticGenericMethod(imie, typeof(GetItemsWithDictionaryOp <>), "ItemsAverageConditional")) { IExpression backwardExpr = imie.Arguments[0]; object backwardDecl = Recognizer.GetArrayDeclaration(backwardExpr); IExpression marginalExpr = imie.Arguments[2]; IExpression indicesExpr = imie.Arguments[3]; IExpression dictExpr = imie.Arguments[4]; IExpression indexExpr = imie.Arguments[5]; IVariableDeclaration indexVar = Recognizer.GetVariableDeclaration(indexExpr); IExpression forwardExpr = imie.Arguments[6]; if (indexVar != null && context.InputAttributes.Has <Sequential>(indexVar)) { if (!compiler.UseSerialSchedules) { context.Warning(indexVar.Name + " is marked Sequential but engine.Compiler.UseSerialSchedules = false"); } IMethodReferenceExpression imre = imie.Method; ITypeReference itr = ((ITypeReferenceExpression)imre.Target).Type; MethodInfo method = itr.GenericType.DotNetType.GetMethod("MarginalIncrement"); method = method.MakeGenericMethod(imre.Method.MethodInfo.GetGenericArguments()); IExpression rhs = Builder.StaticGenericMethod(method, marginalExpr, forwardExpr, backwardExpr, indicesExpr, dictExpr, indexExpr); IStatement increment = Builder.AssignStmt(marginalExpr, rhs); var seq = context.InputAttributes.Get <Sequential>(indexVar); var attr = new IncrementStatement(indexVar, seq.BackwardPass); context.OutputAttributes.Set(increment, attr); onUpdate[backwardDecl] = increment; } } // if we find the pattern: // partialExpr = GetItemsOp2<>.Partial(backwardExpr[index], to_array, indices, index, partialExpr); // then when backwardExpr is updated, we insert the following statement: // to_array[indices[index]] = ArrayIncrement(partialExpr, backwardExpr[index]) if (Recognizer.IsStaticGenericMethod(imie, typeof(GetItemsOp2 <>), "Partial")) { IExpression backwardExpr = imie.Arguments[0]; object backwardDecl = Recognizer.GetArrayDeclaration(backwardExpr); IExpression to_array = imie.Arguments[1]; IExpression indicesExpr = imie.Arguments[2]; IExpression indexExpr = imie.Arguments[3]; IVariableDeclaration indexVar = Recognizer.GetVariableDeclaration(indexExpr); IExpression forwardExpr = imie.Arguments[4]; if (indexVar != null && context.InputAttributes.Has <Sequential>(indexVar)) { if (!compiler.UseSerialSchedules) { context.Warning(indexVar.Name + " is marked Sequential but engine.Compiler.UseSerialSchedules = false"); } IMethodReferenceExpression imre = imie.Method; ITypeReference itr = ((ITypeReferenceExpression)imre.Target).Type; MethodInfo method = itr.GenericType.DotNetType.GetMethod("ArrayIncrement"); method = method.MakeGenericMethod(imre.Method.MethodInfo.GetGenericArguments()); IExpression resultExpr = Builder.ArrayIndex(to_array, Builder.ArrayIndex(indicesExpr, indexExpr)); IExpression rhs = Builder.StaticGenericMethod(method, forwardExpr, backwardExpr, resultExpr); IStatement increment = Builder.AssignStmt(resultExpr, rhs); var seq = context.InputAttributes.Get <Sequential>(indexVar); var attr = new IncrementStatement(indexVar, seq.BackwardPass); context.OutputAttributes.Set(increment, attr); onUpdate[backwardDecl] = increment; } } // if we find the pattern: // forwardExpr = GetItemsJaggedOp<>.ItemsAverageConditional(backwardExpr[index], *, marginalExpr, indices, indices2, index, forwardExpr) // then when backwardExpr is updated, we insert the following statement: // MarginalIncrement(marginalExpr, forwardExpr, backwardExpr[index], indices, indices2, index) if (Recognizer.IsStaticGenericMethod(imie, typeof(GetItemsFromJaggedOp <>), "ItemsAverageConditional")) { IExpression backwardExpr = imie.Arguments[0]; object backwardDecl = Recognizer.GetArrayDeclaration(backwardExpr); IExpression marginalExpr = imie.Arguments[2]; IExpression indicesExpr = imie.Arguments[3]; IExpression indices2Expr = imie.Arguments[4]; IExpression indexExpr = imie.Arguments[5]; IVariableDeclaration indexVar = Recognizer.GetVariableDeclaration(indexExpr); IExpression forwardExpr = imie.Arguments[6]; if (indexVar != null && context.InputAttributes.Has <Sequential>(indexVar)) { if (!compiler.UseSerialSchedules) { context.Warning(indexVar.Name + " is marked Sequential but engine.Compiler.UseSerialSchedules = false"); } IMethodReferenceExpression imre = imie.Method; ITypeReference itr = ((ITypeReferenceExpression)imre.Target).Type; MethodInfo method = itr.GenericType.DotNetType.GetMethod("MarginalIncrement"); method = method.MakeGenericMethod(imre.Method.MethodInfo.GetGenericArguments()); IExpression rhs = Builder.StaticGenericMethod(method, marginalExpr, forwardExpr, backwardExpr, indicesExpr, indices2Expr, indexExpr); IStatement increment = Builder.AssignStmt(marginalExpr, rhs); var seq = context.InputAttributes.Get <Sequential>(indexVar); var attr = new IncrementStatement(indexVar, seq.BackwardPass); context.OutputAttributes.Set(increment, attr); onUpdate[backwardDecl] = increment; } } // if we find the pattern: // forwardExpr = GetItemsDeepJaggedOp<>.ItemsAverageConditional(backwardExpr[index], *, marginalExpr, indices, indices2, indices3, index, forwardExpr) // then when backwardExpr is updated, we insert the following statement: // MarginalIncrement(marginalExpr, forwardExpr, backwardExpr[index], indices, indices2, indices3, index) if (Recognizer.IsStaticGenericMethod(imie, typeof(GetItemsFromDeepJaggedOp <>), "ItemsAverageConditional")) { IExpression backwardExpr = imie.Arguments[0]; object backwardDecl = Recognizer.GetArrayDeclaration(backwardExpr); IExpression marginalExpr = imie.Arguments[2]; IExpression indicesExpr = imie.Arguments[3]; IExpression indices2Expr = imie.Arguments[4]; IExpression indices3Expr = imie.Arguments[5]; IExpression indexExpr = imie.Arguments[6]; IVariableDeclaration indexVar = Recognizer.GetVariableDeclaration(indexExpr); IExpression forwardExpr = imie.Arguments[7]; if (indexVar != null && context.InputAttributes.Has <Sequential>(indexVar)) { if (!compiler.UseSerialSchedules) { context.Warning(indexVar.Name + " is marked Sequential but engine.Compiler.UseSerialSchedules = false"); } IMethodReferenceExpression imre = imie.Method; ITypeReference itr = ((ITypeReferenceExpression)imre.Target).Type; MethodInfo method = itr.GenericType.DotNetType.GetMethod("MarginalIncrement"); method = method.MakeGenericMethod(imre.Method.MethodInfo.GetGenericArguments()); IExpression rhs = Builder.StaticGenericMethod(method, marginalExpr, forwardExpr, backwardExpr, indicesExpr, indices2Expr, indices3Expr, indexExpr); IStatement increment = Builder.AssignStmt(marginalExpr, rhs); var seq = context.InputAttributes.Get <Sequential>(indexVar); var attr = new IncrementStatement(indexVar, seq.BackwardPass); context.OutputAttributes.Set(increment, attr); onUpdate[backwardDecl] = increment; } } return(base.ConvertMethodInvoke(imie)); }
/// <summary> /// Define a variable in the MSL. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="variable"></param> /// private void SearchVariable <T>(Variable <T> variable) { if (searched.Contains(variable)) { return; } if (variable.IsBase && variable.NameInGeneratedCode != null) { string name = variable.NameInGeneratedCode; foreach (IModelExpression expr in searched) { if (name.Equals(expr.Name)) { throw new InferCompilerException("Model contains multiple items with the name '" + name + "'. Names must be unique."); } } } if (variable.IsLoopIndex) { return; // do nothing } searched.Add(variable); // must do this first to prevent re-entry SearchContainers(variable.Containers); List <IStatementBlock> stBlocks = new List <IStatementBlock>(); if (variable.IsArrayElement) { SearchItem(variable); } else { // base variable // Process dependencies if (variable.initialiseTo != null) { toSearch.Push(variable.initialiseTo); } if (variable.initialiseBackwardTo != null) { toSearch.Push(variable.initialiseBackwardTo); } if (!variable.Inline) { // Determine if the variable should be inlined bool inline; if (variable.definition != null) { inline = variable.definition.CanBeInlined(); } else { inline = (variable.conditionalDefinitions.Values.Count == 1); foreach (MethodInvoke condDef in variable.conditionalDefinitions.Values) { inline = inline && condDef.CanBeInlined(); } if (variable is HasItemVariables) { ICollection <IVariable> items = ((HasItemVariables)variable).GetItemsUntyped().Values; if (items.Count > 0) { inline = false; } } } variable.Inline = inline; } if (variable is IVariableArray) { IVariableArray iva = (IVariableArray)variable; IList <IVariableDeclaration[]> jaggedIndexVars; IList <IExpression[]> jaggedSizes; GetJaggedArrayIndicesAndSizes(iva, out jaggedIndexVars, out jaggedSizes); } // ivde is null if randVar has been declared at this point. if (variable.definition != null) { SearchMethodInvoke(variable.definition); } foreach (var attr in variable.GetAttributes <ICompilerAttribute>()) { if (attr is ValueRange) { ValueRange vr = (ValueRange)attr; SearchRange(vr.Range); } else if (attr is DistributedCommunication) { DistributedCommunication dc = (DistributedCommunication)attr; toSearch.Push(dc.arrayIndicesToSendExpression); toSearch.Push(dc.arrayIndicesToReceiveExpression); var attr2 = new DistributedCommunicationExpression(dc.arrayIndicesToSendExpression.GetExpression(), dc.arrayIndicesToReceiveExpression.GetExpression()); // find the base variable Variable parent = variable; while (parent.ArrayVariable != null) { parent = (Variable)parent.ArrayVariable; } var parentDecl = parent.GetDeclaration(); if (Attributes.Has <DistributedCommunicationExpression>(parentDecl)) { throw new Exception($"{parent} has multiple DistributedCommunication attributes"); } Attributes.Set(parentDecl, attr2); } } } foreach (MethodInvoke condDef in variable.conditionalDefinitions.Values) { SearchMethodInvoke(condDef); } if (variable is HasItemVariables) { // fill the array via the definition of its item variable, if any. ICollection <IVariable> ie = ((HasItemVariables)variable).GetItemsUntyped().Values; foreach (IVariable irv in ie) { toSearch.Push(irv); } } foreach (MethodInvoke constraint in variable.constraints) { SearchMethodInvoke(constraint); } foreach (MethodInvoke factor in variable.childFactors) { SearchMethodInvoke(factor); } }