Programming using "Prior Knowledge"

Hello Fellow Rubyists,

Just wanted to introduce/disclose programming using “Prior Knowledge”
based on domain knowledge.

This note in https://github.com/nvijayap/mathematics is self-explanatory

IMPORTANT NOTE:

This program introduces/relies on “Prior Knowledge”
in the domain of mathematics, and avoids
computation where unnecessary.

Also, resorting to computation sometimes doesn’t yield
perfect results as known/anticipated. Example:
(environment: ruby 2.0.0p247 (2013-06-27 revision 41674)
[x86_64-darwin12.4.0])

$ ruby -e “puts Math.sin(Math::PI) # I expect 0”
1.2246467991473532e-16
You may be able to use to good effect in your programs.

Happy Ruby “Prior Knowledge” Programming !

Naga

On Mon, Sep 30, 2013 at 5:33 AM, Naga V. [email protected]
wrote:

Hello Fellow Rubyists,

Just wanted to introduce/disclose programming using “Prior Knowledge”
based on domain knowledge.

This note in https://github.com/nvijayap/mathematics is self-explanatory

I beg to differ. It tells me nothing about why I should be using that
gem. What’s the advantage of using Mathematics.average over doing it
yourself - it’s a one liner anyway? (Btw. the error for empty lists
of numbers might be seen as a bit mysterious.)

IMPORTANT NOTE:

This program introduces/relies on “Prior Knowledge”
in the domain of mathematics, and avoids
computation where unnecessary.

Why do you use #method_missing for #sin and #cos? The implementation
of the two methods is in no way dynamic. You could just code them as
regular methods. That way you would also get error reporting in case
someone passes more than one argument to sin and cos. It’s a mystery
to me why you call a variable which holds degrees “rad” (aka
“radiants”).

Also, “case” might be seen as a bit inefficient. You could use a Hash
for better efficiency:

irb(main):004:0> sin = Hash.new {|h,x|
Math.sin(x)}.merge!(0=>0,Math::PI/2=>1,Math::PI=>0,Math::PI*3/4=>-1)
=> {0=>0, 1.5707963267948966=>1, 3.141592653589793=>0,
2.356194490192345=>-1}
irb(main):005:0> sin[Math::PI]
=> 0

Question is whether it’s worth the added overhead. For all values not
“prior known” you get the old behavior anyway. And if you want nice
(rounded) output, there’s printf (see below).

Also, resorting to computation sometimes doesn’t yield
perfect results as known/anticipated. Example:
(environment: ruby 2.0.0p247 (2013-06-27 revision 41674)
[x86_64-darwin12.4.0])

$ ruby -e “puts Math.sin(Math::PI) # I expect 0”
1.2246467991473532e-16

Yes, but

$ ruby -e ‘printf “%.3f\n”, Math.sin(Math::PI)’
0.000

You may be able to use to good effect in your programs.

Hm…

Cheers

robert

Robert K. wrote in post #1122887:

On Mon, Sep 30, 2013 at 5:33 AM, Naga V. [email protected]
wrote:

Also, resorting to computation sometimes doesn’t yield
perfect results as known/anticipated. Example:
(environment: ruby 2.0.0p247 (2013-06-27 revision 41674)
[x86_64-darwin12.4.0])

$ ruby -e “puts Math.sin(Math::PI) # I expect 0”
1.2246467991473532e-16

Yes, but

$ ruby -e ‘printf “%.3f\n”, Math.sin(Math::PI)’
0.000

And even more to the point:

irb(main):0> printf ‘%.15f’, Math.sin(Math::PI)
0.000000000000000

That’s pretty damn close to 0, if you ask me. And if you want to to be
closer:

