Giter Club home page Giter Club logo

Comments (10)

djeis97 avatar djeis97 commented on August 21, 2024

I hacked together a solution for this. If I had the time, I would do a proper fork/pull request, but for now here are my thoughts.

Firstly, a method on quantity for lists, (list unit power), both for consistency and to simplify the actual reader macro:

(defmethod quantity ((ty cons))
  (expt (quantity (first ty)) (second ty)))

I tried to use the defquantity syntax here, but I couldn't get it to work properly.

Then, the reader macro leverages the quantity function and multiplication of quantities:

(defun quantity-transformer-reader-macro (stream subchar arg)
  (let ((expr (read stream t)))
    `(* ,@(iter:iter (iter:for item :in expr)
            (iter:collecting `(quantity ',item))))))

This has the advantage of supporting anything accepted by quantity and *, allowing units to concisely be applied to whole vectors/matricies, for example.

from cl-ana.

djeis97 avatar djeis97 commented on August 21, 2024

While using my quick modification for a few things, I noticed that there's a flaw- it prevents using list literals for anything but exponents in the reader macro, so all tensors have to be arrays. My first instinct is this:

(defun quantity-transformer-reader-macro (stream subchar arg)
  (declare (ignorable subchar arg))
  (let ((expr (read stream t)))
    `(* ,@(iter:iter (iter:for item :in expr)
            (if (and (typep item 'cons)
                     (eq (first item) 'quote))
                (iter:collect item)
                (iter:collect `(quantity ',item)))))))

This allows quoted objects to bypass the quantity conversion. However, this is quickly moving away from a simple hack/mod and I'd like feedback before I move any further.

from cl-ana.

ghollisjr avatar ghollisjr commented on August 21, 2024

I had actually forgotten about the reader macro and had made quite a few changes to the way the system worked without updating it.

I've changed the reader-macro so that it should support derived units; can you pull and confirm?

from cl-ana.

djeis97 avatar djeis97 commented on August 21, 2024

As far as I can tell, that change works just fine. My only issue is how it passes through the first item, which is then evaluated like a lisp form- it makes for an odd inconsistency with other reader macros, like #(), which assume all their arguments are compile-time literals. This forces using quote to pass a list as a tensor. I actually had similar feelings about using quote in my last comment as a way to bypass quantity, as it also forces using quote in an odd way (although the circumstances there are a little different). I'm not sure what the right answer is here, so what do you think?

Here's what it looks like now:

#q((cos (* 2 pi)) :meter)
#q('(2d0 3d0) :weber)

Quoting the first item would disallow the first option entirely, but would make this possible:

#q((2d0 3d0) :weber)

Note that this doesn't change using arrays:

#q(#(1d0 2d0) :weber)

When I was checking this I noticed another related problem. I'm assuming the reason for printing quantities as (* scale unit) is so they can be read back in, right? Well, that doesn't work when the quantity is part of another data structure, like a list, as the reader will never evaluate the code the printer generates. The way arrays solve this, I think, is by actually creating the array at read time. I suspect that the #q() macro would be best for this by having it just call make-instance (or *, to support tensors) and reader-macro-units->quantity itself. This does, however, limit the extensibility of the macro- it would only support units that were in the system at the time the macro is read, so none of the units defined in the file where the macro is used would be available. In a multi-file project this wouldn't be much of an issue, but it would be something to note. Also, this would require the macro assuming the first argument is a literal, so it can pass it directly to make-instance as the scale (or just to *).

from cl-ana.

ghollisjr avatar ghollisjr commented on August 21, 2024

I'm currently working on a total solution at the moment; as it stands I've changed the unit-scale so that it gets taken literally.

There is an existing problem as you've noted with using the quantity reader-macro for full print and read symmetry since in order to use derived units these need to be known at read-time at the moment. I'm working on a fix which would remove this limitation by only expanding units during a calculation; I'll update once it's committed.

Thank you by the way for all the help; it's been a while since I worked on cl-ana.quantity and it's nice to know someone is finding it at least interesting enough to play with!

from cl-ana.

ghollisjr avatar ghollisjr commented on August 21, 2024

I've updated the quantity situation as follows:

  • Quantities are created at read time.
  • The reader-macro takes both the scale and units literally.
  • The quantity function has a new method on quantities which expands units properly so that derived units can safely be used in the reader macro.
  • Quantities have a make-load-form method so that #q(...) forms can be in compiled code.

I think this works well; can you think of anything else/improvements?

from cl-ana.

djeis97 avatar djeis97 commented on August 21, 2024

As far as I can tell, that should work fine. However, I mentioned before about applying quantities to tensors, as in #q((1.0d0 2.0d0) :meter). I'm not sure if this should be considered an abuse of syntax, but having checked that with your newest commit I realize that passing scale literally takes you to a strange spot where all the math works, but interacting with the components of the tensor is awkward.

Basically, I can (* #q((1.0d0 2.0d0) :meter) 5.0) and get #q((5.0d0 10.0d0) :meter) and (* #q((1.0d0 2.0d0) :meter) :second) and get #q((1.0d0 2.0d0) :meter :second), but I can't (product #q((5.0d0 10.0d0) :meter) to get #q(50.0d0 :meter). This is an odd limbo that I think needs to either be explicitly supported (for example, by using multiplication between the scale and unit at read time to produce, at least for the examples before, a list of quantity objects) or explicitly discouraged (through docs or a warning, for example).

By the way, I love the work you've put in to this library. It's easy to use, well documented, and gets right in to making practical scientific computing with lisp easy. Happy to contribute.

from cl-ana.

ghollisjr avatar ghollisjr commented on August 21, 2024

Just updated so that quantities containing sequences are expanded at read-time, and also actually fixed the arithmetic functions so that units not available at read-time are expanded once any arithmetic function is applied.

So now #q((1.0d0 2.0d0) :meter) yields (#q(1.0d0 :meter) #q(2.0d0 :meter)) and the same for any nested sequence.

I'll wait for your confirmation, and thank you for the kind words!

from cl-ana.

djeis97 avatar djeis97 commented on August 21, 2024

That looks good to me. I noticed your comment in the readme, took a look through the define-quanitity-method code, and I think I have a suggestion. Want me to open up a new issue for that?

from cl-ana.

ghollisjr avatar ghollisjr commented on August 21, 2024

Sounds good.

from cl-ana.

Related Issues (20)

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.