/// <inheritdoc/> public override MathExpression ApplyTo(BinaryExpression expr, IOptimizationContext <ICommutativitySettings> ctx, out bool transformResult) { transformResult = true; var list = expr.Arguments.Select(e => ApplyTo(e, ctx)).ToList(); if (!ctx.Settings.IgnoreCommutativityFor.Contains(expr.Type)) { switch (expr.Type) { case ExpressionType.Add: case ExpressionType.Multiply: case ExpressionType.And: case ExpressionType.Or: bool IsCombinableExpression(MathExpression e) => e is BinaryExpression ex && ex.Type == expr.Type; if (list.Any(IsCombinableExpression)) { foreach (var ex in list.ToArray().Where(IsCombinableExpression).Cast <BinaryExpression>()) { list.Remove(ex); list.AddRange(ex.Arguments); } } break; } } return(new BinaryExpression(expr.Type, list).WithToken(expr.Token)); }
/// <inheritdoc/> public override MathExpression ApplyTo(FunctionExpression expr, IOptimizationContext <IFunctionInlineSettings> ctx, out bool transformResult) { if (expr.IsUserDefined) { var definedFunctions = GetDefinedFunctions(ctx); if (definedFunctions.TryGetValue(expr.Name, out var tup) && expr.Arguments.Count == tup.func.ParameterList.Count) { var variableSubs = GetVariableSubstitutions(ctx); if (variableSubs.Count == 0) { // only when we're not currently substituting foreach (var(replace, with) in tup.func.ParameterList.Zip(expr.Arguments, Helpers.Tuple)) { variableSubs.Add(replace, with); } var value = ApplyTo(tup.func.Definition, ctx); variableSubs.Clear(); transformResult = false; // because we have applied all transformations by definition with the following call // this could very easily create dangerously deep callstacks return(ApplyTo(value, ctx)); // handle nested calls } } } return(base.ApplyTo(expr, ctx, out transformResult)); }
/// <inheritdoc/> public override MathExpression ApplyTo(VariableExpression expr, IOptimizationContext <IFunctionInlineSettings> ctx, out bool transformResult) { var variableSubs = GetVariableSubstitutions(ctx); transformResult = true; if (variableSubs.TryGetValue(expr, out var replaceWith)) { return(replaceWith); } return(base.ApplyTo(expr, ctx, out transformResult)); }
/// <inheritdoc/> public override MathExpression ApplyTo(BinaryExpression expr, IOptimizationContext <IDomainRestrictionSettings> ctx, out bool transformResult) { switch (expr.Type) { case BinaryExpression.ExpressionType.Power: if (expr.Left is LiteralExpression l && l.Value == DecimalMath.E) { transformResult = false; // because we will have already applied to our target // transform into call to `exp` function, then apply to that return(ApplyTo(new FunctionExpression(BuiltinFunctionExp.ConstName, new[] { ApplyTo(expr.Right, ctx) }.ToList(), false).WithToken(expr.Token), ctx)); } break; } return(base.ApplyTo(expr, ctx, out transformResult)); }
public IOptimizationContext AddOrGetContext(string name) { if (null == name) { throw new ArgumentNullException(nameof(name)); } if (this.Contexts.TryGetValue(name, out IOptimizationContext context)) { return(context); } IOptimizationContext optimizationContext = ActivatorUtilities.CreateInstance <TContext>(this.ServiceProvider); this.Contexts.Add(name, optimizationContext); return(optimizationContext); }
/// <inheritdoc/> public override MathExpression ApplyTo(FunctionExpression f, IOptimizationContext <IDomainRestrictionSettings> ctx, out bool transformResult) { if (!f.IsUserDefined && f.Name == BuiltinFunctionExp.ConstName) { // exp(x) if (f.Arguments.Count == 1) { var arg = f.Arguments.First(); if (arg is FunctionExpression fn && !fn.IsUserDefined && fn.Name == BuiltinFunctionLn.ConstName) { // exp(ln(x)) if (fn.Arguments.Count == 1 && ctx.Settings.AllowDomainChangingOptimizations) { var ln = fn.Arguments.First(); var dr = GetDomainRestrictions(ctx); dr.Add(new BinaryExpression(ln, new LiteralExpression(0), BinaryExpression.ExpressionType.LessEq)); transformResult = false; //because we will have already applied to it return(ApplyTo(ln, ctx)); // apply to the argument, transform to that } } } } return(base.ApplyTo(f, ctx, out transformResult)); }
/// <inheritdoc/> public override MathExpression ApplyTo(CustomDefinitionExpression expr, IOptimizationContext <IFunctionInlineSettings> ctx, out bool transformResult) { if (ctx.Settings.ShouldInline && expr.DefinitionSize <= ctx.Settings.DoNotInlineAfterSize) { var definedFunctions = GetDefinedFunctions(ctx); definedFunctions.Add(expr.FunctionName, (expr, false)); var value = ApplyTo(expr.Value, ctx); transformResult = false; // because the resulting value has already been fully transformed if (definedFunctions[expr.FunctionName].hasNotInlinedUses) { return(new CustomDefinitionExpression(expr.FunctionName, expr.ParameterList, expr.Definition, value).WithToken(expr.Token)); } else { return(value); } } return(base.ApplyTo(expr, ctx, out transformResult)); }
/// <inheritdoc/> public override MathExpression ApplyTo(FunctionExpression expr, IOptimizationContext <object?> ctx, out bool transformResult) { if (!expr.IsUserDefined && (expr.Name == BuiltinFunctionExp.ConstName || expr.Name == BuiltinFunctionLn.ConstName)) { // exp(x) if (expr.Arguments.Count == 1) { var arg = ApplyTo(expr.Arguments.First(), ctx); if (arg is LiteralExpression lit) { transformResult = true; if (expr.Name == BuiltinFunctionExp.ConstName) { return(new LiteralExpression(DecimalMath.Exp(lit.Value)).WithToken(expr.Token)); } if (expr.Name == BuiltinFunctionLn.ConstName) { return(new LiteralExpression(DecimalMath.Ln(lit.Value)).WithToken(expr.Token)); } } } } return(base.ApplyTo(expr, ctx, out transformResult)); }
public async Task <OptimizationResult> OptimizeAsync(IOptimizationContext context, AssetFileExtension assetFileExtension) { if (null == assetFileExtension) { assetFileExtension = string.Empty; } if (!context.Assets.Any()) { return(OptimizationResult.Empty); } var orderedAssets = this.Orderer.Order(context.Assets.Where(a => 0 == string.Compare(Path.GetExtension(a.Location.ToString()), assetFileExtension, StringComparison.OrdinalIgnoreCase))); foreach (var asset in orderedAssets) { bool isAssetLoaded = false; foreach (var loader in this.Loaders) { if (loader.CanLoad(asset)) { this.Logger.LogTrace($"Loading asset '{asset.Location}' using '{nameof(loader)}'."); using (var stream = await loader.OpenReadStreamAsync(asset)) { await asset.SetContentAsync(stream); isAssetLoaded = true; } break; } } if (!isAssetLoaded) { throw new InvalidOperationException($"Couldn't find an asset loader to load the asset from '{asset.Location}'."); } } IEnumerable <Asset> assets = orderedAssets; foreach (var transformPair in this.TransformChains.Where(x => 0 == string.Compare(x.Key, assetFileExtension, StringComparison.OrdinalIgnoreCase))) { foreach (ITransform transform in transformPair.Value) { if (null == this.Events?.TransformRunning || this.Events.TransformRunning.Invoke(assetFileExtension, this.Options, transform)) { var inputAssets = assets.ToArray(); assets = await transform.TransformAsync(assetFileExtension, inputAssets); await transform.CleanUpAsync(inputAssets); } } break; } var optimizationResult = new OptimizationResult(); await optimizationResult.InitializeAsync(assets); return(optimizationResult); }
public DefaultOptimizationScope(IServiceProvider serviceProvider) { this.ServiceProvider = serviceProvider; this.DefaultContext = this.AddOrGetContext(Options.DefaultName); }
/// <inheritdoc/> public override MathExpression ApplyTo(BinaryExpression expr, IOptimizationContext <object?> ctx, out bool transformResult) { transformResult = true; var list = expr.Arguments.Select(e => ApplyTo(e, ctx)).ToList();
private Dictionary <VariableExpression, MathExpression> GetVariableSubstitutions(IOptimizationContext <IFunctionInlineSettings> ctx) => ctx.Data <Dictionary <VariableExpression, MathExpression> >().GetOrCreateIn(this);
// name -> function info private Dictionary <string, (CustomDefinitionExpression func, bool hasNotInlinedUses)> GetDefinedFunctions(IOptimizationContext <IFunctionInlineSettings> ctx) => ctx.Data <Dictionary <string, (CustomDefinitionExpression func, bool hasNotInlinedUses)> >().GetOrCreateIn(ctx.Settings);