Obtaining terms in an expansion
randyk
created: 2006-01-05 16:19:08
I have an expansion involving N factors:
(a[0][0] + a[0][1]) (a[1][0] + a[1][1])
  (a[2][0] + a[2][1]) ... (a[N-1][0] + a[N-1][1])
for which I'm trying to find general expressions for the 2^N terms involved when this is all multiplied out. Getting an expression for two of the terms is straightforward when the 2nd indices of the a coefficients are the same:
$C[0] = 1;
$C[$N-1] = 1;
for ($i=0; $i<$N; $i++) {
    $C[0] *= $a->[$i]->[0];
    $C[$N-1] *=  $a->[$i]->[1];
}
but I'm stuck on the problem of getting the other terms. Can someone see a way to do this? Thanks.
Re: Obtaining terms in an expansion
created: 2006-01-05 16:24:16
Could you elaborate on why you need to do this? It sounds an awful lot like homework to me.
Re^2: Obtaining terms in an expansion
BUU
created: 2006-01-05 16:30:35
Who cares if it's homework? He's provided a clear and concise explanation of his problem, he provided the code he's tried so far, what more do you want? Does it really matter for which purpose the ultimate solution will be applied?
Re^2: Obtaining terms in an expansion
created: 2006-01-05 16:44:18
It's not a homework problem, although I can see how it might look like one. The problem arises in something we're looking at involving quantum entanglement - each of the a[i][0] + a[i][1] terms (i=0, 1, 2, ..., N-1) represents a two-level quantum state. N such terms multiplied together thus represents a product state of N two-level states. We're then seeing if a general state can be written in this form - if it cannot, then the degree to which it can't is a measure of the degree of entanglement.
Re^3: Obtaining terms in an expansion
created: 2006-01-05 21:08:45
my $prod = 1; # multiplicative identity, of course

for ( @a )
{
    my($x,$y) = @$_;
    $prod *= $x + $y;
}

That does what you describe, but it's not 2^N. Not sure where the discrepancy lies...

We're building the house of the future together.
Re: Obtaining terms in an expansion
created: 2006-01-05 16:31:17
Do you mean something like
my $mul = 1;
foreach my $i (@$ar) {
   my $sum = 0;
   foreach my $j (@$i) {
      $sum += $j;
   }
   $mul *= $sum;
}
Re^2: Obtaining terms in an expansion
created: 2006-01-05 17:03:30
I should have supplied an example of what I was looking for. For example, for N=2:
( arr[0][0] + arr[0][1] ) ( arr[1][0] + arr[1][1] )
what I want to find is
C[0] = arr[0][0] arr[1][0]
C[1] = arr[0][0] arr[1][1]
C[2] = arr[0][1] arr[1][0]
C[3] = arr[0][1] arr[1][1]
It doesn't matter if the coefficients come out in this order, of course.
Re^3: Obtaining terms in an expansion
created: 2006-01-05 17:54:11
I don't see an operator between arr[0][0] and arr[1][0], so I presume the parenthesis mean you want to multiply.

Your description does not adequately explain what you want, particularly the (a[N-1][0] + a[N-1][1]).

Indices from your example:

0,0 1,0
0,0 1,1
0,1 1,0
0,1 1,1
Don't follow. They should be:
0,0 1,0
0,0 1,1
1,0 1,0
1,1 1,1
2,0 1,0
2,1 1,1
3,0 1,0
3,1 1,1
...
The wrong element is incrementing -- a[0][N-1] * a[1][0], a[0][N-1] * a[1][1].

Furthermore, this makes no sense. Are a[0][1] and a[1][1] use repeatedly throughout? If so, why not change them into constants?

Celebrate Intellectual Diversity

Re^3: Obtaining terms in an expansion
created: 2006-01-05 19:26:05

If 2^N could become m^n, then you could use a recursive solution:

#! perl -slw
use strict;

sub expand{
    return @{ $_[0] } if @_ == 1;
    map{
        my $x = $_;
        my @part = expand( @_ );
        map{ $x * $_ } @part;
    } @{ pop @_ };
}

my @mat = ( [ -1, 2 ], [ 3, -4 ] );
printf +("%s " x @mat ) . '= ',  map{ "[ @$_ ] " } @mat;
print join ' ', expand( @mat );

@mat = ( [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], );
printf +("%s " x @mat ) . '= ',  map{ "[ @$_ ] " } @mat;
print join ' ', expand( @mat );

@mat = ( [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], );
printf +("%s " x @mat ) . '= ',  map{ "[ @$_ ] " } @mat;
print join ' ', expand( @mat );

