Giter VIP home page Giter VIP logo

doctordalek1963 / lintrans Goto Github PK

View Code? Open in Web Editor NEW
3.0 3.0 0.0 301.32 MB

lintrans is a tool to visualize linear transformations in 2D.

Home Page: https://DoctorDalek1963.github.io/lintrans

License: GNU General Public License v3.0

Python 96.04% Shell 2.63% TeX 0.35% NSIS 0.97%
a-level a-level-computer-science linear-algebra matrices matrix-calculations matrix-multiplication python python-package python3

lintrans's People

Contributors

doctordalek1963 avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

lintrans's Issues

[Suggestion] The session file should save more stuff

Summary

The session file currently saves the MatrixWrapper and the polygon, but it should also save:

  • the display settings
  • the input vector position

Example

No response

Contact details (optional)

No response

[Suggestion] Display settings should persist

Summary

Display settings should be saved in a dedicated file when the app is closed, and loaded from that file (if it exists) when the app is opened. This would allow the display settings to persist across sessions.

These persistent display settings would be lower priority than the display settings saved in the session file (see #37), so if lintrans is used to open a session file directly, the settings in that file take priority. The session file display settings will also overwrite the current display settings when a session is loaded. If the app is closed with a session file loaded, those display settings get saved to the session file and the global persistence file.

Example

No response

Contact details (optional)

No response

Transformation grid lines often don't get drawn

With the way the transformed grid lines are currently drawn, we often end up with grid lines that should be drawn, not getting drawn. This means that we get some grid lines in the centre, but they don't continue out far enough and the corners look pretty sparse. I'm not entirely sure how, but I need to draw all the possible grid lines within the canvas.

I think I could use a technique like this. Use y = mx + c and find m for the grid lines. Check if this line intersects the line y = max_y between -max_x and max_x. If it does, then draw as many parallel grid lines as possible. For a mostly vertical grid line to fit within the canvas, it must intersect y = max_y or y = -max_y between -max_x and max_x, so we continue to increment multiples of c until we no longer meet this requirement.

A very similar technique can be used if the grid line doesn't intersect y = max_y between the limits. Instead, we look at intersections with x = max_x or x = -max_x.

Animation speed should be variable

The display settings should have an animation speed setting. This number would be used in animating transformations in LintransMainWindow

App should have global settings

The app should have a global settings dialog, available under the File option in the menubar. These settings should include where to save the logs, the logging level, whether to show the "Would you like to read the tutorial?" pop-up at the start, etc.

[Bug] Indirect self references will crash the program

Description

If a matrix is defined directly in terms of itself, you're not allowed to confirm it. It just won't let you. But if it's indirectly referencing itself, then you can confirm the definition, and you will then have a pair of matrices that form a reference loop. Trying to even enter either of these into the expression input box will crash the program as it tries to see if it's a valid expression.

Reproduction steps

  1. Define A to be any matrix
  2. Define B as an expression involving A
  3. Redefine A as an expression involving B
  4. Type A into the expression input box

Crash report

CRASH REPORT at 2022-08-20 12:09:23

SYSTEM INFO:
  lintrans: 0.3.0-alpha
  Python: 3.10.6
  Qt5: 5.15.2
  PyQt5: 5.15.6
  Platform: Linux-5.19.0-2.1-liquorix-amd64-x86_64-with-glibc2.31

CRASH ORIGIN:
  Exception "maximum recursion depth exceeded in __instancecheck__"
  of type RecursionError in call to _compile()
  on line 290 of /home/dyson/.local/lib/python3.10/re.py

POST MORTEM:
  Matrix wrapper:
    A: "B"
    B: "2A"
    I: [1.0 0.0; 0.0 1.0]

  Expression box: "A"
  Currently displayed: [1.0 0.0; 0.0 1.0]
  Animating (sequence): False (False)

  Grid spacing: 85
  Window size: 1000 x 750
  Viewport size: 782 x 650
  Grid corner: (4.6, 3.823529411764706)

  Display settings:
    draw_background_grid: True
    draw_transformed_grid: True
    draw_basis_vectors: True
    label_basis_vectors: False
    smoothen_determinant: True
    applicative_animation: True
    animation_time: 1200
    animation_pause_length: 400
    draw_determinant_parallelogram: False
    show_determinant_value: True
    draw_eigenvectors: False
    draw_eigenlines: False
    draw_untransformed_polygon: True
    draw_transformed_polygon: True

Contact details

No response

[Suggestion] I/O vectors should be displayable independently

Summary

Currently, the I/O vectors can be toggled on and off, but only as a pair, not independently. I think it would be beneficial for these vectors to be toggleable independently in the display settings.

Example

Teachers could show the input vector and ask their students to find the output vector, using visual inspection and matrix multiplication, and then show the output vector to verify their answers.

Contact details

No response

Animation should be able to move between matrices

Currently, all animation moves from the identity to the matrix in the expression box. I propose adding a new method to LintransMainWindow, something like animate_between_matrices(self, start: MatrixType, end: MatrixType) -> None which would animate from start to end. This would require the introduction of new coord transformation methods in VectorGridPlot to translate coords in the transformed vector space to the canvas space.

Animations should also start from the currently displayed transformation by default, so animating M and then animating M again would be equivalent to rendering M^2.

Additionally, the expression box should support syntax like A,B, which would animate transformation B, and then transformation A. Pressing render would simply render AB, but pressing animate will do it in stages.

Logging should be an option

Python has an extensive stdlib logging module, which I could definitely use. We could log matrix evaluations and rendering information with different logging levels. The user would have the option to direct this log to a file or stdout, and adjust the logging level (info by default).

App should support incremental animations

As referenced in #12, animation should support comma syntax in the input bar. Animating A,B would be equivalent to animating to B, waiting for a moment, then animating to AB.

Likewise, something like A+2rot(45),B^2,3C would be animated in stages as 3C, then (B^{2})(3C), then (A+2rot(45))(B^{2})(3C), so each section gets multiplied together each time.

When a comma-syntax expression is in the input box, the animation button will be enabled, but the standard render button will be disabled.

[Suggestion] Zoom sensitivity should be adjustable

Summary

When using lintrans on a laptop with a trackpad, scrolling can be an issue when the sensitivity of the trackpad is low, meaning that it's hard to zoom with much precision.

I think an option in the global settings could remedy this issue by allowing zoom sensitivity to be adjusted.

Example

No response

Contact details (optional)

No response

Matrices defined as expression should be dynamic, and evaluate their expression only when needed

Currently, when a matrix is defined in terms of an expression, that expression is immediately evaluated and the new matrix has that resultant value.

Say we define matrix A as 2B^2. If the value of B changes, then A does not. It retains the value of evaluation at definition time. I propose that instead, A is defined as the expression itself, which is re-evaluated whenever it's needed. So if B changes, then A is re-evaluated the next time it's used.

Expression syntax should support parentheses

Matrix expression should be allowed to parenthesise other matrix expressions inside themselves. For example, 2(AB)^2 would be equivalent to 2 A^{2} B^{2}, and (2A)^{2} 3B would be the same as 4A^{2} 3B. This would also allow for things like (A^T)^2, which are currently impossible.

Validating and evaluating these expressions would likely be recursive, and parsing them presents a considerable challenge using the current parsing method.

[Suggestion] Matrix definitions should be nullable

Summary

I think that there should be the ability to "undefine" matrices. It's all well and good to overwrite them, but you sometimes want them gone completely. This would be as simple as wrapper['M'] = None on the backend. In the GUI, there should be a button next to each matrix in the InfoPanelDialog to "undefine" it.

Example

No response

Contact details (optional)

No response

[Bug] The parser won't continue after an anonymous matrix

Description

The parser fails to correctly parse expressions with anonymous matrices in them. It can parse anonymous matrices on their own, or as part of an expression if they're wrapped in parentheses, but won't continue to parse after an anonymous matrix if it occurs outside of its own parentheses. That means that something like [-1 0; 0 1]^2 doesn't actually square the matrix.

Reproduction steps

Here's a table of expressions:

expression parse list
3[-1 0; 0 1]^2+A^-1-3M [[('3', '[-1 0;0 1]', '')]]
3([-1 0; 0 1])^2+A^-1-3M [[('3', '[-1 0;0 1]', '2')], [('', 'A', '-1')], [('-3', 'M', '')]]
A^-1-3M+3[-1 0; 0 1]^2 [[('', 'A', '-1')], [('-3', 'M', '')], [('3', '[-1 0;0 1]', '')]]
A^-1-3M+3([-1 0; 0 1])^2 [[('', 'A', '-1')], [('-3', 'M', '')], [('3', '[-1 0;0 1]', '2')]]

Crash report

No response

Contact details (optional)

No response

[Bug] lintrans cannot easily be put at the side of the screen

Description

On GNOME with X11, lintrans cannot be put at the side of the screen (Super+LeftArrow or Super+RightArrow). I can press the key combination but nothing happens. It works fine with other apps. I have also heard that on Windows, lintrans takes up more than half of the screen, and the expression box falls off the bottom.

I think this is because the minimum width is 1000 pixels, which is more than half of the standard HD screen width of 1920 pixels. Reducing the minimum size (but maybe keeping 1000x750 as the default) should hopefully fix this.

Reproduction steps

  1. Open lintrans
  2. Press Super+RightArrow (or Windows+RightArrow)
  3. Observe that it doesn't work as expected (it should fill exactly one half of the screen)

Crash report

N/A

Contact details (optional)

No response

[Bug] It crashed after animating for a bit

Description

animated 6 times in a row

Reproduction steps

D every time

Crash report

CRASH REPORT at 2022-10-03 10:12:29

SYSTEM INFO:
  lintrans: 0.4.0-alpha
  Python: 3.10.4
  Qt5: 5.15.2
  PyQt5: 5.15.6
  Platform: Linux-5.15.0-48-generic-x86_64-with-glibc2.31

CRASH ORIGIN:
  Exception "argument 1 overflowed: value must be in the range -2147483648 to 2147483647"
  of type OverflowError in call to _draw_determinant_text()
  on line 637 of /home/dyson/repos/lintrans/src/lintrans/gui/plots/classes.py

POST MORTEM:
  Matrix wrapper:
    A: [1.0 1.0; 0.0 2.0]
    B: [1.0 2.0; 0.0 2.0]
    C: [1.0 -1.0; -1.0 -1.0]
    D: [2.0 -9.0; 3.0 7.0]
    I: [1.0 0.0; 0.0 1.0]

  Expression box: "D"
  Currently displayed: [-5798404.641761554 -58024780.49779437; 19341593.49926479 26437584.523679763]
  Animating (sequence): True (False)

  Grid spacing: 35
  Window size: 1920 x 1018
  Viewport size: 1702 x 918
  Grid corner: (24.314285714285713, 13.114285714285714)

  Display settings:
    draw_background_grid: True
    draw_transformed_grid: False
    draw_basis_vectors: True
    label_basis_vectors: False
    smoothen_determinant: True
    applicative_animation: True
    animation_time: 1200
    animation_pause_length: 400
    draw_determinant_parallelogram: True
    show_determinant_value: True
    draw_eigenvectors: False
    draw_eigenlines: False
    draw_untransformed_polygon: True
    draw_transformed_polygon: True
    draw_input_vector: True
    draw_output_vector: True

Contact details

No response

Drawing too many lines when orthogonal

To reproduce this bug, and compare "(0.01I)^2" with "(0.01I)^2rot(0.1)" and see that when the basis vectors are horizontal and vertical, way too many lines are drawn. This causes severe lag, especially when zoomed out.

I'm pretty sure this bug is in _draw_parallel_lines(), although I'm not sure exactly where.

[Suggestion] The epsilon distance around draggable and snappable points should be larger

Summary

Currently, the mouse cursor has to be less than 5 pixels from the basis vector tip or polygon point that the user is trying to drag. It also has to be less than 0.1 grid units away from an integer coordinate to snap to it. These numbers should both be higher.

I think the best way to handle this would be using an option in the global settings. The user could configure both distances independently and perhaps even toggle snapping to integer coordinates. This would require creating a proper GUI for the global settings, but the require infrastructure is already in place for that. It would also mean integrating the automatic update type into this GUI and removing the config file (which was meant to be temporary anyway).

Example

Most teachers and students will be using lintrans on a laptop. Using the trackpad precisely can be quite finicky, so a larger radius around draggable points and snappable integer coordinates would be useful.

Contact details (optional)

No response

Compatibility with older Python versions

As far as in aware, the only reason we don't support 3.9 is because of the TypeGuard in src/lintrans/typing_/__init__.py. Since this is just a typing thing for mypy, could we conditionally import it or maybe extract it out to a .pyi file to allow the program to run with Python 3.9? Type checks would be done with GitHub Actions with the most recent version of Python, but the actual program would run on multiple versions. All these versions would get unit tested.

Circular import error when installing normally

When installing lintrans with pip install ., it installs fine, but then importing it or running python -m lintrans will result in a circular import error. I don't know why this happens, but it's fine if you use editable mode and do pip install -e ., which is what I use and what the compile guides use anyway.

This isn't a problem, I'm just logging it with an issue for completeness.

Crashes when rendering or animating determinant 0 matrices

When rendering a matrix with determinant 0, the program crashes, complaining that it can't convert infinity to integer when trying to draw the grid lines. When animating, it crashes near the end of the animation, as everything collapses into a lower dimension. When we're rendering a matrix with determinant 0, we shouldn't draw the grid lines.

Display settings should be implemented

There's a button called Change display settings which is currently disabled. I intend for this button to open a dialog with checkboxes. This dialog will return a DisplaySettings dataclass object, which will be an attribute of the plot. Then the rendering methods can respect the settings in this object when rendering. Having it as one object would also making saving easier, as we can just have this as an attribute on the SaveObject.

Proposed display settings:

  • Show determinant as parallelogram
  • Label determinant with its value
  • Determinant text should be properly centered in the parallelogram
  • Show invariant lines (eigenlines)
  • Label eigenlines with eigenvalues

Visual matrix definitions should be implemented

I need to implement defining matrices visually. This is a key part of the app and I think I've got most of the groundwork done in terms of classes and structures. I just need to create the DefineVisuallyDialog class and implement dragging the basis vectors.

[Suggestion] The user should be prompted to save even if they haven't saved a file previously

Summary

Office software like Microsoft Word will have a titlebar like *Untitled - Word and will prompt the user to choose a file and save their work before exiting. lintrans does this, but only if the user has already chosen a file to save to. I propose that they should be prompted even if they haven't chosen a file.

Example

When you've been using lintrans for a while and you've defined several matrices, it's common to want to save them. However, lintrans doesn't currently prompt the user, making it very easy to accidentally lose that work.

Contact details (optional)

No response

Grids should be toggle-able in `DisplaySettings`

I think that the background axes should always be visible, but the background and transformed grids (arguably the basis vectors as well) should be toggle-able in the display settings. This will reduce clutter when trying to view things like eigenlines.

Additionally, as a small point here, the order in which we draw things is important, since each thing gets drawn on top of the next. We should be drawing the background grid first, and the transformed grid last.

Animation of ~180° rotations and reflections

Currently, when animating a 180° rotation or a reflection, there will be a pause and then the basis vectors will jump to their new positions. This is because we're trying to keep the determinant constant. And for the same reason, rotations close to 180° (roughly 160° - 200°) speed up in the middle of their animation because the components of the basis vectors have to travel significantly different distances but the determinant lock keeps them on the unit circle.

The save and load options in the file menu should be functional

We should be able to save and load sessions. A session would consist of the matrix_wrapper object and the expression currently in the input box. A SaveObject would be created, pickled, and saved to a binary file. We could then load this binary save file at a different time.

This SaveObject would be a simple dataclass containing things like the current expression, matrix wrapper, and display settings.

Matrices with very large det will crash when smoothing det

When animating a matrix with very large elements, taking the determinant raises an error from NumPy. This results in a program crash. This is easily seen when animating from a det 0 matrix to a very high det matrix, but can also be seen when animating from I. We'll need a try/except clause somewhere to show an error message when this happens, but I'm not completely sure where.

Crash when animating certain large matrices

The 32-bit integer limit of Qt is relevant for all calls to a draw method on a QPainter object. However, LintransMainWindow._is_matrix_too_big() only checks the coordinates of the basis vectors. Problems occur when we end up animating towards a large matrix. I'm not entirely sure what the problem is, but we end up trying to draw a line that's way out of bounds for the canvas in _draw_parallel_lines().

To reproduce this bug, try to animate "(999I)^2".

To fix this, I propose a signal emitted by VisualizeTransformationWidget and a slot on LintransMainWindow. The signal would be emitted when the matrix was too big for the canvas, and then slot would stop animation and create the warning dialog box.

Additionally, the canvas coords methods should probably be bounded.

[Bug] Transitional animation with commas won't reset when the target matrix is the same

Description

When using transitional animation and commas in the expression, the plot won't reset if the target matrix is the same as the start matrix.

Reproduction steps

  1. Define A as any matrix
  2. Turn off applicative animation
  3. Try to animate A,A,A
  4. See that it animates to A and then hangs until the animation time is over

Crash report

No response

Contact details (optional)

No response

[Suggestion] The definition name dropdown should default to the first undefined matrix

Summary

When defining a matrix, the dropdown should default to the first matrix which has not been previously defined. If all matrices already have a definition, then use A.

Example

It is a common problem that a user will accidentally overwrite A instead of defining a new matrix, because they didn't remember to choose a new name.

This would also solve the issue of having to remember which names you'd already used, since the default name would be undefined.

Contact details (optional)

No response

[Suggestion] Expression history

There should be a history of expressions that the user has evaluated. They could scroll through them with the up and down arrow keys, much like a shell prompt. This would make re-using expressions much easier.

Zooming in and out should be an option

The user should be able to zoom in and out when using the scroll wheel over the canvas. This might be as simple as adjusting the grid_spacing, but there are likely other things to adjust. The reset button should also reset the zoom level.

The main transformation view should support input and output vectors

There should be the option to have a vector in the main transformation view which the user can drag around and see a corresponding output vector. So if we're visualizing the transformation defined by M, then the user can drag around the vector v, which is defined in terms of background grid coords, and then we can also show the output vector Mv. Similar to this old Desmos prototype: https://www.desmos.com/calculator/dpcgriuq6v

Light and dark themes

The app should support full light and dark themes. We can use the darkdetect module to detect dark mode independent of OS, but we need styles and/or palettes for light and dark mode. The default Qt style is called Fusion, although there's no official dark mode variant. I'll probably find someone else's implementation and tweak it for lintrans.

I'm not entirely sure how I'm going to handle colours for vectors etc. Maybe that's handled with palettes? I'll have to do more research.

Animation should smoothly animate determinants

When animating a transformation, we're currently ignoring the determinant. Ideally, we would smoothly animate between determinant of 1, to the determinant of the matrix. This would mean that the animation looks significantly smoother.

I think we can do this by multiplying matrix_move by some number, which starts as 1 / det, but increases up to 1. Possibly not, I'm not sure.

[Suggestion] Anonymous matrices

Matrix expressions should support simple MATLAB/Octave-style matrices. These would not be assigned to a name, and would thus be anonymous.

The syntax for these matrices is like so (the space after the semicolon is optional):

  • [1 2; 3 4]
  • [2.3 -5.2; 10 -1]

They could be used like any other matrix:

  • 2[3 -2.1; 7 0.1]^2
  • (3rot(-45)A^T[-6.43 -1; 3 2.9])^-1

This should just be a case of updating the parser.

Animation should not block scrolling or resizing the window

Currently, while an expression is animating, the user cannot scroll or resize the window. If you scroll, then the change in zoom will only take effect after the animation is complete. Resizing the window simply isn't possible.

I don't know how to allow for handling these events while we're animating. Most of the time spent in the animate_expression method is in time.sleep(0.01). Perhaps if this was asynchronous, the Qt event loop could handle QWheelEvents and QResizeEvents while we're animating.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.