I'm learning Raku and something's confusing me.
To calculate the sum of elementwise products of two lists (at least one of them finite) I was hoping to be able to write something like
@a Z*[+] @b
But it doesn't give the expected result.
Using the [+] @a Z* @b
form works as expected
> my @a = 2...6;
[2 3 4 5 6]
> my @b = 5...1;
[5 4 3 2 1]
> @a Z @b;
((2 5) (3 4) (4 3) (5 2) (6 1))
> @a Z* @b;
(10 12 12 10 6)
> [+] @a Z* @b
50
But it doesn't like it when I chain the Z*
and [+]
together
> @a Z*[+] @b
(30)
> @a Z*+ @b
(10)
> @a +Z* @b
===SORRY!=== Error while compiling:
Undeclared name:
Z used at line 1
> @a +[Z*] @b
6
> @a [Z*]+ @b
(10)
> @a [Z*][+] @b
(30)
I imagine there's some precedence issue going on here but don't find adequate examples in the Raku documentation.
I found unexplained behavior with >>*<<
as well:
> [+] @a >>*<< @b
50
> @a [+][>>*<<] @b
125
> @a [>>*<<][+] @b
Lists on either side of non-dwimmy hyperop of infix:<*> are not of the same length while recursing
left: 5 elements, right: 1 elements
in block <unit> at <unknown file> line 1
Questions
6
, (10)
, (30)
and 125
?This is the standard form of Sum of Product. It is formed by O Ring the minterms of the function for which the output is true. This is also known as Sum of Min terms or Canonical disjunctive normal form (CDNF). It is just a fancy name.
- Mathematics Stack Exchange Can a sum of products be split as a product of two sums? Imagine that the vertical segments are your P 's. Then the product of sums is the area of the entire rectangle, whereas the sum of products is only the red area. So the original summation is definitely not the same as this double sum.
A canonical Product of Sum expression can be converted into Minimal Product of sum form by using Karnaugh map (K-map). Another method for converting canonical into minimal is by using Boolean algebraic theorems. The use of K-map is very easy that is why K-map is preferred.
Each combination has a min terms denoted by small m and its decimal combination number written in subscript. Each of these minterms will be only true for the specific input combination. There are few different forms of Sum of Product.
Is it possible to evaluate the product-sum of two lists in this way?
Yes.
Let's start with chaining:
One can write Raku code that chains right-to-left but we'll stick with left-to-right.
A left to right English reading of what you're calling "product sum" would be "sum of products of elements of these lists". So we want sum on left, product next, lists last.
There is a built in sum
but no built in product
, so we need to deal with the latter. One way is to write [Z*]
as a reduction (which means it has to appear on the left of the lists it reduces over). Another is to write a new product
function.
Putting the above together, here are some of the ways we can write a "product sum":
say [+] [Z*] @a, @b; # 50 (closest to what it seems you want)
say sum [Z*] @a, @b; # 50 (`sum` is idiomatic)
say sum zip :with(&[*]), @a, @b; # 50 (some prefer `zip :with(&[*])` over `[Z*]`)
say sum product @a, @b; # 50 (requires a user defined `sub`)
sub product (|lists) { zip :with(&[*]), |lists }
Doing it as above means you can use any number of lists rather than just two.
If you really want to stick with infix notation, which limits you to two lists, you can do that for the product part:
say [+] @a Z* @b; # 50 (using infix sequential shallow zip metaop)
say [+] @a >>*<< @b; # 50 (using infix parallel nesting hyper metaop)
say sum @a Z* @b; # 50 (replacing `sum` with `[+]` reduction)
say sum @a >>*<< @b; # 50
What's happening across the different chained variants to cause results like
6
,(10)
,(30)
and125
?
Raku is correctly doing what your code expresses.
The following code examples explain all the code/results @Zaid shared. You (any reader, not just @Zaid) may have to do some work to understand why; if you can't work out how these examples explain one or more of Zaid's results, please comment and I'll be happy to explain in a comment and/or update this answer and will thank you for your question/comment.
say my @a = 2...6; # [2 3 4 5 6]
say my @b = 5...1; # [5 4 3 2 1]
say [+] [5,4,3,2,1]; # 15
# Same as:
say sum @b; # 15
say 2 Z* 15; # (30)
# zip stops once shortest list exhausted, so same as:
say [2,3,4,5,6] Z* 15; # (30)
say +@b; # 5
# `+` coerces argument(s) to number, so short for:
say elems @b; # 5
# Same as:
say elems [5,4,3,2,1]; # 5
say 2 Z* 5; # (10)
#say +foo; # Error while compiling: Undeclared ... foo
# Same effect as:
#say foo; # Error while compiling: Undeclared ... foo
say [Z*] @b; # (120)
# Same as:
say 5 Z* 4 Z* 3 Z* 2 Z* 1; # (120)
say @a [Z*] 5; # (10)
# square brackets redundant, and
# zip stops once shortest list exhausted, so same as:
say 2 Z* 5; # (10)
say [+] @a >>*<< @b; # 50
say [>>*<<] @b; # 120
# hypers redundant if both args scalars, so same as:
say [*] [5,4,3,2,1]; # 120
# (5 * 4 * 3 * 2 * 1)
say @a [+] [>>*<<] @b; # 125
# square brackets round infix `+` redundant, so same as:
say @a + [>>*<<] @b; # 125
# hypers redundant if both args scalars, so same as:
say 5 + [*] @b; # 125 (5 + 120)
say @a [>>*<<][+] @b; # Same as:
say @a [>>*<<] [+] @b; #
say @a [>>*<<] sum @b; #
say @a >>*<< sum @b; #
#say @a >>*<< 15; # Lists on either side ... not of the same length
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With