__END__
P:\test>junk
[ -1 2 ]  [ 3 -4 ]  = -3 6 4 -8
[ 1 2 ]  [ 3 4 ]  [ 5 6 ]  = 15 30 20 40 18 36 24 48
[ 1 2 3 ]  [ 4 5 6 ]  [ 7 8 9 ]  = 28 56 84 35 70 105 42 84 126 32 64 96 40 80 120 48 96 144 36 72 108 45 90 135 54 108 162

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Obtaining terms in an expansion
created: 2006-01-05 17:28:54
If I understand correctly, (one way of looking at the problem) you just need a way to combine N iterators where each iterator iterates through two items. list_iter() and comb_iter() in node 122941 would do that.
Re: Obtaining terms in an expansion
created: 2006-01-05 18:19:01
Does this do what you want?
my $n = $ARGV[0] || 5;
my @terms = qw( a[0][0] a[0][1] );
foreach my $i (1 .. $n) {
    @terms = map { ("$_ a[$i][0]","$_ a[$i][1]") } @terms;
}   
foreach my $i (0 .. $#terms) {
    print "term[$i] = $terms[$i]\n";
}   
Re^2: Obtaining terms in an expansion
created: 2006-01-05 18:40:25
You have N terms going in, and N terms coming out. this is considered 2 terms, so there are 4 expressions returned. He says in the OP that he wants 2^N expressions returned.
Re^3: Obtaining terms in an expansion
created: 2006-01-06 10:16:18
That's funny, because when I run the program for N=2, I get:
term[0] = a[0][0] a[1][0] a[2][0]
term[1] = a[0][0] a[1][0] a[2][1]
term[2] = a[0][0] a[1][1] a[2][0]
term[3] = a[0][0] a[1][1] a[2][1]
term[4] = a[0][1] a[1][0] a[2][0]
term[5] = a[0][1] a[1][0] a[2][1]
term[6] = a[0][1] a[1][1] a[2][0]
term[7] = a[0][1] a[1][1] a[2][1]
So perhaps I have an off-by-one error, but certainly I'm generating 2^N terms.
Re: Obtaining terms in an expansion
created: 2006-01-05 19:01:24
So you want to compute an outer product? For two 1-dimensional terms (i.e. vectors) you have:
[a1...an]' * [b1...bn] = [a1*b1 ... a1*bn; ...; an*b1 ... an*bn]
which can be written "a_i * b_j" using physicists' tensor notation. For two 2-dimensional terms (i.e. matrices) you have a tensor product like "a_ij * b_kl", and you can generalize this to any rank (and to other operations besides "*"). I think [cpan://PDL] can compute outer products for low ranks, but you'll probably need to create an iterator or some such to avoid running out of memory with higher ranks.
Re: Obtaining terms in an expansion
created: 2006-01-05 19:57:40
ok, so the 2^N terms are each a product of N terms, a[i][j], where j can be 0 or 1 and i goes from 0 to N-1
ie, each one looks like, say
a[0][0] * a[1][0] * a[2][1] * a[3][0] * ... * a[N-1][1]
So, we want do some binary magic.
how about something like:
#!/usr/bin/perl -wl
use strict;
use Data::Dumper;

my $N = 4;
my $size = 32;
my $arr = [[1, 2],
           [3, 4],
           [5, 6],
           [7, 8]];

my @C;

foreach my $m (0..2**$N - 1) {

    my $vec = "";
    vec($vec, 0, $size) = $m;
    my @bits = split(//, unpack("B*", $vec));
    splice(@bits, 0, $size - $N);

    # so @bits now contains the binary expansion of $m
    # with exactly $N bits, as you can verify by uncommenting
#    print join "::", @bits;


    $C[$m] = 1;
    # now we multiply the $N terms $arr->[i][j]
    # where j is the i-th bit in the binary expansion of $m
    $C[$m] *= $arr->[$_][$bits[$_]] for 0..$N-1;
}

print Dumper \@C;

note, $size must be a power of 2, for vec to work, and unless you're on a 64-bit machine, it probably cannot be more than 32.

also, this works for $N no more than 31(32?) - but you may have other problems (memory say), if you want to go above that.

Hope this helps.
Re: Obtaining terms in an expansion
created: 2006-01-05 20:01:41
I don't like how this question was asked, and seems I'm not the only one -- even after your reply to clarify, I still can't understand what you are after or why.

Are you multiplying polynomials? Taking the square root of a hamiltonian? Calculating the angular velocity of a catapulted gerbil? :)

Maybe it would help if you would link to an article describing the process you are trying to model in perl.

