Example #1
0
 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);
 }
Example #2
0
        protected void ProcessAssign(IExpression target, IExpression rhs, ref bool shouldDelete)
        {
            IVariableDeclaration ivd = Recognizer.GetVariableDeclaration(target);

            if (ivd == null)
            {
                return;
            }
            if (rhs is IArrayCreateExpression)
            {
                IArrayCreateExpression iace = (IArrayCreateExpression)rhs;
                bool zeroLength             = iace.Dimensions.All(dimExpr =>
                                                                  (dimExpr is ILiteralExpression) && ((ILiteralExpression)dimExpr).Value.Equals(0));
                if (!zeroLength && iace.Initializer == null)
                {
                    return; // variable will have assignments to elements
                }
            }
            bool firstTime = !variablesAssigned.Contains(ivd);

            variablesAssigned.Add(ivd);
            bool isInferred   = context.InputAttributes.Has <IsInferred>(ivd);
            bool isStochastic = CodeRecognizer.IsStochastic(context, ivd);

            if (!isStochastic)
            {
                return;
            }
            VariableInformation vi            = VariableInformation.GetVariableInformation(context, ivd);
            Containers          defContainers = context.InputAttributes.Get <Containers>(ivd);
            int        ancIndex = defContainers.GetMatchingAncestorIndex(context);
            Containers missing  = defContainers.GetContainersNotInContext(context, ancIndex);
            // definition of a stochastic variable
            IExpression lhs = target;

            if (lhs is IVariableDeclarationExpression)
            {
                lhs = Builder.VarRefExpr(ivd);
            }
            IExpression defExpr = lhs;

            if (firstTime && isStochastic)
            {
                // Create a ChannelInfo attribute for use by later transforms, e.g. MessageTransform
                ChannelInfo defChannel = ChannelInfo.DefChannel(vi);
                defChannel.decl = ivd;
                context.OutputAttributes.Set(ivd, defChannel);
            }
            bool       isDerived = context.InputAttributes.Has <DerivedVariable>(ivd);
            IAlgorithm algorithm = this.algorithmDefault;
            Algorithm  algAttr   = context.InputAttributes.Get <Algorithm>(ivd);

            if (algAttr != null)
            {
                algorithm = algAttr.algorithm;
            }
            if (algorithm is VariationalMessagePassing && ((VariationalMessagePassing)algorithm).UseDerivMessages && isDerived && firstTime)
            {
                vi.DefineAllIndexVars(context);
                IList <IStatement>   stmts     = Builder.StmtCollection();
                IVariableDeclaration derivDecl = vi.DeriveIndexedVariable(stmts, context, ivd.Name + "_deriv");
                context.OutputAttributes.Set(ivd, new DerivMessage(derivDecl));
                ChannelInfo derivChannel = ChannelInfo.DefChannel(vi);
                derivChannel.decl = derivDecl;
                context.OutputAttributes.Set(derivChannel.decl, derivChannel);
                context.OutputAttributes.Set(derivChannel.decl, new DescriptionAttribute("deriv of '" + ivd.Name + "'"));
                // Add the declarations
                stmts = Containers.WrapWithContainers(stmts, missing.outputs);
                context.AddStatementsBeforeAncestorIndex(ancIndex, stmts);
            }
            bool isPointEstimate = context.InputAttributes.Has <PointEstimate>(ivd);

            if (this.analysis.variablesExcludingVariableFactor.Contains(ivd))
            {
                this.variablesLackingVariableFactor.Add(ivd);
                // ivd will get a marginal channel in ConvertMethodInvoke
                useOfVariable[ivd] = ivd;
                return;
            }
            if (isDerived && !isInferred && !isPointEstimate)
            {
                return;
            }

            IExpression useExpr2 = null;

            if (firstTime)
            {
                // create marginal and use channels
                vi.DefineAllIndexVars(context);
                IList <IStatement> stmts = Builder.StmtCollection();

                CreateMarginalChannel(ivd, vi, stmts);
                if (isStochastic)
                {
                    CreateUseChannel(ivd, vi, stmts);
                    context.InputAttributes.Set(useOfVariable[ivd], defContainers);
                }

                // Add the declarations
                stmts = Containers.WrapWithContainers(stmts, missing.outputs);
                context.AddStatementsBeforeAncestorIndex(ancIndex, stmts);
            }
            if (isStochastic && !useOfVariable.ContainsKey(ivd))
            {
                Error("cannot find use channel of " + ivd);
                return;
            }
            IExpression  marginalExpr = Builder.ReplaceVariable(lhs, ivd, marginalOfVariable[ivd]);
            IExpression  useExpr      = isStochastic ? Builder.ReplaceVariable(lhs, ivd, useOfVariable[ivd]) : marginalExpr;
            InitialiseTo it           = context.InputAttributes.Get <InitialiseTo>(ivd);

            Type[] genArgs = new Type[] { defExpr.GetExpressionType() };
            if (rhs is IMethodInvokeExpression)
            {
                IMethodInvokeExpression imie = (IMethodInvokeExpression)rhs;
                if (Recognizer.IsStaticGenericMethod(imie, new Func <PlaceHolder, PlaceHolder>(Clone.Copy)) && ancIndex < context.InputStack.Count - 2)
                {
                    IExpression          arg  = imie.Arguments[0];
                    IVariableDeclaration ivd2 = Recognizer.GetVariableDeclaration(arg);
                    if (ivd2 != null && context.InputAttributes.Get <MarginalPrototype>(ivd) == context.InputAttributes.Get <MarginalPrototype>(ivd2))
                    {
                        // if a variable is a copy, use the original expression since it will give more precise dependencies.
                        defExpr      = arg;
                        shouldDelete = true;
                        bool makeClone = false;
                        if (makeClone)
                        {
                            VariableInformation         vi2      = VariableInformation.GetVariableInformation(context, ivd2);
                            IList <IStatement>          stmts    = Builder.StmtCollection();
                            List <IList <IExpression> > indices  = Recognizer.GetIndices(defExpr);
                            IVariableDeclaration        useDecl2 = vi2.DeriveIndexedVariable(stmts, context, ivd2.Name + "_use", indices);
                            useExpr2 = Builder.VarRefExpr(useDecl2);
                            Containers defContainers2 = context.InputAttributes.Get <Containers>(ivd2);
                            int        ancIndex2      = defContainers2.GetMatchingAncestorIndex(context);
                            Containers missing2       = defContainers2.GetContainersNotInContext(context, ancIndex2);
                            stmts = Containers.WrapWithContainers(stmts, missing2.outputs);
                            context.AddStatementsBeforeAncestorIndex(ancIndex2, stmts);
                            context.InputAttributes.Set(useDecl2, defContainers2);

                            // TODO: call CreateUseChannel
                            ChannelInfo usageChannel = ChannelInfo.UseChannel(vi2);
                            usageChannel.decl = useDecl2;
                            context.InputAttributes.CopyObjectAttributesTo <InitialiseTo>(vi.declaration, context.OutputAttributes, useDecl2);
                            context.InputAttributes.CopyObjectAttributesTo <DerivMessage>(vi.declaration, context.OutputAttributes, useDecl2);
                            context.OutputAttributes.Set(useDecl2, usageChannel);
                            //context.OutputAttributes.Set(useDecl2, new DescriptionAttribute("use of '" + ivd.Name + "'"));
                            context.OutputAttributes.Remove <InitialiseTo>(vi.declaration);

                            IExpression copyExpr = Builder.StaticGenericMethod(
                                new Func <PlaceHolder, PlaceHolder>(Clone.Copy), genArgs, useExpr2);
                            var copyStmt = Builder.AssignStmt(useExpr, copyExpr);
                            context.AddStatementAfterCurrent(copyStmt);
                        }
                    }
                }
            }

            // Add the variable factor
            IExpression variableFactorExpr;
            bool        isGateExitRandom = context.InputAttributes.Has <VariationalMessagePassing.GateExitRandomVariable>(ivd);

            if (isGateExitRandom)
            {
                variableFactorExpr = Builder.StaticGenericMethod(
                    new Models.FuncOut <PlaceHolder, PlaceHolder, PlaceHolder>(Gate.ExitingVariable),
                    genArgs, defExpr, marginalExpr);
            }
            else
            {
                Delegate d = algorithm.GetVariableFactor(isDerived, it != null);
                if (isPointEstimate)
                {
                    d = new Models.FuncOut <PlaceHolder, PlaceHolder, PlaceHolder>(Clone.VariablePoint);
                }
                if (it == null)
                {
                    variableFactorExpr = Builder.StaticGenericMethod(d, genArgs, defExpr, marginalExpr);
                }
                else
                {
                    IExpression initExpr = Builder.ReplaceExpression(lhs, Builder.VarRefExpr(ivd), it.initialMessagesExpression);
                    variableFactorExpr = Builder.StaticGenericMethod(d, genArgs, defExpr, initExpr, marginalExpr);
                }
            }
            context.InputAttributes.CopyObjectAttributesTo <GivePriorityTo>(ivd, context.OutputAttributes, variableFactorExpr);
            context.InputAttributes.CopyObjectAttributesTo <Algorithm>(ivd, context.OutputAttributes, variableFactorExpr);
            if (isStochastic)
            {
                context.OutputAttributes.Set(variableFactorExpr, new IsVariableFactor());
            }
            var assignStmt = Builder.AssignStmt(useExpr2 == null ? useExpr : useExpr2, variableFactorExpr);

            context.AddStatementAfterCurrent(assignStmt);
        }
Example #3
0
        internal IVariableDeclaration DeriveArrayVariable(ICollection <IStatement> addTo, BasicTransformContext context, string name,
                                                          IList <IExpression[]> arraySize, IList <IVariableDeclaration[]> newIndexVar,
                                                          IList <IList <IExpression> > indices      = null,
                                                          IList <IList <IExpression> > wildcardVars = null,
                                                          bool useLiteralIndices = false,
                                                          bool copyInitializer   = false)
        {
            List <IExpression[]>          newSizes     = new List <IExpression[]>();
            List <IVariableDeclaration[]> newIndexVars = new List <IVariableDeclaration[]>();
            Type innerType = varType;

            if (indices != null)
            {
                // add wildcard variables to newIndexVars
                for (int i = 0; i < indices.Count; i++)
                {
                    List <IExpression>          sizeBracket      = new List <IExpression>();
                    List <IVariableDeclaration> indexVarsBracket = new List <IVariableDeclaration>();
                    for (int j = 0; j < indices[i].Count; j++)
                    {
                        IExpression index = indices[i][j];
                        if (Recognizer.IsStaticMethod(index, new Func <int>(GateAnalysisTransform.AnyIndex)))
                        {
                            int replaceCount = 0;
                            sizeBracket.Add(ReplaceIndexVars(context, sizes[i][j], indices, wildcardVars, ref replaceCount));
                            IVariableDeclaration v = indexVars[i][j];
                            if (wildcardVars != null)
                            {
                                v = Recognizer.GetVariableDeclaration(wildcardVars[newIndexVars.Count][indexVarsBracket.Count]);
                            }
                            else if (Recognizer.GetLoopForVariable(context, v) != null)
                            {
                                // v is already used in a parent loop.  must generate a new variable.
                                v = GenerateLoopVar(context, "_a");
                            }
                            indexVarsBracket.Add(v);
                        }
                    }
                    if (sizeBracket.Count > 0)
                    {
                        newSizes.Add(sizeBracket.ToArray());
                        newIndexVars.Add(indexVarsBracket.ToArray());
                    }

                    innerType = Util.GetElementType(innerType);
                }
            }
            int literalIndexingDepth = 0;

            if (arraySize != null)
            {
                newSizes.AddRange(arraySize);
                if (useLiteralIndices)
                {
                    literalIndexingDepth = newSizes.Count;
                }
                newIndexVars.AddRange(newIndexVar);
            }
            // innerType may not be an array type, so we create the new array type here instead of descending further.
            Type arrayType     = CodeBuilder.MakeJaggedArrayType(innerType, newSizes);
            int  indexingDepth = (indices == null) ? 0 : indices.Count;
            List <IList <IExpression> > replacements = new List <IList <IExpression> >();

            if (indices != null)
            {
                replacements.AddRange(indices);
            }
            for (int i = indexingDepth; i < sizes.Count; i++)
            {
                if (replacements.Count == 0)
                {
                    newSizes.Add(sizes[i]);
                    if (indexVars.Count > i)
                    {
                        newIndexVars.Add(indexVars[i]);
                    }
                }
                else
                {
                    // must substitute references to indexVars with indices
                    IExpression[]          sizeBracket        = new IExpression[sizes[i].Length];
                    IVariableDeclaration[] indexVarBracket    = new IVariableDeclaration[sizes[i].Length];
                    IList <IExpression>    replacementBracket = Builder.ExprCollection();
                    for (int j = 0; j < sizeBracket.Length; j++)
                    {
                        int replaceCount = 0;
                        sizeBracket[j] = ReplaceIndexVars(context, sizes[i][j], replacements, wildcardVars, ref replaceCount);
                        if (replaceCount > 0)
                        {
                            indexVarBracket[j] = GenerateLoopVar(context, "_a");
                        }
                        else if (indexVars.Count > i)
                        {
                            indexVarBracket[j] = indexVars[i][j];
                        }
                        if (indexVarBracket[j] != null)
                        {
                            replacementBracket.Add(Builder.VarRefExpr(indexVarBracket[j]));
                        }
                    }
                    newSizes.Add(sizeBracket);
                    newIndexVars.Add(indexVarBracket);
                    replacements.Add(replacementBracket);
                }
            }

            IVariableDeclaration arrayvd = Builder.VarDecl(CodeBuilder.MakeValid(name), arrayType);

            Builder.NewJaggedArray(addTo, arrayvd, newIndexVars, newSizes, literalIndexingDepth);
            context.InputAttributes.CopyObjectAttributesTo(declaration, context.OutputAttributes, arrayvd);
            // cannot copy the initializer since it will have a different size.
            context.OutputAttributes.Remove <InitialiseTo>(arrayvd);
            context.OutputAttributes.Remove <InitialiseBackwardTo>(arrayvd);
            context.OutputAttributes.Remove <InitialiseBackward>(arrayvd);
            context.OutputAttributes.Remove <VariableInformation>(arrayvd);
            context.OutputAttributes.Remove <SuppressVariableFactor>(arrayvd);
            context.OutputAttributes.Remove <LoopContext>(arrayvd);
            context.OutputAttributes.Remove <Containers>(arrayvd);
            context.OutputAttributes.Remove <ChannelInfo>(arrayvd);
            context.OutputAttributes.Remove <IsInferred>(arrayvd);
            context.OutputAttributes.Remove <QueryTypeCompilerAttribute>(arrayvd);
            context.OutputAttributes.Remove <DerivMessage>(arrayvd);
            context.OutputAttributes.Remove <PointEstimate>(arrayvd);
            context.OutputAttributes.Remove <DescriptionAttribute>(arrayvd);
            context.OutputAttributes.Remove <MarginalPrototype>(arrayvd);
            VariableInformation vi = VariableInformation.GetVariableInformation(context, arrayvd);

            vi.IsStochastic = IsStochastic;
            vi.sizes        = newSizes;
            vi.indexVars    = newIndexVars;
            if (useLiteralIndices)
            {
                vi.LiteralIndexingDepth = literalIndexingDepth;
            }
            if (marginalPrototypeExpression != null)
            {
                // substitute indices in the marginal prototype expression
                vi.marginalPrototypeExpression = GetMarginalPrototypeExpression(context, marginalPrototypeExpression, replacements, wildcardVars);
            }
            InitialiseTo it = context.InputAttributes.Get <InitialiseTo>(declaration);

            if (it != null && copyInitializer)
            {
                // if original array is indexed [i,j][k,l][m,n] and indices = [*,*][3,*] then
                // initExpr2 = new PlaceHolder[wildcard0,wildcard1] { new PlaceHolder[wildcard2] { new PlaceHolder[newIndexVar] { initExpr[wildcard0,wildcard1][3,wildcard2] } } }
                IExpression initExpr = it.initialMessagesExpression;
                // add indices to the initialiser expression
                int wildcardBracket = 0;
                for (int depth = 0; depth < indexingDepth; depth++)
                {
                    IList <IExpression> indexCollection = Builder.ExprCollection();
                    int wildcardCount = 0;
                    for (int i = 0; i < indices[depth].Count; i++)
                    {
                        if (Recognizer.IsStaticMethod(indices[depth][i], new Func <int>(GateAnalysisTransform.AnyIndex)))
                        {
                            indexCollection.Add(wildcardVars[wildcardBracket][wildcardCount]);
                            wildcardCount++;
                        }
                        else
                        {
                            indexCollection.Add(indices[depth][i]);
                        }
                    }
                    if (indexCollection.Count > 0)
                    {
                        if (wildcardCount > 0)
                        {
                            wildcardBracket++;
                        }
                        initExpr = Builder.ArrayIndex(initExpr, indexCollection);
                    }
                }
                // add array creates to the initialiser expression
                if (newIndexVar != null)
                {
                    initExpr = MakePlaceHolderArrayCreate(initExpr, newIndexVar);
                }
                if (wildcardBracket > 0)
                {
                    while (wildcardBracket > 0)
                    {
                        wildcardBracket--;
                        initExpr = MakePlaceHolderArrayCreate(initExpr, vi.indexVars[wildcardBracket]);
                    }
                }
                context.OutputAttributes.Set(arrayvd, new InitialiseTo(initExpr));
            }
            ChannelTransform.setAllGroupRoots(context, arrayvd, false);
            return(arrayvd);
        }
Example #4
0
        /// <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");
            }
        }