Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Second draft of linearalgebra.mac for the contrib folder. #1185

Open
wants to merge 29 commits into
base: master
Choose a base branch
from

Conversation

LukeLongworth
Copy link
Contributor

As before, I don't intend for this pull request to be accepted yet. This is just me publishing the latest version for people to look at.

This is the latest version of #1148 which I will subsequently close. This version marks the point where I've stopped writing new functions (for now) and am now using this file to write my quizzes. I have included two files; linearalgebra.mac which is the file intended for eventual use, and linearalgebra_no_test.mac which is the same, but has no s_test_case lines, as these were causing issues when importing to questions with simp:true. A separate issue, #1184, has been raised concerning this.

The files contain:

  • Convenience functions for student vector input
  • Various predicate functions for vector and matrix properties
  • Functions to manipulate/extract parts of matrices
  • Functions to convert collections of vectors into a locally standard form (currently preferring lists of lists or matrices)
  • Functions to compare objects, typically checking for independence, or equivalence to subspaces.
  • Functions to convert collection of vectors to a basis
  • Extension of significantfigures to work for matrices
  • Extension of norm and cond functions to use the 2-norm
  • Extension of linsolve to accept matrix input and optionally use least squares
  • A function to produce smallest integer vector parallel to given vector (useful for eigenproblems!)
  • rowspace and nullTspace functions to pair with columnspace and nullspace
  • Rayleigh quotient calculation
  • Algebraic and geometric multiplicities of eigenvalues
  • Computing various matrices and factorisations, including rectangular diagonal matrix, projection matrices, QR, Jordan form, (orthgonal) diagonalisation, SVD, and pseudoinverse.

Still to-do:

  • Possibly write some eigenvalue/eigenvector predicates (need to determine what is actually useful)
  • Work on the disp_eqns function that produces nice LaTeX for displaying systems of linear equations.
  • More functions will likely get added (and possibly removed) as work continues on local linear algebra course.

I think I've figured out my workflow now, and will keep everything in this branch, which I think means that I can update this pull request directly? I will figure that out when it comes to it.

Version 0.2 of linearalgebra.mac
Remove the s_test_case for vec_convert that seems to be causing issues.
The convenience functions `c` and `r` throw errors regularly if non-conforming vectors are added/multiplied inappropriately, so the original solution of directly converting to matrix form was inappropriate. 

The solution is to keep `c` and `r` as inert functions and use `vec_convert` to remove these as needed. Correspondingly, `vec_convert` now uses `errcatch` and will return the original expression when errors arise. A new predicate function, `vec_convertedp`, will detect whether an expression was successfully converted to matrix form.
Whilst editing questions I have found that saving and loading has been very burdensome compared to normal and my theory is that it runs all tests on every save, and on every preview (perhaps with deployed variants this would stop). This file exists with no `s_test_case` lines to see if the load times are improved.
Declared `c` and `r` to be nonscalar so that they behave appropriately with other matrices in expressions.
Fixed the vector display functions; they now display the tex-formatted entries rather than just the plaintex (how did I miss this earlier??)
Prevented divide by zero errors in integerify
Fixed subspace_equiv
Added col_vecp and row_vecp
v0.2 of linearalgebra.mac features most of the functions I expect to use, and test cases for almost all of these functions.  It contains:
- Convenience functions for student vector input
- Various predicate functions for vector and matrix properties
- Functions to manipulate/extract parts of matrices
- Functions to convert collections of vectors into a locally standard form (currently preferring lists of lists or matrices)
- Functions to compare objects, typically checking for independence, or equivalence to subspaces.
- Functions to convert collection of vectors to a basis
- Extension of significantfigures to work for matrices
- Extension of norm and cond functions to use the 2-norm
- Extension of linsolve to accept matrix input and optionally use least squares
- A function to produce smallest integer vector parallel to given vector (useful for eigenproblems!)
- rowspace and nullTspace functions to pair with columnspace and nullspace
- Rayleigh quotient calculation
- Algebraic and geometric multiplicities of eigenvalues
- Computing various matrices and factorisations, including rectangular diagonal matrix, projection matrices, QR, Jordan form, (orthgonal) diagonalisation, SVD, and pseudoinverse.