Re^2: Obtaining terms in an expansion
created: 2006-01-05 20:08:05
hmm.. that seems pretty clear to me : [id://521365|here]
The problem arises in something we're looking at involving quantum entanglement - each of the a[i][0] + a[i][1] terms (i=0, 1, 2, ..., N-1) represents a two-level quantum state. N such terms multiplied together thus represents a product state of N two-level states. We're then seeing if a general state can be written in this form - if it cannot, then the degree to which it can't is a measure of the degree of entanglement.
Re^2: Obtaining terms in an expansion
created: 2006-01-05 21:05:46

I apologize if the motivation wasn't clear. At a mathematical level, it's a problem of multiplying N polynomials, each of which has two terms:

For N=2:
(a+b)*(c+d) = ac + ad + bc + bd

For N=3:
(a+b)*(c+d)*(e+f) = ace + acf + ade + adf +
                  + bce + bcf + bde + bdf
What I was after was an explicit expression for each of the 2**N terms on the right-hand-side of these equations.

As for why one would want to do this beyond a homework question, this problem arises in theories of quantum computing, particularly in trying to write an arbitrary state in terms of what's called the computational basis for an N-qubit state.

Re^3: Obtaining terms in an expansion
created: 2006-01-06 01:46:51
I believe that to solve this you would need to create two separate arrays; one to contain the variables on the left side of the equation and another to contain each of the terms on the right side of the equation. Since you know that you will have 2**N variables on the left side, you would want to create an array named, say, Variable{2**N-1) to contain the variables. Then you would create an array Terms2**N-1 to contain the terms generated by multiplying the polynomials. I don't think one would need a two dimensional array. The first part of the program code could pop up a message box asking what N is, and then it would create the arrays as I described above. Then the code would step through array Variable[] multiplying the variables as appropriate and placing the resulting terms into array Terms[]. So the expansion is simply the sum of the elements of array Terms2**N-1. I am new to Perl so I am still working on actual code to do what I've described. I think that this is an interesting problem. BTW, ignore those hyperlinks..there should be brackets there but it's late and I'd rather sleep than read the writeup formatting tips tonight:)
Re^3: Obtaining terms in an expansion
QM
created: 2006-01-07 12:10:25
Completely irrelevant time waster:
#!/your/perl/here

use strict;
use warnings;

{ # closure for sub terms
  
  my @term_list = ('A'..'Z', 'a'..'z');
  
  sub terms
  {
    my $N = shift;
    my $last = 2*$N-1;
    my @pairs;
    my $index = 0;
    my $globber = '';
    while ( $index < $last )
    {
      $globber .= '{' 
               . $term_list[$index++] 
               . ',' 
               . $term_list[$index++]
               . '}';
    }
    my $terms = join ' + ', glob($globber);
    return $terms;
  }

} # end closure for sub terms

foreach my $n (1..5)
{
  my $terms = terms($n);
  print "N=$n: <", $terms, ">\n";
}

exit;

__OUTPUT__
N=1: 
N=2: 
N=3: 
N=4: 
N=5: 

-QM
--
Quantum Mechanics: The dreams stuff is made of

Re: Obtaining terms in an expansion
created: 2006-01-06 03:42:56
Math::Combinatorics can be used to iterate through the 2**N permutations.
Re^2: Obtaining terms in an expansion
created: 2006-01-06 07:52:59
Actually 2**N is the number of subsets of a set of cardinality N, while the number of permutations of a set of N distinct elements is N! (faculty). ivancho used the subset theme quite succesfully in this node above.
Re^3: Obtaining terms in an expansion
created: 2006-01-06 08:23:58
In a way you are correct, except that it's "factorial" not "faculty" - I used the word permutations a bit too loosely.

However, the module Math::Combinatorics can still be used to iterate through the 2**N subsets as well as the nCr combinations and the N! permutations.

Re^4: Obtaining terms in an expansion
created: 2006-01-06 14:34:06

Thank you, for pointing me to the "factorial"
Note to self: Don't transfer mathematical/technical terms from German to English without consulting a dictionary first.

Also, would you be able to give example code for the subset iteration with Math::Combinatorics?

If there is an easy way to do so, it has escaped me.

The closest I saw in the docs was that example to generate:
"Morse signals: diferent signals of 3 positions using the two symbols - and .".

Now Morse signals of length 3 are surely one-to-one and onto the subsets of a 3 element set (set elements = pos in signal; element not/contained = dot/dash)

This iteration is like computing 2**n as sumk=0..n nCk

At least this is not trivial application of the modules methods.

Re^5: Obtaining terms in an expansion
created: 2006-01-06 17:19:14
I guess that's as good as it gets from [cpan://Math::Combinatorics] - doable, but not very natural.

There are plenty of other iterators out there that give all the subsets, though - [cpan://List::PowerSet], [cpan://Data::PowerSet], [cpan://Algorithm::ChooseSubsets] - We just have to convert them to give a bit mask instead - ie:

use List::PowerSet qw/powerset_lazy/;
my @set = (0) x $N;
my @C   = (1) x 2**$N;
my $M = 0;
my $ps_itr = powerset_lazy(0 .. $N-1);
while (my $ref_set = $ps_itr->()) {
    $_ = 1 for local @set[@$ref_set];
    $C[ $M ] *= $arr->[ $_ ][ $set[$_] ] for 0 .. $N-1;
    $M++;
}
Re^5: Obtaining terms in an expansion
created: 2006-01-09 05:09:41
The 2**N doesn't need to be computed anyway. next_multiset() will just keep returning each possible set until all have been returned, at which point it returns undef().

Everything but the troll

perlmonks.org content © perlmonks.org and BrowserUk, BUU, choedebeck, DungeonKeeper, educated_foo, ikegami, InfiniteSilence, ivancho, jdporter, pKai, QM, randyk, runrig, Scott7477, tphyahoo, trammell

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03