protected override IExpression ConvertAssign(IAssignExpression iae) { foreach (IStatement stmt in context.FindAncestors <IStatement>()) { // an initializer statement may perform a copy, but it is not valid to replace the lhs // in that case. if (context.InputAttributes.Has <Initializer>(stmt)) { return(iae); } } // Look for assignments where the right hand side is a SetTo call if (iae.Expression is IMethodInvokeExpression imie) { bool isCopy = Recognizer.IsStaticGenericMethod(imie, new Func <PlaceHolder, PlaceHolder>(Clone.Copy)); bool isSetTo = Recognizer.IsStaticGenericMethod(imie, typeof(ArrayHelper), "SetTo"); bool isSetAllElementsTo = Recognizer.IsStaticGenericMethod(imie, typeof(ArrayHelper), "SetAllElementsTo"); bool isGetItemsPoint = Recognizer.IsStaticGenericMethod(imie, typeof(GetItemsPointOp <>), "ItemsAverageConditional"); bool isGetJaggedItemsPoint = Recognizer.IsStaticGenericMethod(imie, typeof(GetJaggedItemsPointOp <>), "ItemsAverageConditional"); bool isGetDeepJaggedItemsPoint = Recognizer.IsStaticGenericMethod(imie, typeof(GetDeepJaggedItemsPointOp <>), "ItemsAverageConditional"); bool isGetItemsFromJaggedPoint = Recognizer.IsStaticGenericMethod(imie, typeof(GetItemsFromJaggedPointOp <>), "ItemsAverageConditional"); bool isGetItemsFromDeepJaggedPoint = Recognizer.IsStaticGenericMethod(imie, typeof(GetItemsFromDeepJaggedPointOp <>), "ItemsAverageConditional"); bool isGetJaggedItemsFromJaggedPoint = Recognizer.IsStaticGenericMethod(imie, typeof(GetJaggedItemsFromJaggedPointOp <>), "ItemsAverageConditional"); if (isCopy || isSetTo || isSetAllElementsTo || isGetItemsPoint || isGetJaggedItemsPoint || isGetDeepJaggedItemsPoint || isGetJaggedItemsFromJaggedPoint || isGetItemsFromJaggedPoint || isGetItemsFromDeepJaggedPoint) { IVariableDeclaration ivd = Recognizer.GetVariableDeclaration(iae.Target); // Find the condition context var ifs = context.FindAncestors <IConditionStatement>(); var condContext = new List <IConditionStatement>(); foreach (var ifSt in ifs) { if (!CodeRecognizer.IsStochastic(context, ifSt.Condition)) { condContext.Add(ifSt); } } var copyAttr = context.InputAttributes.GetOrCreate <CopyOfAttribute>(ivd, () => new CopyOfAttribute()); IExpression rhs; if (isSetTo || isSetAllElementsTo) { // Mark as copy of the second argument rhs = imie.Arguments[1]; } else { // Mark as copy of the first argument rhs = imie.Arguments[0]; } InitialiseTo init = context.InputAttributes.Get <InitialiseTo>(ivd); if (init != null) { IVariableDeclaration ivdRhs = Recognizer.GetVariableDeclaration(rhs); InitialiseTo initRhs = (ivdRhs == null) ? null : context.InputAttributes.Get <InitialiseTo>(ivdRhs); if (initRhs == null || !initRhs.initialMessagesExpression.Equals(init.initialMessagesExpression)) { // Do not replace a variable with a unique initialiser return(iae); } } var initBack = context.InputAttributes.Get <InitialiseBackwardTo>(ivd); if (initBack != null && !(initBack.initialMessagesExpression is IArrayCreateExpression)) { IVariableDeclaration ivdRhs = Recognizer.GetVariableDeclaration(rhs); InitialiseBackwardTo initRhs = (ivdRhs == null) ? null : context.InputAttributes.Get <InitialiseBackwardTo>(ivdRhs); if (initRhs == null || !initRhs.initialMessagesExpression.Equals(init.initialMessagesExpression)) { // Do not replace a variable with a unique initialiser return(iae); } } if (isCopy || isSetTo) { RemoveMatchingSuffixes(iae.Target, rhs, condContext, out IExpression lhsPrefix, out IExpression rhsPrefix); copyAttr.copyMap[lhsPrefix] = new CopyOfAttribute.CopyContext { Expression = rhsPrefix, ConditionContext = condContext }; } else if (isSetAllElementsTo) { copyAttr.copiedInEveryElementMap[iae.Target] = new CopyOfAttribute.CopyContext { Expression = rhs, ConditionContext = condContext }; } else if (isGetItemsPoint || isGetJaggedItemsPoint || isGetDeepJaggedItemsPoint || isGetItemsFromJaggedPoint || isGetItemsFromDeepJaggedPoint || isGetJaggedItemsFromJaggedPoint) { var target = ((IArrayIndexerExpression)iae.Target).Target; int inputDepth = imie.Arguments.Count - 3; List <IExpression> indexExprs = new List <IExpression>(); for (int i = 0; i < inputDepth; i++) { indexExprs.Add(imie.Arguments[1 + i]); } int outputDepth; if (isGetDeepJaggedItemsPoint) { outputDepth = 3; } else if (isGetJaggedItemsPoint || isGetJaggedItemsFromJaggedPoint) { outputDepth = 2; } else { outputDepth = 1; } copyAttr.copyAtIndexMap[target] = new CopyOfAttribute.CopyContext2 { Depth = outputDepth, ConditionContext = condContext, ExpressionAtIndex = (lhsIndices) => { return(Builder.JaggedArrayIndex(rhs, indexExprs.ListSelect(indexExpr => new[] { Builder.JaggedArrayIndex(indexExpr, lhsIndices) }))); } }; } else { throw new NotImplementedException(); } } } return(iae); }
/// <summary> /// Add the definition of a random variable to the MSL, inside of the necessary containers. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="variable"></param> /// <remarks> /// A scalar variable is declared and defined in one line such as: <c>int x = factor(...);</c>. /// An array variable is first declared with an initializer such as: <c>int[] array = new int[4];</c>. /// Then it is defined either with a bulk factor such as: <c>array = factor(...);</c>, /// or it is defined via its item variable. /// An item variable is defined by 'for' loop whose body is: <c>array[i] = factor(...);</c>. /// </remarks> protected void BuildRandVar <T>(Variable <T> variable) { if (!variable.IsDefined) { throw new InferCompilerException("Variable '" + variable + "' has no definition"); } if (variable.IsArrayElement) { for (int initType = 0; initType < 2; initType++) { IModelExpression init = (initType == 0) ? variable.initialiseTo : variable.initialiseBackwardTo; if (init != null) { IExpression initExpr = init.GetExpression(); // find the base variable Variable parent = variable; while (parent.ArrayVariable != null) { IVariableDeclaration[] indexVars = new IVariableDeclaration[parent.indices.Count]; for (int i = 0; i < indexVars.Length; i++) { IModelExpression expr = parent.indices[i]; if (!(expr is Range)) { throw new Exception(parent + ".InitializeTo is not allowed since the indices are not ranges"); } indexVars[i] = ((Range)expr).GetIndexDeclaration(); } initExpr = VariableInformation.MakePlaceHolderArrayCreate(initExpr, indexVars); parent = (Variable)parent.ArrayVariable; } IVariableDeclaration parentDecl = (IVariableDeclaration)parent.GetDeclaration(); ICompilerAttribute attr; if (initType == 0) { attr = new InitialiseTo(initExpr); } else { attr = new InitialiseBackwardTo(initExpr); } Attributes.Set(parentDecl, attr); } } return; } IVariableDeclaration ivd = (IVariableDeclaration)variable.GetDeclaration(); if (variable.initialiseTo != null) { Attributes.Set(ivd, new InitialiseTo(variable.initialiseTo.GetExpression())); } if (variable.initialiseBackwardTo != null) { Attributes.Set(ivd, new InitialiseBackwardTo(variable.initialiseBackwardTo.GetExpression())); } List <IStatementBlock> stBlocks = new List <IStatementBlock>(); stBlocks.AddRange(variable.Containers); IVariableDeclarationExpression ivde = Builder.VarDeclExpr(ivd); if (variable is IVariableArray iva) { IList <IStatement> sc = Builder.StmtCollection(); IList <IVariableDeclaration[]> jaggedIndexVars; IList <IExpression[]> jaggedSizes; GetJaggedArrayIndicesAndSizes(iva, out jaggedIndexVars, out jaggedSizes); // check that containers are all unique and distinct from jaggedIndexVars Set <IVariableDeclaration> loopVars = new Set <IVariableDeclaration>(); foreach (IStatementBlock stBlock in stBlocks) { if (stBlock is ForEachBlock fb) { IVariableDeclaration loopVar = fb.Range.GetIndexDeclaration(); if (loopVars.Contains(loopVar)) { throw new InvalidOperationException("Variable '" + ivd.Name + "' uses range '" + loopVar.Name + "' twice. Use a cloned range instead."); } loopVars.Add(loopVar); } } foreach (IVariableDeclaration[] bracket in jaggedIndexVars) { foreach (IVariableDeclaration indexVar in bracket) { if (loopVars.Contains(indexVar)) { throw new InvalidOperationException("Variable '" + ivd.Name + "' uses range '" + indexVar.Name + "' twice. Use a cloned range instead."); } } } Builder.NewJaggedArray(sc, ivd, jaggedIndexVars, jaggedSizes); if (!variable.Inline) { BuildStatementBlocks(stBlocks, true); foreach (IStatement stmt in sc) { AddStatement(stmt); } BuildStatementBlocks(stBlocks, false); } ivde = null; // prevent re-declaration } if (ivde != null) { if (!variable.Inline) { BuildStatementBlocks(stBlocks, true); AddStatement(Builder.ExprStatement(ivde)); BuildStatementBlocks(stBlocks, false); } ivde = null; } if (ivde != null) { throw new InferCompilerException("Variable '" + variable + "' has no definition"); } }