Still to-do: 
- Possibly write some eigenvalue/eigenvector predicates (need to determine what is actually useful)
- Work on the disp_eqns function that produces nice LaTeX for displaying systems of linear equations. 
- More functions will likely get added (and possibly removed) as work continues on local linear algebra course.
Copy of linearalgebra.mac v0.2.3 (committed 8th May 2024) with the s_test_case lines removed.
Implemented old fix for integerify (missed in the upgrade to 0.2.3).
Implemented old fix to integerify (missed in upgrade to 0.2.3)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, the fact that you (@LukeLongworth) have a _no_test.mac file vindicates my proposal in issue #1184 to move all the tests into a _test.mac file!

@sangwinc
Copy link
Member

sangwinc commented May 8, 2024

@LukeLongworth, thanks so much for pushing on with all of this. It looks super useful! I do like the r and c input mechanism. Like the oo etc. input for intervals, it's minimal and reasonable to remember.

We are about to refactor a lot of the Maxima code to include docs within the code, and then automatically generate the user docs from the docs in the code. That puts all the docs into one place. We might, at that point, move the test cases back into the main codebase but strip them out when we include the code within the question. I do really like the principle of having docs, code and tests all adjacent in one file. Perhaps we could have an email discussion about where you are with this? Would you like to include this in the next release and is (part?) of it ready?

Deleting file with plan to rename `linearalgebra_no_test` to `linearalgebra`
Mostly a documentation update. 

Also added checks in lin_indp and subspace_equiv so that they don't throw errors when given lists of lists of unequal length.
* @param[matrix] M a matrix
* @return[boolean] Does M have orthogonal columns?
*/
orthogonal_columnsp(M):= ev(diagp(transpose(M).M),simp);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the diagp be outside the ev?

I also noticed that sometimes, even with simp, complicated expressions (with square roots as they may appear in the context of orthonormal matrices) sometimes don't get fully simplified. For example,
image only collapses into the identity matrix when applying expand. I wonder if it's worthwhile adding this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the ev is fine in either position. I got a bit paranoid about simplification when writing, as I kept finding that certain functions or expressions were returning unevaluated unexpectedly. My interpretation of this particular expression is "take the expression diagp(transpose(M).M) and evaluate it with simplification turned on", so the transpose(M).M should still be evaluated as expected before the diagp predicate runs. My very quick check now suggests that both are fine, but if I see a counter-example I'm very happy to swap them.

Yes, that's a good point on expand. Could you please send me the problem case you've screenshotted above? I'll need to figure out which functions will need that and that looks like a good test case to use.

Thanks for your help with little project Georg! It's great to have a second pair of eyes on this :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair point about the ev, my intuition was that diagp returns a boolean anyway so I thought you'd want to simplify the expression within diagp, but I guess technically it might as well not evaluate the if-clauses and return them as is, for some reason, and if simplification is on, it'll apply recursively everywhere so no harm putting it on the outside? You probably have a better idea of how all of this works than I do...

The use case where I encountered this simplification issue is actually slightly more complex as I'm using a custom scalar product. I've been trying to reproduce the issue for the standard scalar product, but so far without success.
Anyway, below is some maxima code that you can run to see that expand sometimes does make a difference.

/* Compute orthogonal projection with respect to a custom scalar product */
proj(u, v, sp) := sp(v,u)/sp(u,u)*u;
/* Gram-Schmidt orthogonalization with respect to a custom scalar product */
gram_schmidt(M, sp) := block([u_1, u_2,u_3,v_2,v_3,AA],
    /*Prepare Gram-Schmidt process*/
    u_1: col(M,1),
    v_2: col(M,2),
    v_3: col(M,3),
    /*orthogonalize*/
    u_2: v_2 - proj(u_1, v_2, sp),
    u_3: v_3 - proj(u_1, v_3, sp) - proj(u_2, v_3, sp),
    /*normalize*/
    u_1: u_1/sqrt(sp(u_1,u_1)),
    u_2: u_2/sqrt(sp(u_2,u_2)),
    u_3: u_3/sqrt(sp(u_3,u_3)),
    AA: addcol(u_1, u_2, u_3),
    return(AA)
);
/* A symmetric positive definite matrix and corresponding bilinear form (scalar product) */
A: matrix([3,-1,0],[-1,3,0],[0,0,2]);
bform(w,v) := transpose(w).A.v;
/* Orthogonalize the standard basis with respect to this scalar product */
baseM: ident(3);
OB: expand(gram_schmidt(baseM, bform));
/* Customized predicate functions */
orthogonal_columnsp(M, spMat):= diagp(ev(transpose(M).spMat.M,simp));
orthonormal_columnsp(M, spMat):= if matrixp(M) then is(ev(transpose(M).spMat.M,simp) = ident(second(matrix_size(M)))) else false;
/* Check outputs */
orthogonal_columnsp(OB, A);
orthonormal_columnsp(OB, A);
ev(transpose(OB).A.OB, simp);
ev(expand(transpose(OB).ev(expand(A.OB), simp)), simp);

- Added support for displaying augmented matrices easily using an inert function and texput. Also added `aug` and `de_aug` to convert matrices in and out of this mode.
- Reworked `triu`, `tril`, `get_diag`, `triup`, `trilp`, `diagp`, and `diag_entries`. These should be significantly more efficient now. Thanks for the `genmatrix` tip-off Georg Osang!
- Added `un_vec_convert` to change matrices into `c` and `r` form. Mostly intended for making teachers' answers the format we expect students to use.
- Added a line to `make_list_of_lists` that will take a single vector and make it a list of a list. e.g. `[1,2,k]` -> `[[1,2,k]]`.
- Edited `orthogonal_columnsp` and associated functions to forcibly expand the matrix before comparing. Thanks Georg! 
- Added support for eigenproblems. This includes
  - `eigenvaluep` and `eigenvectorp` which check whether a given value or vector is "eigen". Optionally checks them against a given vector or value respectively. 
  - `get_eigenvalue` and `get_eigenvector` to extract the corresponding one from a given. Much nicer than using `eigenvectors` when you only want one! Can also orthonormalise the basis if requested.
  - Moved `Rayleigh` up to be with these.
- Added support for vector parametric equations. It's a bit sparse, but these functions can check whether a given expression is of the desired form, and if so extract the useful bits (linear offset, direction vectors, parameters) and then format this nicely for TeX display. This is the only remaining TODO: add support for other vector input options, notably lists and ntuples. This will likely not happen in 2024. 
- Finished off `disp_eqns` and added `mat_disp_eqns` to do the same given `A` and `b` instead of a list of equations. 
- I've given up on PLU for now and have thus removed this section. I think that `rref`, `triangularize`, `echelon` and `lu_factor` do a good enough job, though it's still baffling to me that none of them do partial pivoting, nor do they avoid scaling rows unnecessarily.
Added test cases for v0.2.4
Added 
- rowscale and columnscale, intended as complements to rowop, rowswap, columnop and columnswap. It is odd that the third elementary row/column operation is not included by default.
- setrowmx, setcolmx, and setdiagmx, intended as complements to setelmx. Used to overwrite rows, columns or diagonals.
Added tests for new functions in linearalgebra
Copy link
Contributor

@geoo89 geoo89 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just had a quick pass through the functions you define. Mostly some nitpicking about names. (I find maxima not that consistent with its naming and some function names aren't very memorable, but maybe it's worth striving a bit for consistent naming.)

I will be authoring some linear algebra questions in the next month so will hopefully get to test this some more.

