Probably done for today. Added a start to some caching optimizations.

This commit is contained in:
That_One_Nerd 2024-02-27 16:49:06 -05:00
parent 48476dde69
commit 21c498f445
6 changed files with 147 additions and 8 deletions

View File

@ -0,0 +1,32 @@
namespace Graphing.Extensions;
public static class FormattingExtensions
{
private static readonly string[] sizeUnits =
[
" bytes",
" KB",
" MB",
" GB",
" TB",
" PB",
];
public static string FormatAsBytes(this long bytes)
{
double val = bytes;
int unitIndex = 0;
while (val > 1024)
{
unitIndex++;
val /= 1024;
}
string result;
if (unitIndex == 0) result = val.ToString("0");
else result = val.ToString("0.00");
return result + sizeUnits[unitIndex];
}
}

View File

@ -39,6 +39,8 @@
MenuEquations = new ToolStripMenuItem();
MenuEquationsDerivative = new ToolStripMenuItem();
MenuEquationsIntegral = new ToolStripMenuItem();
MenuMisc = new ToolStripMenuItem();
MenuMiscCaches = new ToolStripMenuItem();
GraphMenu.SuspendLayout();
SuspendLayout();
//
@ -58,7 +60,7 @@
// GraphMenu
//
GraphMenu.ImageScalingSize = new Size(32, 32);
GraphMenu.Items.AddRange(new ToolStripItem[] { MenuViewport, MenuColors, MenuEquations });
GraphMenu.Items.AddRange(new ToolStripItem[] { MenuViewport, MenuColors, MenuEquations, MenuMisc });
GraphMenu.Location = new Point(0, 0);
GraphMenu.Name = "GraphMenu";
GraphMenu.Size = new Size(1449, 42);
@ -125,6 +127,20 @@
MenuEquationsIntegral.Size = new Size(360, 44);
MenuEquationsIntegral.Text = "Compute Integral";
//
// MenuMisc
//
MenuMisc.DropDownItems.AddRange(new ToolStripItem[] { MenuMiscCaches });
MenuMisc.Name = "MenuMisc";
MenuMisc.Size = new Size(83, 38);
MenuMisc.Text = "Misc";
//
// MenuMiscCaches
//
MenuMiscCaches.Name = "MenuMiscCaches";
MenuMiscCaches.Size = new Size(359, 44);
MenuMiscCaches.Text = "View Caches";
MenuMiscCaches.Click += MenuMiscCaches_Click;
//
// GraphForm
//
AutoScaleDimensions = new SizeF(13F, 32F);
@ -154,5 +170,7 @@
private ToolStripMenuItem MenuEquations;
private ToolStripMenuItem MenuEquationsDerivative;
private ToolStripMenuItem MenuEquationsIntegral;
private ToolStripMenuItem MenuMisc;
private ToolStripMenuItem MenuMiscCaches;
}
}

View File

@ -1,4 +1,6 @@
using Graphing.Graphables;
using Graphing.Extensions;
using Graphing.Graphables;
using System.Text;
namespace Graphing.Forms;
@ -346,7 +348,7 @@ public partial class GraphForm : Form
static double Integrate(EquationDelegate e, double lower, double upper)
{
// TODO: a better rendering method could make this much faster.
const double step = 1e-1;
const double step = 1e-2;
double factor = 1;
if (upper < lower)
@ -364,4 +366,33 @@ public partial class GraphForm : Form
return sum * factor;
}
}
private void MenuMiscCaches_Click(object? sender, EventArgs e)
{
// TODO: Replace with a form with a pie chart of the use by equation
// and the ability to reset them.
StringBuilder message = new();
long total = 0;
foreach (Graphable able in ables)
{
if (able is Equation equ)
{
long size = equ.GetCacheBytes();
message.AppendLine($"{able.Name}: {size.FormatAsBytes()}");
total += size;
}
}
message.AppendLine($"\nTotal: {total.FormatAsBytes()}\n\nClick \"No\" to erase caches.");
DialogResult result = MessageBox.Show(message.ToString(), "Graph Caches", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
if (result == DialogResult.No)
{
foreach (Graphable able in ables)
{
if (able is Equation equ) equ.EraseCache();
}
}
}
}

View File

@ -8,23 +8,33 @@ public class Equation : Graphable
private readonly EquationDelegate equ;
private readonly List<Float2> cache;
public Equation(EquationDelegate equ)
{
equationNum++;
Name = $"Equation {equationNum}";
this.equ = equ;
cache = [];
}
public override IEnumerable<Line2d> GetItemsToRender(in GraphForm graph)
{
const int step = 10;
double epsilon = Math.Abs(graph.ScreenSpaceToGraphSpace(new Int2(0, 0)).x
- graph.ScreenSpaceToGraphSpace(new Int2(step / 2, 0)).x) / 5;
List<Line2d> lines = [];
bool addedToDictionary = false;
double previousX = graph.MinVisibleGraph.x;
double previousY = equ(previousX);
for (int i = 1; i < graph.ClientRectangle.Width; i += 10)
double previousY = GetFromCache(previousX, epsilon, ref addedToDictionary);
for (int i = 1; i < graph.ClientRectangle.Width; i += step)
{
double currentX = graph.ScreenSpaceToGraphSpace(new Int2(i, 0)).x;
double currentY = equ(currentX);
double currentY = GetFromCache(currentX, epsilon, ref addedToDictionary);
if (Math.Abs(currentY - previousY) <= 10)
{
lines.Add(new Line2d(new Float2(previousX, previousY), new Float2(currentX, currentY)));
@ -32,10 +42,50 @@ public class Equation : Graphable
previousX = currentX;
previousY = currentY;
}
if (addedToDictionary) cache.Sort((a, b) => a.y.CompareTo(b.y));
return lines;
}
public EquationDelegate GetDelegate() => equ;
public void EraseCache() => cache.Clear();
private double GetFromCache(double x, double epsilon, ref bool addedToDictionary)
{
(double dist, double nearest) = NearestCachedPoint(x);
if (dist < epsilon) return nearest;
else
{
addedToDictionary = true;
double result = equ(x);
cache.Add(new(x, result));
// TODO: Rather than sorting the whole list when we add a single number,
// we could just insert it.
return result;
}
}
private (double dist, double y) NearestCachedPoint(double x)
{
// TODO: Replace with a binary search system.
double closestDist = double.PositiveInfinity;
double closest = 0;
foreach (Float2 p in cache)
{
double dist = Math.Abs(x - p.x);
if (dist < closestDist)
{
closestDist = dist;
closest = p.y;
}
}
return (closestDist, closest);
}
public long GetCacheBytes() => cache.Count * 16;
}
public delegate double EquationDelegate(double x);

View File

@ -13,7 +13,8 @@ internal static class Program
Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
GraphForm graph = new("One Of The Graphing Calculators Of All Time");
graph.Graph(new Equation(Math.Cos));
graph.Graph(new Equation(x => Math.Pow(2, x)));
graph.Graph(new Equation(Math.Log2));
Application.Run(graph);
}

View File

@ -1,7 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
@ -9,6 +8,14 @@
<RootNamespace>Graphing.Testing</RootNamespace>
<AssemblyName>ThatOneNerd.Graphing.Testing</AssemblyName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputType>Exe</OutputType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputType>WinExe</OutputType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Base\Base.csproj" />