Comments (10)
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.
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.
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.
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.
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.
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.
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.
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.
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.
Sounds good.
from cl-ana.
Related Issues (20)
- HDF5 1.10 breaks cl-ana HOT 3
- Cannot load due an error in antik by lisp-unit test library HOT 1
- sb-ext:delete-directory can be replaced by uiop:delete-directory-tree HOT 1
- HDF5 String support HOT 1
- cl-ana.csv-table: smart-read-from-string should return NIL for empty strings HOT 2
- We would like to name an official chatroom for cl-ana HOT 6
- How to control cl-ana.table-viewing gnuplot behavior? HOT 1
- What is the proper way to work in a columnar fashion? HOT 11
- cl-ana.tensor:tensor-map raises condition when used with vectors with the fill-pointer different than capacity HOT 4
- Functions in cl-ana.generic-math can enter infinite loops with sequences with nils HOT 2
- cl-ana, meet numcl
- New areas in cl-ana: in-memory analysis/summarizing, and data pre-processing HOT 11
- `cl-ana.reusable-table:reusable-table` can be misleading and lead to surprising bugs HOT 3
- `cl-ana.table:open-plist-table` does not respect lower-case symbols HOT 1
- Readibility Suggestion: predicates should end in `p` or `-p`.
- Inaccuracies in the "plotting" documentation on the Wiki HOT 2
- No applicable method for the generic function cl-ana.table:table-load-next-row HOT 1
- problem in drawing log function HOT 3
- local hdf5-cffi HOT 4
- Some systems failed to build for Quicklisp dist HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cl-ana.