irb> require ‘bigdecimal’
irb> require ‘bigdecimal/math’
irb> s = BigMath.sin BigMath.PI(1000), 1000
=> #<BigDecimal:15e0f88,’-0.2689451280 5027876503 4668568112 3104626557
2061945196 3039291663 6186366058 1142512668 9630473349 9820495715
1460161087 1416135178 9643003569 7962658932 1349284854 3949064332
2231580786 1782810477 7802537839 7894670545 7187191875 5140592572
2997079271 1467022134 0051624503 9392256267 7538151880 7356193539
4778247007 1704751775 7803001673 0208580982 0134020955 3401193823
2545853466 5213952486 4740472330 3188330824 8018302374 4330382467
8316579518 9813958658 9343529894 8381551772 6329374998 6826958535
2224777855 5844762013 8314549698 6911071442 1532097170 8417746277
2511648311 0416694837 3357370089 2901399127 4605931619 4978883979
4312388437 8581659915 4672899820 9925716083 5388463613 9685203353
5314325878 5756987635 9416315120 5829003988 8531954939 9173477868
5451489623 3195503850 1090751953 3326386266 9317789620 1846949099
8480102044 7147268693 9451391849 4369207480 6337161738 6538414681
4938615648 8539725637 9951290968 9460331883 5099541436 4605805376
0861991522 2911773841 3095486208 8661258701 0301543689 7327349237
4898748746 0207218665 2496099510 7075139899 5717871356 5255356832
2607876419 7170912949 6015774027 191E-1015’,1044(2295)>

I’m pretty sure that if I specify PI to a thousand decimal places, and
instruct the library to calculate sin to a thousand decimal places, and
it gives me a 1015 zeroes after the decimal point, that’s a zero.

I appreciate where you’re going with this library, and adding knowledge
about PI to the trig functions makes sense (although I wonder why
log/Math::E got no love?), but I’m quite certain that anyone who wants
to control the precision of their answers already has the tools at their
disposal to do so.

I also feel a little uneasy that, while I know beforehand how much
accuracy Math.sin and Math::PI provide, using your library I’m no longer
sure of the precision, depending on the parameters I provide. While
Math::PI gives exactly zero, I don’t know which of BigMath::PI(32) or
BigMath::PI(64) will have the same exact result on a given machine, if
either.

Oh and a minor coding style nitpick: in your overridden sin/cos
functions you called the variable ‘rad’ when it should probably have
been called ‘deg’.

On Tue, Oct 1, 2013 at 5:47 PM, Naga V. [email protected] wrote:

Robert K. wrote in post #1122887:

On Mon, Sep 30, 2013 at 5:33 AM, Naga V. [email protected]
wrote:

Thanks for reviewing and providing valuable comments.

You’re welcome.

into a call, when answer is known from a “domain” space. The
implementation may change down the line while adhering to “Prior
Knowledge” paradigm.

You did not answer my question but I see you changed the implementation.

Agreed; Made some changes by using Hash in some places with latest
release of the gem.

I am sorry to say that but the way you use Hash there shows a certain
lack of understanding. The new code is even slower than before (see
below). Also looking at a recent version [1] lines 166 and 178 are
just plain wrong.

Question is whether it’s worth the added overhead. For all values not
“prior known” you get the old behavior anyway. And if you want nice
(rounded) output, there’s printf (see below).

The aim/goal is to gradually expand on this; Mathematics is just one
domain; “Prior Knowledge” paradigm can encompass other domains. It is a
mesh-in of co-mingling currently known approaches/paradigms with this
“Prior Knowledge” paradigm.

If you wanted to provide an implementation of the “prior knowledge”
paradigm I would have expected a generic piece of code (a library if
you will) which allows others to make use of that paradigm more
easily. I only see mathematical functions with special treatment of a
few particular input values.

$ ruby -e ‘printf “%.3f\n”, Math.sin(Math::PI)’
0.000

It’s not about extent of rounding; it’s about letting out known answer
rightaway. It’s not about getting it work to match with known answer,
it’s about not drilling down further into the computational logistics
when the known answer can be quickly let out.

If you advertise your code the way you do you should probably provide
an example which clearly shows the advantage of your approach. Your
solution is less efficient than simply calling original functions.
Example for Math#sin:

$ ./x.rb
Rehearsal --------------------------------------------------------
Math.sin(0) 0.312000 0.000000 0.312000 ( 0.320018)
Math.sin(0.0) 0.109000 0.000000 0.109000 ( 0.107006)
sin(0) 2.262000 0.000000 2.262000 ( 2.266129)
sin(0.0) 1.934000 0.000000 1.934000 ( 1.925110)
sin2(0) 0.297000 0.000000 0.297000 ( 0.300017)
sin2(0.0) 0.281000 0.000000 0.281000 ( 0.281016)
----------------------------------------------- total: 5.195000sec

                       user     system      total        real

Math.sin(0) 0.327000 0.000000 0.327000 ( 0.323019)
Math.sin(0.0) 0.094000 0.000000 0.094000 ( 0.107006)
sin(0) 2.293000 0.000000 2.293000 ( 2.281130)
sin(0.0) 1.919000 0.000000 1.919000 ( 1.921110)
sin2(0) 0.296000 0.000000 0.296000 ( 0.299017)
sin2(0.0) 0.281000 0.000000 0.281000 ( 0.283016)

see https://gist.github.com/rklemme/6790261#file-test-01-rb

It is just a mixup of
computation and domain knowledge. The domain can be in any space.

As said above: then a general mechanism would be in order. But
basically we have that with Hash#default_proc already:

$ ruby xx.rb
user system total real
fib1 1.294000 0.000000 1.294000 ( 1.297074)
fib2 0.141000 0.000000 0.141000 ( 0.140008)
fib3 0.000000 0.000000 0.000000 ( 0.007000)

https://gist.github.com/rklemme/6790261#file-test-02-rb

Kind regards

robert

[1]
https://github.com/nvijayap/mathematics/blob/b9e74223262fada6a201ef242a1728e594f4f9a4/lib/mathematics.rb

Matthew K. wrote in post #1122901:

I also feel a little uneasy that, while I know beforehand how much
accuracy Math.sin and Math::PI provide, using your library I’m no longer
sure of the precision, depending on the parameters I provide. While
Math::PI gives exactly zero, I don’t know which of BigMath::PI(32) or
BigMath::PI(64) will have the same exact result on a given machine, if
either.

Sorry for replying to myself. I do know that neither of them should,
since 232 is not the same as 1032, but hopefully you get my point.

Robert K. wrote in post #1122887:

On Mon, Sep 30, 2013 at 5:33 AM, Naga V. [email protected]
wrote:

Hello Fellow Rubyists,

Just wanted to introduce/disclose programming using “Prior Knowledge”
based on domain knowledge.

This note in https://github.com/nvijayap/mathematics is self-explanatory

I beg to differ. It tells me nothing about why I should be using that
gem. What’s the advantage of using Mathematics.average over doing it
yourself - it’s a one liner anyway? (Btw. the error for empty lists
of numbers might be seen as a bit mysterious.)

Thanks for reviewing and providing valuable comments.

The gem is just an avenue to express the “Prior Knowledge” programming
style/paradigm.

The gem just includes methods such as “average” as a bridging mechanism
to math words that crop up in conversation/teaching/linguistics.

I will look into handling empty list.

IMPORTANT NOTE:

This program introduces/relies on “Prior Knowledge”
in the domain of mathematics, and avoids
computation where unnecessary.

Why do you use #method_missing for #sin and #cos? The implementation
of the two methods is in no way dynamic. You could just code them as
regular methods. That way you would also get error reporting in case
someone passes more than one argument to sin and cos. It’s a mystery
to me why you call a variable which holds degrees “rad” (aka
“radiants”).

The way it is currently designed/implemented is to quickly let out
answers for known arguments, and rely on Math for the rest - in the
spirit of “Prior Knowledge” paradigm - no need to drill down further
into a call, when answer is known from a “domain” space. The
implementation may change down the line while adhering to “Prior
Knowledge” paradigm.

Also, “case” might be seen as a bit inefficient. You could use a Hash
for better efficiency:

irb(main):004:0> sin = Hash.new {|h,x|
Math.sin(x)}.merge!(0=>0,Math::PI/2=>1,Math::PI=>0,Math::PI*3/4=>-1)
=> {0=>0, 1.5707963267948966=>1, 3.141592653589793=>0,
2.356194490192345=>-1}
irb(main):005:0> sin[Math::PI]
=> 0

Agreed; Made some changes by using Hash in some places with latest
release of the gem.

Question is whether it’s worth the added overhead. For all values not
“prior known” you get the old behavior anyway. And if you want nice
(rounded) output, there’s printf (see below).

The aim/goal is to gradually expand on this; Mathematics is just one
domain; “Prior Knowledge” paradigm can encompass other domains. It is a
mesh-in of co-mingling currently known approaches/paradigms with this
“Prior Knowledge” paradigm.