* @param[list] ex A list of numbers
* @return[number] The greatest common divisor of all elements in ex
*/
lgcd(ex):= block([ex_gcd,ii],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could probably simplify this by using lreduce (or similar) instead of a for loop: https://maxima.sourceforge.io/docs/manual/maxima_21.html#lreduce

* @param[matrix] ta a mxn matrix
* @return[boolean] Are ex and ta row equivalent?
*/
row_equiv(ex,ta):= block(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be called row_equivp, given that this is a predicate function?

Same for col_equiv and subspace_equiv.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're probably correct here. For some reason I had in my head that a predicate function would only take a single input, but a quick Google disproves that. I am wanting to do a (hopefully) final pass of function name changes before starting on question-writing in earnest, so I will fix these up then. My colleague had some other suggestions that I want to implement too.

* @param[matrix] M a matrix
* @return[boolean] Is M a symmetric matrix?
*/
sym_p(M):= if squarep(M) then is(M = ev(transpose(M),simp)) else false;
Copy link
Contributor

@geoo89 geoo89 Jun 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The underscore in sym_p is inconsistent with the other predicate functions in its vicinity. Is symp already an existing keyword, or is there some other reason for this? Maybe symmetricp is a decent name too given that the others aren't abbreviated either?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

symmetricp already exists in the ctensor package but is forbidden, hence why I used the shortened name here as a maybe temporary option. I agree that symp is better than sym_p though, I'm not sure why I broke convention here. Perhaps I just read it is a misspelling of "simp" and didn't like it.

* @param[matrix] M An mxn matrix
* @return[matrix] The same matrix with all entries below the diagonal set to 0
*/
triu(M):= block([imax,jmax],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that diag is already taken as a keyword, but the naming inconsistency irks me a bit. Do you think it would be worthwhile renaming triu and tril to get_triu and get_tril?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather keep triu and tril as they are and change get_diag to something else. I chose triu and tril to match the equivalent functions in NumPy because I am expecting to do a bit of Python CodeRunner alongside STACK. This is also why I chose column_stack as a function name. I wonder if something as simple as diagonal would work, it seems to be an unused function name.

* @param[matrix] M An mxn matrix
* @return[boolean] Is this matrix upper triangular?
*/
triup(M):= block([tri,imax,jmax,ii,jj],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that you changed this from the earlier definition triup(M):= if matrixp(M) then is(M = triu(M)) else false; .

Just curious, is that for performance reasons or were there some other drawbacks?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whilst I was changing up triu etc I decided that it felt wrong to loop through the whole matrix to create triu(M) and then compare it element by element to M when I could just do it in one loop, so I changed it. I don't expect performance to be impacted massively (unless M is huge for some reason), but performance was indeed the motivation for the change.

Changed the names of some functions per suggestions from others; added two more vector parametric equation functions to test whether a given point is in a given affine subspace and whether a given vector is in a given vector subspace.
Adjusted test cases for recent commit to linearalgebra.mac
* If v is a zero vector, returns false by default as the intended use case is determining whether a given DIRECTION vector is in a subspace.
*
* @param[matrix] v The vector of interest
* @param[list] dir_vecs A list of mx1 matrices that span the subspace. Does not need to be a basis.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think when I wrote this myself, I chose to have a column matrix, where the columns spanned the subspace. I think with this choice it's more explicitly a "list of vectors", rather than an implicit convention on the columns of a matrix.

@sangwinc
Copy link
Member

Thanks @LukeLongworth, that's a lot of work. Given it's in the "contrib" folder I'm happy to merge this into master to make it immediately available. I'm happy to do this. Are you ready?

This is a lot of very useful work, thanks.

@geoo89
Copy link
Contributor

geoo89 commented Jun 21, 2024

I tested this on 4 different servers (our ecampus, our old sandbox, our new sandbox, and the Uni Trieste server). For 3 of them things run quite smoothly.
On our new sandbox, however, the preview doesn't load and then the whole server is unresponsive for a few minutes. Using stack_include with small files works well on that server.

The logs show:

Fatal error: Maximum execution time of 30+2 seconds exceeded (terminated) in /bitnami/moodle/question/type/stack/stack/cas/connector.server.class.php on line 54

At the same time there are also unauthenticated requests to the Maxima service, which stop when cancelling the preview (closing the browser tab).

10.11.2.1 - - [13/Jun/2024:13:42:14 +0000] "POST /versions/2024012900/ HTTP/2.0" 401 172 "-" "-" 77 0.000 [maxima-v2024012900-goemaxima-http] [] - - - - 

For every 401 response from the Maxima service, there is a corresponding timeout message in the Moodle logs.
I'm not sure how it's possible for unauthenticated requests to be sent to Maxima when the username and password is set correctly, but it looks like that is what is happening.

It doesn't matter if the CAS connection timeout is set to 10 secs or 100 secs. This server uses goemaxima (like our other sandbox) and is hosted on google cloud platform, but has fewer resources: 'e2-small' (0.5-2 vCPU, 2 GB RAM) as opposed to 'e2-medium' (1-2 vCPU, 4 GB RAM). I don't think this is a stack_include issue because even when pasting the code directly, we get the same issue.


Technically this is a resources/server configuration issue, and we can resolve it by e.g. giving our server more resources.

But it does seem a bit scary that when importing a question from another server and trying to preview it, it could hang the whole server for a while (unless that's also a server setup issue -- seems a bit strange to me that a single request could hang the entire server).

I wonder if it is worthwhile trying to modularize the library a bit to mitigate this risk, so that users don't have to include everything all the time? Is it possible to have recursive stack_include calls?

@aharjula
Copy link
Member

Is it possible to have recursive stack_include calls?

No. And in particular, it is impossible to conditionally include stuff.

Having that inside the STACK compiler would be inconvenient, and I (as the one who built this first iteration of the include logic) don't believe it is worth it. Personally, I imagine that whatever is in the "contrib" will eventually end up in the core or become fragmented into small parts easier to include. I also imagine that at some point, someone will decide that they do not like this, and they build some wildly more complicated system based on the fact that the include just includes from an address. We might end up with someone setting up an external package management system which constructs a minimal include with all the required parts based on the URL, e.g.: stack_include(".../include?functions=orthonormal_columnsp,gram_schmidt"), could naturally be that package management system would be part of STACK but it could also be a separate thing but it would require some metadata about requirements etc...

@geoo89
Copy link
Contributor

geoo89 commented Jun 21, 2024

I see, that makes a lot of sense.

So with the vision of moving all or a lot of this into core, performance right now is not that relevant in the long run.

stack_include_contrib always takes the latest version from github (according to #971), right? So contributors have to be careful to maintain backward-compatibility, and e.g. splitting up the library once it has been committed is tricky.
Until some sort of package management system exists, would it make sense for stack_include_contrib to include an (optional) commit hash or STACK version?

@aharjula
Copy link
Member

Yes, it (stack_include_contrib) does indeed take the latest version. The docs also say that these are equivalent, thus its the head of the master branch:

stack_include("https://raw.githubusercontent.com/maths/moodle-qtype_stack/master/stack/maxima/contrib/validators.mac");
stack_include_contrib("validators.mac");

Again, as long as we only work with URLs and have no special extra arguments for the inclusion outside that URL, one can simply tune the URL to get the version one wants. So that those who understand the risks and actually pay attention to these issues can just as well do something like this to get a very specific version of something:

stack_include("https://raw.githubusercontent.com/maths/moodle-qtype_stack/97d70c9ebcff641f204a65091836bd489dc323a7/stack/maxima/contrib/prooflib.mac");

If someone wants to make something like stack_include_contrib("prooflib.mac","97d70c9ebcff641f204a65091836bd489dc323a7") to act as some sort of a shorthand for that feel free but I for one would recommend just writing the full URL when need be. I would not add extra arguments at this point as we really do not know if the future will keep "contrib" where it is now and whether URL construction would be that simple.

@LukeLongworth
Copy link
Contributor Author

Thanks for your testing of this @geoo89, I don't have the resources to do that myself and it sounds very useful.

I don't think it's a big problem if stack_include_contrib files don't work on all (especially lower-resourced) servers, as I believe that the content should be used with some care anyway. Crashing the whole server when trying to preview a question is concerning though.

I don't mind breaking this into smaller files, but would appreciate some guidance on best practice. My initial thoughts are:

  • Group similar functions together, trying to minimise dependencies between groups
  • When dependencies are unavoidable, just copy that code in place with some appropriate commenting.
  • Avoid having the same named function appear in two libraries to prevent confusion when including both files in one question.

I also agree with @aharjula's comments. I think that this project has stretched the limits of what stack_include_contrib is intended for, and the appropriate response to issues like this is not to change stack_include but to change the inclusions themselves.

@sangwinc I'm not finding myself making many more changes now (i.e. the occasional urge I'm getting to do more with it is more easily quashed) so you're welcome to add it to contrib if you like. As Georg mentioned, it might be more difficult to split up the file into smaller pieces whilst maintaining backwards compatibility.

As a last comment/thought: if there are key functions that I think make sense as core maxima, where would those belong? Their own file alongside intervals.mac and inequalities.mac, or in assessment.mac generally (or somewhere else)?

if vectorp(ex) then return([list_matrix_entries(ex)]),
if is(op1="matrix") then return(args(transpose(ex))),
ex: args(ex),
if ev(every(lambda([ex2],constantp(ex2) or atom(ex2)),ex),simp) then return([ex]),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While working on some questions, I encountered some unexpected behavior:

I would expect make_list_of_lists([matrix([1],[2],[3]),matrix([2],[3],[4])]) to return [[1,2,3],[2,3,4]], but instead it returns
[[matrix([1],[2],[3]),matrix([2],[3],[4])]], i.e. wrapping the input into another layer of list brackets.
make_list_of_lists([c(1,2,3),c(2,3,4)]) also yields [[matrix([1],[2],[3]),matrix([2],[3],[4])]].

I observed that constantp(matrix([1],[2],[3])) evaluates to true, causing this early return. Some more investigation shows that constantp(matrix([1],[a],[3])) evaluates to false, and consequently make_list_of_lists([matrix([1],[2],[3]),matrix([2],[a],[4])]) and make_list_of_lists([c(1,2,3),c(2,a,4)]) return the expected output [[1,2,3],[2,a,4]].

This inconsistent behavior makes me believe that constantp/atom is maybe not the correct check to do, and maybe a similar type check for some type of iterable like in the first two lines is more appropriate?

Some more experimentation also shows that make_list_of_lists([1,a,g(x),4]) gives an error, because we don't do the early return here (neither constantp nor atom applies to g(x)) and the next line tries to call args on an atom.

As a more general question: What's the rationale for using lists of lists over lists of vectors (like in subspace_equivp and lin_indp) or a matrix (like lin_indp already supports)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi George,

I missed this message, sorry! I did push a fix to make_list_of_lists, as I had independently run into the same issue, and also identified that constantp wasn't doing what I expected. The new version just checks to see whether all elements in the list are scalars, and if so return a nested list. The rationale here is that if someone called make_list_of_lists([1,2,3]) in a linear algebra context I would personally expect the result to be [[1,2,3]] rather than [1,2,3] or [[1],[2],[3]]. I hope this change fixes the problems you highlighted!

To answer the more general question: Probably a coincidence, and I'm happy for extra functionality to be added here. Originally when I was writing these, I tried to account for every reasonable input type which meant that every function had a big list of if-thens at the beginning to put everything into a form that I could work with easily. Eventually I realised I was duplicating a lot of work and decided to move that "cleaning" process into a single function. My vague memory is that the lin_indp function supporting matrices is because I was expecting the use case of "does this matrix have full column rank" to be common enough that it would be annoying to use make_list_of_lists every time. Typing this explanation out has made me feel like I undercut my previous arguments somewhat!

Modify disp_eqns to support parameters
I didn't realise that vectors of constants were also considered constants, so one of the if-statements in make_list_of_lists wasn't behaving as intended. 

There may be a bug in point_in_affine_spacep; its 3rd test didn't work for me when running the whole bank of tests. I think that the problem is that I didn't declare local variables, so I have added that and I hope it fixes it.
%i is NOT the corresponding eigenvalue for matrix([0,-1],[1,0]) and c(1,%i), so the ta should be false.

get_eigenvector returns an empty list rather than false when given an incorrect eigenvalue, so the ta should be [] instead of false.
@sangwinc
Copy link
Member

Thanks for all your continued work on this @LukeLongworth. Rather than pull requests to master, should we set up a branch for this work. Then other people could contribute?

@LukeLongworth
Copy link
Contributor Author

@sangwinc that suits me fine! That could be a good place to experiment with splitting the file up into multiple smaller files too without interfering with the questions that myself and Georg are working on (I assume that we are both importing from my personal branch)

@geoo89
Copy link
Contributor

geoo89 commented Jul 29, 2024

Thanks @sangwinc ! I think a branch for contributions like this might be convenient. I've made some changes that are currently sitting on my fork (updated some functions and added a few). After some discussion with Luke I realized that the tests are meant to run with simp:false, that's why there are still failing. They pass assuming simp:true. I haven't got around to fixing them and I'll be on leave until mid-October, so it'll have to wait until then, unfortunately.

But we already observed that there is some functionality we are using a lot, like the c/r notation, conversion function, and lin_indp/subspace_equivp and a few others which might be nice to have in core at some point. When I'm back, we hope to investigate a bit more what depends on what, and see if we can split the library into smaller units.

@sangwinc
Copy link
Member

@LukeLongworth, just looking through your library. It's a lot of work, and really impressive! Thank you for doing this. What would you like me to do next?

- Fixed a bug in disp_eqns where negative pivots were missing their minus sign when the pivot was not in the first column.
- Added tex1 into the format_as_coeff function as suggested by Georg Osang

TODO: Unit tests need updating.
@sangwinc
Copy link
Member

OK, we do need a branch for this work, otherwise were going to get conflicts between @LukeLongworth and @geoo89 and we don't need to do that!

Luke, could you send a pull request here: https://github.com/maths/moodle-qtype_stack/tree/linear-algebra-beta
and we can then all track that!

@geoo89 I agree that r and c are really useful and could just be in the core. Also @LukeLongworth's library is now getting big and we probably need to split this up anyway before we release it. @geoo89 could you open a discussion about r and c on Zulip and find out what people think, especially from colleagues who don't speak English? They may well want other things...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants