Пример #1
0
        private void CreateConditionalsChannel(VariableInformation vi, VariableToChannelInformation vtci, IList <IStatement> stmts)
        {
            vtci.conditionalsChannel      = ChannelInfo.MarginalChannel(vi);
            vtci.conditionalsChannel.decl = vi.DeriveIndexedVariable(stmts, context, vi.Name + "_conditionals");
            context.OutputAttributes.Remove <InitialiseTo>(vtci.conditionalsChannel.decl);
            context.OutputAttributes.Set(vtci.conditionalsChannel.decl, vtci.conditionalsChannel);
            context.OutputAttributes.Set(vtci.conditionalsChannel.decl, new DescriptionAttribute("conditionals of '" + vi.Name + "'"));
            Type marginalType = MessageTransform.GetDistributionType(vi.varType, vi.InnermostElementType,
                                                                     vi.marginalPrototypeExpression.GetExpressionType(), true);
            Type                conditionalsType = typeof(List <>).MakeGenericType(marginalType);
            IExpression         conditionals_mpe = Builder.NewObject(conditionalsType);
            VariableInformation conditionals_vi  = VariableInformation.GetVariableInformation(context, vtci.conditionalsChannel.decl);

            conditionals_vi.marginalPrototypeExpression = conditionals_mpe;
        }
        private bool InvalidMarginalPrototype(VariableInformation vi, object decl)
        {
            Type marginalType = vi.marginalPrototypeExpression.GetExpressionType();

            if (marginalType == null)
            {
                throw new InferCompilerException("Cannot determine type of marginal prototype expression: " + vi.marginalPrototypeExpression);
            }
            Type domainType  = Distribution.GetDomainType(marginalType);
            Type messageType = MessageTransform.GetDistributionType(vi.varType, domainType, marginalType, false);

            if (MessageTransform.IsPointMass(messageType))
            {
                context.OutputAttributes.Remove <MarginalPrototype>(decl);
                vi.marginalPrototypeExpression = null;
                return(true);
            }
            return(false);
        }
Пример #3
0
        /// <summary>
        /// Get the message prototype in the specified direction
        /// </summary>
        /// <param name="channelInfo">The channel information</param>
        /// <param name="direction">The direction</param>
        /// <param name="marginalPrototypeExpression">The marginal prototype expression</param>
        /// <param name="path">Path name of message</param>
        /// <param name="queryTypes">The set of queries to support.  Only used for marginal channels.</param>
        /// <returns>An expression for the method prototype</returns>
        public override IExpression GetMessagePrototype(
            ChannelInfo channelInfo, MessageDirection direction,
            IExpression marginalPrototypeExpression, string path, IList <QueryType> queryTypes)
        {
            CodeBuilder Builder = CodeBuilder.Instance;

            if (channelInfo.IsMarginal)
            {
                // We want the marginal variable to be a GibbsEstimator over the appropriate
                // distribution type
                if (direction == MessageDirection.Forwards && !UseSideChannels)
                {
                    bool estimateMarginal = false;
                    bool collectSamples = false, collectDistributions = false;
                    foreach (QueryType qt in queryTypes)
                    {
                        if (qt.Name == "Marginal")
                        {
                            estimateMarginal = true;
                        }
                        else if (qt.Name == "Samples")
                        {
                            collectSamples = true;
                        }
                        else if (qt.Name == "Conditionals")
                        {
                            collectDistributions = true;
                        }
                    }
                    Type innermostMessageType = marginalPrototypeExpression.GetExpressionType();
                    Type innermostElementType = Distribution.IsDistributionType(innermostMessageType) ? Distribution.GetDomainType(innermostMessageType) : innermostMessageType;
                    //t = MessageExpressionTransform.GetDistributionType(channelInfo.varInfo.varType, channelInfo.varInfo.innermostElementType, innermostMessageType, true);
                    Type t          = MessageTransform.GetDistributionType(channelInfo.varInfo.varType, innermostElementType, innermostMessageType, true);
                    Type messTyp    = typeof(GibbsMarginal <,>).MakeGenericType(t, Distribution.GetDomainType(t));
                    bool isConstant = !channelInfo.varInfo.IsStochastic;
                    return(Builder.NewObject(
                               messTyp, (t == innermostMessageType) ? marginalPrototypeExpression : Builder.DefaultExpr(t), Quoter.Quote(isConstant ? 0 : this.BurnIn), Quoter.Quote(this.Thin),
                               Quoter.Quote(estimateMarginal), Quoter.Quote(collectSamples), Quoter.Quote(collectDistributions)));
                }
                else
                {
                    return(marginalPrototypeExpression);
                }
            }
            else
            {
                // Default is sample
                Type t         = marginalPrototypeExpression.GetExpressionType();
                bool useSample = (path != "Distribution");
                if (useSample)
                {
                    Type messTyp = Distribution.GetDomainType(t);
                    while (messTyp.IsArray)
                    {
                        messTyp = messTyp.GetElementType();
                    }
                    return(Builder.DefaultExpr(messTyp));
                }
                else
                {
                    return(marginalPrototypeExpression);
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Converts a variable declaration by creating definition, marginal and uses channel variables.
        /// </summary>
        protected override IExpression ConvertVariableDeclExpr(IVariableDeclarationExpression ivde)
        {
            IVariableDeclaration ivd = ivde.Variable;
            VariableInformation  vi  = VariableInformation.GetVariableInformation(context, ivd);

            // If the variable is deterministic, return
            if (!vi.IsStochastic)
            {
                ProcessConstant(ivd);
                context.OutputAttributes.Set(ivd, new DescriptionAttribute("The constant '" + ivd.Name + "'"));
                return(ivde);
            }
            bool suppressVariableFactor = context.InputAttributes.Has <SuppressVariableFactor>(ivd);
            bool isDerived  = context.InputAttributes.Has <DerivedVariable>(ivd);
            bool isConstant = false;
            bool isInferred = context.InputAttributes.Has <IsInferred>(ivd);
            int  useCount;

            ChannelAnalysisTransform.UsageInfo info;
            if (!analysis.usageInfo.TryGetValue(ivd, out info))
            {
                useCount = 0;
            }
            else
            {
                useCount = info.NumberOfUsesOld;
            }
            if (!(algorithm is Algorithms.GibbsSampling) && !isConstant && !suppressVariableFactor && (useCount == 1) && !isInferred && isDerived)
            {
                // this is optional
                suppressVariableFactor = true;
                context.InputAttributes.Set(ivd, new SuppressVariableFactor());
            }
            context.InputAttributes.Remove <LoopContext>(ivd);
            context.InputAttributes.Set(ivd, new LoopContext(context));

            // Create variable-to-channel information for the variable.
            VariableToChannelInformation vtc = new VariableToChannelInformation();

            vtc.shareAllUses = (useCount == 1);
            Context.InputAttributes.Set(ivd, vtc);

            // Ensure the marginal prototype is set.
            MarginalPrototype mpa = Context.InputAttributes.Get <MarginalPrototype>(ivd);

            try
            {
                vi.SetMarginalPrototypeFromAttribute(mpa);
            }
            catch (ArgumentException ex)
            {
                Error(ex.Message);
            }

            // Create the definition channel
            vtc.defChannel      = ChannelInfo.DefChannel(vi);
            vtc.defChannel.decl = ivd;
            // Always create a variable factor for a stochastic variable
            if (!isConstant && !suppressVariableFactor)
            {
                vi.DefineAllIndexVars(context);
                IList <IStatement> stmts = Builder.StmtCollection();

                // Create marginal channel
                vtc.marginalChannel      = ChannelInfo.MarginalChannel(vi);
                vtc.marginalChannel.decl = vi.DeriveIndexedVariable(stmts, context, vi.Name + "_marginal");
                context.InputAttributes.CopyObjectAttributesTo <InitialiseTo>(vi.declaration, context.OutputAttributes, vtc.marginalChannel.decl);
                context.OutputAttributes.Set(vtc.marginalChannel.decl, vtc.marginalChannel);
                context.OutputAttributes.Set(vtc.marginalChannel.decl, new DescriptionAttribute("marginal of '" + ivd.Name + "'"));
                SetMarginalPrototype(vtc.marginalChannel.decl);
                if (algorithm is GibbsSampling && ((GibbsSampling)algorithm).UseSideChannels)
                {
                    Type marginalType = MessageTransform.GetDistributionType(vi.varType, vi.InnermostElementType,
                                                                             vi.marginalPrototypeExpression.GetExpressionType(), true);
                    Type domainType = ivd.VariableType.DotNetType;

                    vtc.samplesChannel      = ChannelInfo.MarginalChannel(vi);
                    vtc.samplesChannel.decl = vi.DeriveIndexedVariable(stmts, context, vi.Name + "_samples");
                    context.OutputAttributes.Remove <InitialiseTo>(vtc.samplesChannel.decl);
                    context.OutputAttributes.Set(vtc.samplesChannel.decl, vtc.samplesChannel);
                    context.OutputAttributes.Set(vtc.samplesChannel.decl, new DescriptionAttribute("samples of '" + ivd.Name + "'"));
                    Type                samplesType = typeof(List <>).MakeGenericType(domainType);
                    IExpression         samples_mpe = Builder.NewObject(samplesType);
                    VariableInformation samples_vi  = VariableInformation.GetVariableInformation(context, vtc.samplesChannel.decl);
                    samples_vi.marginalPrototypeExpression = samples_mpe;

                    vtc.conditionalsChannel      = ChannelInfo.MarginalChannel(vi);
                    vtc.conditionalsChannel.decl = vi.DeriveIndexedVariable(stmts, context, vi.Name + "_conditionals");
                    context.OutputAttributes.Remove <InitialiseTo>(vtc.conditionalsChannel.decl);
                    context.OutputAttributes.Set(vtc.conditionalsChannel.decl, vtc.conditionalsChannel);
                    context.OutputAttributes.Set(vtc.conditionalsChannel.decl, new DescriptionAttribute("conditionals of '" + ivd.Name + "'"));
                    Type                conditionalsType = typeof(List <>).MakeGenericType(marginalType);
                    IExpression         conditionals_mpe = Builder.NewObject(conditionalsType);
                    VariableInformation conditionals_vi  = VariableInformation.GetVariableInformation(context, vtc.conditionalsChannel.decl);
                    conditionals_vi.marginalPrototypeExpression = conditionals_mpe;
                }
                else
                {
                    vtc.samplesChannel      = vtc.marginalChannel;
                    vtc.conditionalsChannel = vtc.marginalChannel;
                }

                // Create uses channel
                vtc.usageChannel      = ChannelInfo.UseChannel(vi);
                vtc.usageChannel.decl = vi.DeriveArrayVariable(stmts, context, vi.Name + "_uses", Builder.LiteralExpr(useCount), Builder.VarDecl("_ind", typeof(int)), useLiteralIndices: true);
                context.InputAttributes.CopyObjectAttributesTo <InitialiseTo>(vi.declaration, context.OutputAttributes, vtc.usageChannel.decl);
                context.OutputAttributes.Set(vtc.usageChannel.decl, vtc.usageChannel);
                context.OutputAttributes.Set(vtc.usageChannel.decl, new DescriptionAttribute("uses of '" + ivd.Name + "'"));
                SetMarginalPrototype(vtc.usageChannel.decl);

                //setAllGroupRoots(context, ivd, false);

                context.AddStatementsBeforeCurrent(stmts);

                // Append usageDepth indices to def/marginal/use expressions
                IExpression defExpr      = Builder.VarRefExpr(ivd);
                IExpression marginalExpr = Builder.VarRefExpr(vtc.marginalChannel.decl);
                IExpression usageExpr    = Builder.VarRefExpr(vtc.usageChannel.decl);
                IExpression countExpr    = Builder.LiteralExpr(useCount);

                // Add clone factor tying together all of the channels
                IMethodInvokeExpression usesEqualDefExpression;
                Type[] genArgs = new Type[] { vi.varType };
                if (algorithm is GibbsSampling && ((GibbsSampling)algorithm).UseSideChannels)
                {
                    GibbsSampling gs               = (GibbsSampling)algorithm;
                    IExpression   burnInExpr       = Builder.LiteralExpr(gs.BurnIn);
                    IExpression   thinExpr         = Builder.LiteralExpr(gs.Thin);
                    IExpression   samplesExpr      = Builder.VarRefExpr(vtc.samplesChannel.decl);
                    IExpression   conditionalsExpr = Builder.VarRefExpr(vtc.conditionalsChannel.decl);
                    if (isDerived)
                    {
                        Delegate d = new FuncOut3 <PlaceHolder, int, int, int, PlaceHolder, PlaceHolder, PlaceHolder, PlaceHolder[]>(Factor.ReplicateWithMarginalGibbs);
                        usesEqualDefExpression = Builder.StaticGenericMethod(d, genArgs, defExpr, countExpr, burnInExpr, thinExpr, marginalExpr, samplesExpr, conditionalsExpr);
                    }
                    else
                    {
                        Delegate d = new FuncOut3 <PlaceHolder, int, int, int, PlaceHolder, PlaceHolder, PlaceHolder, PlaceHolder[]>(Factor.UsesEqualDefGibbs);
                        usesEqualDefExpression = Builder.StaticGenericMethod(d, genArgs, defExpr, countExpr, burnInExpr, thinExpr, marginalExpr, samplesExpr, conditionalsExpr);
                    }
                }
                else
                {
                    Delegate d;
                    if (isDerived)
                    {
                        d = new FuncOut <PlaceHolder, int, PlaceHolder, PlaceHolder[]>(Factor.ReplicateWithMarginal <PlaceHolder>);
                    }
                    else
                    {
                        d = new FuncOut <PlaceHolder, int, PlaceHolder, PlaceHolder[]>(Factor.UsesEqualDef <PlaceHolder>);
                    }
                    usesEqualDefExpression = Builder.StaticGenericMethod(d, genArgs, defExpr, countExpr, marginalExpr);
                }
                if (isDerived)
                {
                    context.OutputAttributes.Set(usesEqualDefExpression, new DerivedVariable());            // used by Gibbs
                }
                // Mark this as a pseudo-factor
                context.OutputAttributes.Set(usesEqualDefExpression, new IsVariableFactor());
                if (useCount == 1)
                {
                    context.OutputAttributes.Set(usesEqualDefExpression, new DivideMessages(false));
                }
                else
                {
                    context.InputAttributes.CopyObjectAttributesTo <DivideMessages>(ivd, context.OutputAttributes, usesEqualDefExpression);
                }
                context.InputAttributes.CopyObjectAttributesTo <GivePriorityTo>(ivd, context.OutputAttributes, usesEqualDefExpression);
                IAssignExpression assignExpr = Builder.AssignExpr(usageExpr, usesEqualDefExpression);

                // Copy attributes across from input to output
                Context.InputAttributes.CopyObjectAttributesTo <Algorithm>(ivd, context.OutputAttributes, assignExpr);
                context.OutputAttributes.Remove <InitialiseTo>(ivd);
                if (vi.ArrayDepth == 0)
                {
                    // Insert the UsesEqualDef statement after the declaration.
                    // Note the variable will not have been defined yet.
                    context.AddStatementAfterCurrent(Builder.ExprStatement(assignExpr));
                }
                else
                {
                    // For an array, the UsesEqualDef statement should be inserted after the array is allocated.
                    // Store the statement for later use by ConvertArrayCreate.
                    context.InputAttributes.Remove <LoopContext>(ivd);
                    context.InputAttributes.Set(ivd, new LoopContext(context));
                    context.InputAttributes.Remove <Containers>(ivd);
                    context.InputAttributes.Set(ivd, new Containers(context));
                    vtc.usesEqualDefsStatements = Builder.StmtCollection();
                    vtc.usesEqualDefsStatements.Add(Builder.ExprStatement(assignExpr));
                }
            }
            // These must be set after the above or they will be copied to the other channels
            context.OutputAttributes.Set(ivd, vtc.defChannel);
            context.OutputAttributes.Set(vtc.defChannel.decl, new DescriptionAttribute("definition of '" + ivd.Name + "'"));
            return(ivde);
        }
Пример #5
0
        // Determine the message type of target from the message type of the factor arguments
        protected void ProcessFactor(IExpression factor, MessageDirection direction)
        {
            NodeInfo info = GetNodeInfo(factor);
            // fill in argumentTypes
            Dictionary <string, Type>        argumentTypes = new Dictionary <string, Type>();
            Dictionary <string, IExpression> arguments     = new Dictionary <string, IExpression>();

            for (int i = 0; i < info.info.ParameterNames.Count; i++)
            {
                string parameterName = info.info.ParameterNames[i];
                // Create message info. 'isForward' says whether the message
                // out is in the forward or backward direction
                bool        isChild    = info.isReturnOrOut[i];
                IExpression arg        = info.arguments[i];
                bool        isConstant = !CodeRecognizer.IsStochastic(context, arg);
                if (isConstant)
                {
                    arguments[parameterName] = arg;
                    Type inwardType = arg.GetExpressionType();
                    argumentTypes[parameterName] = inwardType;
                }
                else if (!isChild)
                {
                    IExpression msgExpr = GetMessageExpression(arg, fwdMessageVars);
                    if (msgExpr == null)
                    {
                        return;
                    }
                    arguments[parameterName] = msgExpr;
                    Type inwardType = msgExpr.GetExpressionType();
                    if (inwardType == null)
                    {
                        Error("inferred an incorrect message type for " + arg);
                        return;
                    }
                    argumentTypes[parameterName] = inwardType;
                }
                else if (direction == MessageDirection.Backwards)
                {
                    IExpression msgExpr = GetMessageExpression(arg, bckMessageVars);
                    if (msgExpr == null)
                    {
                        //Console.WriteLine("creating backward message for "+arg);
                        CreateBackwardMessageFromForward(arg, null);
                        msgExpr = GetMessageExpression(arg, bckMessageVars);
                        if (msgExpr == null)
                        {
                            return;
                        }
                    }
                    arguments[parameterName] = msgExpr;
                    Type inwardType = msgExpr.GetExpressionType();
                    if (inwardType == null)
                    {
                        Error("inferred an incorrect message type for " + arg);
                        return;
                    }
                    argumentTypes[parameterName] = inwardType;
                }
            }
            IAlgorithm alg     = algorithm;
            Algorithm  algAttr = context.InputAttributes.Get <Algorithm>(info.imie);

            if (algAttr != null)
            {
                alg = algAttr.algorithm;
            }
            List <ICompilerAttribute> factorAttributes = context.InputAttributes.GetAll <ICompilerAttribute>(info.imie);
            string methodSuffix = alg.GetOperatorMethodSuffix(factorAttributes);

            // infer types of children
            for (int i = 0; i < info.info.ParameterNames.Count; i++)
            {
                string parameterName = info.info.ParameterNames[i];
                bool   isChild       = info.isReturnOrOut[i];
                if (isChild != (direction == MessageDirection.Forwards))
                {
                    continue;
                }
                IExpression target     = info.arguments[i];
                bool        isConstant = !CodeRecognizer.IsStochastic(context, target);
                if (isConstant)
                {
                    continue;
                }
                IVariableDeclaration ivd = Recognizer.GetVariableDeclaration(target);
                if (ivd == null)
                {
                    continue;
                }
                Type           targetType = null;
                MessageFcnInfo fcninfo    = null;
                if (direction == MessageDirection.Forwards)
                {
                    try
                    {
                        fcninfo = GetMessageFcnInfo(info.info, "Init", parameterName, argumentTypes);
                    }
                    catch (Exception)
                    {
                        try
                        {
                            fcninfo = GetMessageFcnInfo(info.info, methodSuffix + "Init", parameterName, argumentTypes);
                        }
                        catch (Exception ex)
                        {
                            //Error("could not determine message type of "+ivd.Name, ex);
                            try
                            {
                                fcninfo = GetMessageFcnInfo(info.info, methodSuffix, parameterName, argumentTypes);
                                if (fcninfo.PassResult)
                                {
                                    throw new MissingMethodException(StringUtil.MethodFullNameToString(fcninfo.Method) +
                                                                     " is not suitable for initialization since it takes a result parameter.  Please provide a separate Init method.");
                                }
                                if (fcninfo.PassResultIndex)
                                {
                                    throw new MissingMethodException(StringUtil.MethodFullNameToString(fcninfo.Method) +
                                                                     " is not suitable for initialization since it takes a resultIndex parameter.  Please provide a separate Init method.");
                                }
                            }
                            catch (Exception ex2)
                            {
                                if (direction == MessageDirection.Forwards)
                                {
                                    Error("could not determine " + direction + " message type of " + ivd.Name + ": " + ex.Message, ex2);
                                    continue;
                                }
                                fcninfo = null;
                            }
                        }
                    }
                    if (fcninfo != null)
                    {
                        targetType = fcninfo.Method.ReturnType;
                        if (targetType.IsGenericParameter)
                        {
                            if (direction == MessageDirection.Forwards)
                            {
                                Error("could not determine " + direction + " message type of " + ivd.Name + " in " + StringUtil.MethodFullNameToString(fcninfo.Method));
                                continue;
                            }
                            fcninfo = null;
                        }
                    }
                    if (fcninfo != null)
                    {
                        VariableInformation vi = VariableInformation.GetVariableInformation(context, ivd);
                        try
                        {
                            targetType = MessageTransform.GetDistributionType(ivd.VariableType.DotNetType, target.GetExpressionType(), targetType, true);
                        }
                        catch (Exception ex)
                        {
                            if (direction == MessageDirection.Forwards)
                            {
                                Error("could not determine " + direction + " message type of " + ivd.Name, ex);
                                continue;
                            }
                            fcninfo = null;
                        }
                    }
                }
                Dictionary <IVariableDeclaration, IVariableDeclaration> messageVars = (direction == MessageDirection.Forwards) ? fwdMessageVars : bckMessageVars;
                if (fcninfo != null)
                {
                    string name = ivd.Name + (direction == MessageDirection.Forwards ? "_F" : "_B");
                    IVariableDeclaration msgVar;
                    if (!messageVars.TryGetValue(ivd, out msgVar))
                    {
                        msgVar = Builder.VarDecl(name, targetType);
                    }
                    if (true)
                    {
                        // construct the init expression
                        List <IExpression> args       = new List <IExpression>();
                        ParameterInfo[]    parameters = fcninfo.Method.GetParameters();
                        foreach (ParameterInfo parameter in parameters)
                        {
                            string argName = parameter.Name;
                            if (IsFactoryType(parameter.ParameterType))
                            {
                                IVariableDeclaration factoryVar = GetFactoryVariable(parameter.ParameterType);
                                args.Add(Builder.VarRefExpr(factoryVar));
                            }
                            else
                            {
                                FactorEdge factorEdge          = fcninfo.factorEdgeOfParameter[parameter.Name];
                                string     factorParameterName = factorEdge.ParameterName;
                                bool       isOutgoingMessage   = factorEdge.IsOutgoingMessage;
                                if (!arguments.ContainsKey(factorParameterName))
                                {
                                    if (direction == MessageDirection.Forwards)
                                    {
                                        Error(StringUtil.MethodFullNameToString(fcninfo.Method) + " is not suitable for initialization since it requires '" + parameter.Name +
                                              "'.  Please provide a separate Init method.");
                                    }
                                    fcninfo = null;
                                    break;
                                }
                                IExpression arg = arguments[factorParameterName];
                                args.Add(arg);
                            }
                        }
                        if (fcninfo != null)
                        {
                            IMethodInvokeExpression imie = Builder.StaticMethod(fcninfo.Method, args.ToArray());
                            //IExpression initExpr = MessageTransform.GetDistributionArrayCreateExpression(ivd.VariableType.DotNetType, target.GetExpressionType(), imie, vi);
                            IExpression initExpr = imie;
                            KeyValuePair <IVariableDeclaration, IExpression> key = new KeyValuePair <IVariableDeclaration, IExpression>(msgVar, factor);
                            messageInitExprs[key] = initExpr;
                        }
                    }
                    if (fcninfo != null)
                    {
                        messageVars[ivd] = msgVar;
                    }
                }
                if (fcninfo == null)
                {
                    if (direction == MessageDirection.Forwards)
                    {
                        continue;
                    }
                    //Console.WriteLine("creating backward message for "+target);
                    CreateBackwardMessageFromForward(target, factor);
                }
                IExpression msgExpr = GetMessageExpression(target, messageVars);
                arguments[parameterName] = msgExpr;
                Type inwardType = msgExpr.GetExpressionType();
                argumentTypes[parameterName] = inwardType;
            }
        }
        /// <summary>
        /// Converts variable declarations inside loops into array declarations at the top level.
        /// </summary>
        /// <param name="ivde"></param>
        /// <returns></returns>
        protected override IExpression ConvertVariableDeclExpr(IVariableDeclarationExpression ivde)
        {
            IVariableDeclaration ivd   = ivde.Variable;
            bool isLoneDeclaration     = (context.FindAncestorIndex <IExpressionStatement>() == context.Depth - 2);
            List <IForStatement> loops = context.FindAncestors <IForStatement>();

            if (loops.Count == 0)
            {
                List <IConditionStatement> ifs = context.FindAncestors <IConditionStatement>();
                if (ifs.Count == 0)
                {
                    return(ivde);
                }
                // Add declaration outside the if
                IStatement outermostContainer = ifs[0];
                int        ancIndex           = context.GetAncestorIndex(outermostContainer);
                var        defaultExpr        = Builder.DefaultExpr(ivd.VariableType);
                var        assignSt           = Builder.AssignStmt(ivde, defaultExpr);
                context.OutputAttributes.Set(assignSt, new Initializer());
                context.AddStatementBeforeAncestorIndex(ancIndex, assignSt);
                if (isLoneDeclaration)
                {
                    return(null);
                }
                else
                {
                    return(Builder.VarRefExpr(ivd));
                }
            }
            // ignore declaration of a loop variable
            if (Recognizer.LoopVariable(loops[loops.Count - 1]) == ivd)
            {
                return(ivde);
            }

            // Declaration is inside one or more loops, find their sizes and index variables
            Type        type      = Builder.ToType(ivd.VariableType);
            Type        arrayType = type;
            LoopVarInfo lvi       = new LoopVarInfo(loops);

            for (int i = 0; i < loops.Count; i++)
            {
                IForStatement loop = loops[i];
                lvi.indexVarRefs[i] = Builder.VarRefExpr(Recognizer.LoopVariable(loop));
                arrayType           = Util.MakeArrayType(arrayType, 1);
            }
            Predicate <int> isPartitionedAtDepth = (depth => context.InputAttributes.Has <Partitioned>(Recognizer.GetVariableDeclaration(lvi.indexVarRefs[depth])));
            Type            messageType          = Distributions.Distribution.IsDistributionType(type)
                                   ? MessageTransform.GetDistributionType(arrayType, type, type, 0, loops.Count, isPartitionedAtDepth)
                                   : MessageTransform.GetArrayType(arrayType, type, 0, isPartitionedAtDepth);

            lvi.arrayvd       = Builder.VarDecl(ivd.Name, messageType);
            loopVarInfos[ivd] = lvi;
            MessageArrayInformation mai = context.InputAttributes.Get <MessageArrayInformation>(ivd);

            if (mai != null)
            {
                mai.loopVarInfo = lvi;
            }
            context.InputAttributes.CopyObjectAttributesTo(ivd, context.OutputAttributes, lvi.arrayvd);
            context.InputAttributes.Remove <VariableInformation>(lvi.arrayvd);

            VariableInformation vi  = VariableInformation.GetVariableInformation(context, ivd);
            VariableInformation vi2 = VariableInformation.GetVariableInformation(context, lvi.arrayvd);

            vi2.IsStochastic = vi.IsStochastic;

            // Initialise the array to the appropriate sizes
            // TODO: change to work over loop brackets not loops
            IExpression expr = Builder.VarDeclExpr(lvi.arrayvd);

            for (int i = 0; i < loops.Count; i++)
            {
                IForStatement        loop     = loops[i];
                IExpression          loopSize = Recognizer.LoopSizeExpression(loop);
                IExpressionStatement assignSt = Builder.AssignStmt(expr,
                                                                   MessageTransform.GetArrayCreateExpression(expr, expr.GetExpressionType(),
                                                                                                             new IExpression[] { loopSize }));
                context.OutputAttributes.Set(assignSt.Expression, new DescriptionAttribute("Create array for replicates of '" + ivd.Name + "'"));
                context.OutputAttributes.Set(assignSt, new Initializer());

                if (expr is IVariableDeclarationExpression)
                {
                    expr = Builder.VarRefExpr(lvi.arrayvd);
                }
                expr = Builder.ArrayIndex(expr, lvi.indexVarRefs[i]);
                vi2.indexVars.Add(new IVariableDeclaration[] { Recognizer.GetVariableDeclaration(lvi.indexVarRefs[i]) });
                vi2.sizes.Add(new IExpression[] { loopSize });

                // Add declaration outside the loop
                int ancIndex = context.GetAncestorIndex(loop);
                context.AddStatementBeforeAncestorIndex(ancIndex, assignSt);
            }
            vi2.indexVars.AddRange(vi.indexVars);
            vi2.sizes.AddRange(vi.sizes);
            // If the variable declaration was a statement by itself, then return null (i.e. delete the statement).
            if (isLoneDeclaration)
            {
                return(null);
            }
            // Return a reference to the newly created array
            else
            {
                return(expr);
            }
        }