Also, resorting to computation sometimes doesn’t yield
perfect results as known/anticipated. Example:
(environment: ruby 2.0.0p247 (2013-06-27 revision 41674)
[x86_64-darwin12.4.0])

$ ruby -e “puts Math.sin(Math::PI) # I expect 0”
1.2246467991473532e-16

Yes, but

$ ruby -e ‘printf “%.3f\n”, Math.sin(Math::PI)’
0.000

It’s not about extent of rounding; it’s about letting out known answer
rightaway. It’s not about getting it work to match with known answer,
it’s about not drilling down further into the computational logistics
when the known answer can be quickly let out. It is just a mixup of
computation and domain knowledge. The domain can be in any space.

You may be able to use to good effect in your programs.

Hm…

Cheers

robert

I was wondering this too. The thing that came to mind for me was caching
results for expensive calculations (e.g. factorial), and preloading the
cache. Is that different from “prior knowledge”?

I made a prototype, which I can paste into a gist when I get back to the
computer.

Sent from my phone, so excuse the typos.
On Oct 3, 2013 5:08 AM, “Eric C.”
[email protected]

On Wed, Oct 2, 2013 at 2:43 AM, Robert K.
[email protected]wrote:

Is there already an acknowledged “prior knowledge paradigm” in either
programming or other fields? I’m having trouble finding one. But the way
you and Naga V. have been talking seems to imply that one has already
been recognized and formulated.

Matthew K. wrote in post #1123282:

I was wondering this too. The thing that came to mind for me was caching
results for expensive calculations (e.g. factorial), and preloading the
cache. Is that different from “prior knowledge”?

I made a prototype, which I can paste into a gist when I get back to the
computer.

Sent from my phone, so excuse the typos.
On Oct 3, 2013 5:08 AM, “Eric C.”
[email protected]

factorial was included yesterday as also triangular_number,
binomial_coefficient. caching (in-memory/local/remote/distributed) is
one of several ways; there are other ways as well like rpc/rest/*cloud
calls, depending on the need/nature of the “intelligent function” in the
domain space, and the prior knowledge of the complexity vis-a-vis the
path to take.

Eric C. wrote in post #1123264:

On Wed, Oct 2, 2013 at 2:43 AM, Robert K.
[email protected]wrote:

Is there already an acknowledged “prior knowledge paradigm” in either
programming or other fields? I’m having trouble finding one. But the way
you and Naga V. have been talking seems to imply that one has already
been recognized and formulated.

No; I conceived it per my initial post above.

On Thu, Oct 3, 2013 at 2:49 AM, Naga V. [email protected] wrote:

Eric C. wrote in post #1123264:

On Wed, Oct 2, 2013 at 2:43 AM, Robert K.
[email protected]wrote:

[…]
Is there already an acknowledged “prior knowledge paradigm” in either
programming or other fields? I’m having trouble finding one. But the way
you and Naga V. have been talking seems to imply that one has already
been recognized and formulated.

I don’t think so. The reason would be that this basically falls in
the realm of optimization and the term “prior knowledge” does not
really add information to the former. The way optimizations are
implemented totally depends on the problem domain as Naga already
acknowledged. And, of course, you use all the knowledge you have
about that problem domain when implementing the optimization. There
is hardly a common feature that could be employed across the board. I
think that is also the reason why we cannot see a pattern here which
is worthwhile to be generalized and put into code.

No; I conceived it per my initial post above.

I am sorry to say that but I find it a bit audacious to claim you have
conceived something here. (Granted, there probably are software
patents around for even less sophisticated “inventions”. But that’s a
completely different story.) The way you code indicates to me that
you do not comprehend some basic programming concepts (see your use of
Hash for example). In light of that it is even bolder to make such a
claim publicly.

Regards

robert

Naga V. wrote in post #1123314:

Matthew K. wrote in post #1123282:

I was wondering this too. The thing that came to mind for me was caching
results for expensive calculations (e.g. factorial), and preloading the
cache. Is that different from “prior knowledge”?

I made a prototype, which I can paste into a gist when I get back to the
computer.

factorial was included yesterday as also triangular_number,
binomial_coefficient.

So I see. How much of binomial_coefficient is “prior knowledge”, and
how much is typical boundary case handling?

caching (in-memory/local/remote/distributed) is
one of several ways; there are other ways as well like rpc/rest/*cloud
calls,

… aren’t those just variations of remote/distributed caching?

depending on the need/nature of the “intelligent function” in the
domain space, and the prior knowledge of the complexity vis-a-vis the
path to take.

Sorry… lost me a bit there; does that mean: the trade-off between
calculation costs and latency?

For the record, I lost my prototypes from yesterday, but here’s a bit of
a play around I had this morning:
https://gist.github.com/phluid61/6803544 It’s a simple factorial
calculator/cache. I whipped up a benchmark to compare it against
non-caching function calls (with varying levels of prior knowledge) to
see how it performed. Of course, factorial is not a particularly useful
function (i.e. it’s probably not going to be invoked enough times in the
real world for it to be worth much caching the results). To be honest,
I’m not sure what operations would be useful; maybe sin/cos and sqrt,
if you’re doing a lot of geometry with consistent angles.

On Thu, Oct 3, 2013 at 2:54 PM, Naga V. removed_email_a[email protected] wrote:

No; I conceived it per my initial post above.
similar. What’s wrong with the Hash? It’s the construct to setup a
default value (From http://www.ruby-doc.org/core-2.0.0/Hash.html - You
can set the default value by sending it as an argument to ::new:).

You create the Hash every time the method is invoked. You calculate
Math.sin() for every call yet claim to “quickly let out
answers for known arguments”. But you only do that after filling the
Hash with all the prior knowledge values. Don’t you see how
inefficient that is? Plus, you do not avoid the calculation of
Math.sin for your special input values. This completely flies in the
face of your claim. If you do not recognize that from the source code
you can easily see that from the benchmarks I posted.

Did you look at the gist I posted? There is an example which makes
better usage of Hash to quickly return values.

Cheers

robert

Robert K. wrote in post #1123351:

On Thu, Oct 3, 2013 at 2:49 AM, Naga V. [email protected] wrote:

Eric C. wrote in post #1123264:

On Wed, Oct 2, 2013 at 2:43 AM, Robert K.
[email protected]wrote:

[…]
Is there already an acknowledged “prior knowledge paradigm” in either
programming or other fields? I’m having trouble finding one. But the way
you and Naga V. have been talking seems to imply that one has already
been recognized and formulated.

I don’t think so. The reason would be that this basically falls in
the realm of optimization and the term “prior knowledge” does not
really add information to the former. The way optimizations are
implemented totally depends on the problem domain as Naga already
acknowledged. And, of course, you use all the knowledge you have
about that problem domain when implementing the optimization. There
is hardly a common feature that could be employed across the board. I
think that is also the reason why we cannot see a pattern here which
is worthwhile to be generalized and put into code.

No; I conceived it per my initial post above.

I am sorry to say that but I find it a bit audacious to claim you have
conceived something here. (Granted, there probably are software
patents around for even less sophisticated “inventions”. But that’s a
completely different story.) The way you code indicates to me that
you do not comprehend some basic programming concepts (see your use of
Hash for example). In light of that it is even bolder to make such a
claim publicly.

Claim is based on search conducted, and not having run into anything
similar. What’s wrong with the Hash? It’s the construct to setup a
default value (From http://www.ruby-doc.org/core-2.0.0/Hash.html - You
can set the default value by sending it as an argument to ::new:).

Regards

robert

On Thu, Oct 3, 2013 at 11:30 PM, Matthew K. [email protected]
wrote:

Robert K. wrote in post #1123388:

Did you look at the gist I posted? There is an example which makes
better usage of Hash to quickly return values.

I just noticed that fib3 is a bit aggressive in recalculating values.
If you invoke fib3[49] it calculates 2…49 nicely, but if you then
invoke fib3[50] it recalculates 2…49 despite already having them in the
hash.

Right you are. Good catch!

Compare:

fib4 = Hash.new do |h, n|
h[n] = h[n - 1] + h[n - 2]
end.update(0 => 0, 1 => 1)

I want to spend hours optimising this now.

Not necessary: that’s easily fixed. You just need to record the max
value in the Hash:
https://gist.github.com/rklemme/6790261#file-test-02-rb

Kind regards

robert

Robert K. wrote in post #1123388:

Did you look at the gist I posted? There is an example which makes
better usage of Hash to quickly return values.

I just noticed that fib3 is a bit aggressive in recalculating values.
If you invoke fib3[49] it calculates 2…49 nicely, but if you then
invoke fib3[50] it recalculates 2…49 despite already having them in the
hash.

Compare:

fib4 = Hash.new do |h, n|
h[n] = h[n - 1] + h[n - 2]
end.update(0 => 0, 1 => 1)

I want to spend hours optimising this now.

Robert K. wrote in post #1123514:

On Thu, Oct 3, 2013 at 11:30 PM, Matthew K. [email protected]
wrote:

I want to spend hours optimising this now.

Not necessary: that’s easily fixed. You just need to record the max
value in the Hash:
https://gist.github.com/rklemme/6790261#file-test-02-rb

That was my first approach. For some reason it didn’t have as profound
an effect as I’d expected. I even tried it by making the ‘max’ a
variable in an enclosing scope, but that seemed a bit worse (probably
understandable, depending on how ruby deals with closures and bindings.)

Then I was wondering about the storage and retrieval characteristics of
an Array vs a Hash. I wish I’d committed my code before the weekend, it
appeared that the Hash outperformed the Array slightly, although of
course it’s hard to come up with a meaningful benchmark since Fibonacci
numbers aren’t often used in real applications.

I was also wondering about my purely recursive Hash-based solution, the
effect of flipping around the -1 and -2 terms

fib4 = Hash.new do |h, n|
#h[n] = h[n - 1] + h[n - 2]
h[n] = h[n - 2] + h[n - 1]
end.update(0 => 0, 1 => 1)

I’d have to spend more time on that one, and I’m being pestered by a
5y/o for breakfast right now.

Admin T. wrote in post #1123558:

Well, in some other languages, such as JavaScript and Lua, there is no
Array; “array” is constructed using a Hash. Of course, if you are used
to with languages such as C, you always think that in a compiled
language, Array (direct access) should perform better than Hash.

Given that this is a Ruby forum, and we’re talking about a Ruby script,
with Ruby snippets, it could be reasonable to assume that I meant the
Ruby “Array” class. Specifically, Array as implemented in ruby 2.0-p247
and a recent 2.1-trunk.

I’ve not spent much time digging through array.c but I’m pretty sure it
does follow the C paradigm for arrays (i.e. contiguous fixed-sized
memory blocks), and I assume that each element of the array would be a
VALUE (fixnum, object pointer, etc.) or some equivalent. As such, I’d
expect the lookup time to be smaller than for Hash; therefore I guess
(but didn’t have much time to dig into it) that the performance hit,
such as it was, came from somewhere else. Either some other
under-the-hood overhead, or a glitch in my implementation (I don’t have
the code here to inspect), or since we’re talking microseconds’ or even
nanoseconds’ difference when calculating 50!, maybe even memory caches.
It might even be the fact that Array doesn’t have a default_proc, so I
had to wrap the Array with another object.

I’m also aware that Array does some sort of aggressive expansion, but to
be sure there’s only a single allocation, I tried something like this:

m = ary.length
if n > m
ary[n] = nil
end
(m…n).each{|i| ary[i] = … }

The difference for 51! and fib(50) was, as you’d expect, negligible.

Matthew K. wrote in post #1123547:

Then I was wondering about the storage and retrieval characteristics of
an Array vs a Hash. I wish I’d committed my code before the weekend, it
appeared that the Hash outperformed the Array slightly, although of
course it’s hard to come up with a meaningful benchmark since Fibonacci
numbers aren’t often used in real applications.

Well, in some other languages, such as JavaScript and Lua, there is no
Array; “array” is constructed using a Hash. Of course, if you are used
to with languages such as C, you always think that in a compiled
language, Array (direct access) should perform better than Hash.

Regards,

Bill

Matthew K. wrote in post #1123562:


The difference for 51! and fib(50) was, as you’d expect, negligible.

I think this shows why in some other languages, they don’t bother with
Array.

Regards,

Bill

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs