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); }
/// <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 bool isInferred = context.InputAttributes.Has <IsInferred>(ivd); if (!vi.IsStochastic) { return(ivde); } bool suppressVariableFactor = context.InputAttributes.Has <SuppressVariableFactor>(ivd); bool isDerived = context.InputAttributes.Has <DerivedVariable>(ivd); bool isStochastic = vi.IsStochastic; int useCount; ChannelAnalysisTransform.UsageInfo info; if (!analysis.usageInfo.TryGetValue(ivd, out info)) { useCount = 0; } else { useCount = info.NumberOfUsesOld; } if (!(algorithm is Algorithms.GibbsSampling) && isStochastic && !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 vtci = new VariableToChannelInformation(); vtci.shareAllUses = (useCount <= 1); Context.InputAttributes.Set(ivd, vtci); // Create the definition channel vtci.defChannel = ChannelInfo.DefChannel(vi); vtci.defChannel.decl = ivd; // Always create a variable factor for a stochastic variable if (isInferred || (isStochastic && !suppressVariableFactor)) { vi.DefineAllIndexVars(context); IList <IStatement> stmts = Builder.StmtCollection(); // Create marginal channel CreateMarginalChannel(vi, vtci, stmts); if (algorithm is GibbsSampling && ((GibbsSampling)algorithm).UseSideChannels) { CreateSamplesChannel(vi, vtci, stmts); CreateConditionalsChannel(vi, vtci, stmts); } else { vtci.samplesChannel = vtci.marginalChannel; vtci.conditionalsChannel = vtci.marginalChannel; } if (isStochastic) { // Create uses channel CreateUsesChannel(vi, useCount, vtci, stmts); } //setAllGroupRoots(context, ivd, false); context.AddStatementsBeforeCurrent(stmts); // Append usageDepth indices to def/marginal/use expressions IExpression defExpr = Builder.VarRefExpr(ivd); IExpression marginalExpr = Builder.VarRefExpr(vtci.marginalChannel.decl); IExpression countExpr = Builder.LiteralExpr(useCount); // Add clone factor tying together all of the channels IMethodInvokeExpression variableFactorExpr; 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(vtci.samplesChannel.decl); IExpression conditionalsExpr = Builder.VarRefExpr(vtci.conditionalsChannel.decl); if (isDerived) { Delegate d = new FuncOut3 <PlaceHolder, int, int, int, PlaceHolder, PlaceHolder, PlaceHolder, PlaceHolder[]>(Clone.ReplicateWithMarginalGibbs); variableFactorExpr = Builder.StaticGenericMethod(d, genArgs, defExpr, countExpr, burnInExpr, thinExpr, marginalExpr, samplesExpr, conditionalsExpr); } else { Delegate d = new FuncOut3 <PlaceHolder, int, int, int, PlaceHolder, PlaceHolder, PlaceHolder, PlaceHolder[]>(Clone.UsesEqualDefGibbs); variableFactorExpr = Builder.StaticGenericMethod(d, genArgs, defExpr, countExpr, burnInExpr, thinExpr, marginalExpr, samplesExpr, conditionalsExpr); } } else { Delegate d; if (isDerived) { d = new FuncOut <PlaceHolder, int, PlaceHolder, PlaceHolder[]>(Clone.ReplicateWithMarginal <PlaceHolder>); } else { d = new FuncOut <PlaceHolder, int, PlaceHolder, PlaceHolder[]>(Clone.UsesEqualDef <PlaceHolder>); } variableFactorExpr = Builder.StaticGenericMethod(d, genArgs, defExpr, countExpr, marginalExpr); } if (isDerived) { context.OutputAttributes.Set(variableFactorExpr, new DerivedVariable()); // used by Gibbs } // Mark this as a pseudo-factor context.OutputAttributes.Set(variableFactorExpr, new IsVariableFactor()); if (useCount <= 1) { context.OutputAttributes.Set(variableFactorExpr, new DivideMessages(false)); } else { context.InputAttributes.CopyObjectAttributesTo <DivideMessages>(ivd, context.OutputAttributes, variableFactorExpr); } context.InputAttributes.CopyObjectAttributesTo <GivePriorityTo>(ivd, context.OutputAttributes, variableFactorExpr); if (vtci.usageChannel != null) { IExpression usageExpr = Builder.VarRefExpr(vtci.usageChannel.decl); IAssignExpression assignExpr = Builder.AssignExpr(usageExpr, variableFactorExpr); // 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)); vtci.usesEqualDefsStatements = Builder.StmtCollection(); vtci.usesEqualDefsStatements.Add(Builder.ExprStatement(assignExpr)); } } } // These must be set after the above or they will be copied to the other channels if (isStochastic) { context.OutputAttributes.Set(ivd, vtci.defChannel); } if (!context.InputAttributes.Has <DescriptionAttribute>(vtci.defChannel.decl)) { context.OutputAttributes.Set(vtci.defChannel.decl, new DescriptionAttribute("definition of '" + ivd.Name + "'")); } return(ivde); }
/// <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); }