factorial table expansion

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

factorial table expansion

R.A.Ward
I'm a novice trying to generate factorial table expansion as described below. I
am able to do this with many nested for loops, but I seem unable to do this in
the proper spirit of lua table and iteration techniques (e.g. the permutations
generater in PiL 9.1). 

The idea is to turn a table of tables like this:

factors={
	side     = { left = -1, right = 1 },
	duration = { short = 200, med = 500, long = 800 },
	validity = { valid = 1, invalid = 0 }
}

into a table containing one table for every possible combination of factor
levels, for the above example a table of 2*3*2 entries:

conditions = {
	{ left, short, valid },
	{ left, short, invalid },
	{ left, med, valid },
	{ left, med, invalid },
	{ left, long, valid },
	{ left, long, invalid },
	{ right, short, valid },
	{ right, short, invalid },
	{ right, med, valid },
	{ right, med, invalid },
	{ right, long, valid },
	{ right, long, invalid },
}


My code below should illustrate what I mean about not being in the spirit of
lua! I'd very much appreciate ideas about how to improve this novice effort!
Rob

-----

function icount(t)
 local k, v
 local i = 0
 for k, v in pairs(t) do
  if v then
   i = i+1
  end
 end
 return i
end

function createdesign(design, repsPerBlock, nblocks)
 local repsPerBlock = repsPerBlock or 1
 local nblocks = nblocks or 1
 local nconds = 1
 local nlvls = {}
 local conds = {}
 local nfactor = icount(design)
 for f,lvls in pairs(design) do
  if lvls then
   nlvls[f] = icount(lvls)
   nconds = nconds * nlvls[f]
  end
 end
 
 blocksize = nconds*repsPerBlock
 ntrials = blocksize * nblocks
 for i = 1, ntrials do
  conds[i] = {}
 end

 ncycles = 1
 for f, lvls in pairs(design) do 
  nlevels = icount(lvls)
  trlsPerCyc = blocksize/ncycles
  nreps = trlsPerCyc/nlevels
  trialsthisblock = 0
  while( trialsthisblock < blocksize) do
   for cycle = 1, ncycles do
    for level in pairs(lvls) do
     for rep = 1, nreps do
      for block = 1, nblocks do
       trialno = (block-1)*blocksize + trialsthisblock+1
       value = level
       print(trialno,value)
       conds[trialno][f] = value
      end -- block
      trialsthisblock = trialsthisblock+1
     end -- rep
    end -- level
   end -- cycle
   ncycles = ncycles * nlevels
  end -- trialsthisblock
 end -- factor
        
 return conds
end



--
This mail sent through http://webmail.bangor.ac.uk

Reply | Threaded
Open this post in threaded view
|

Re: factorial table expansion

Paul Chiusano
Ah, okay, you are computing a cartesian product of some sets. There's
a snazzy, functional programming way of doing it using a 'fold' and
just a simple pairwise cartesian product function. Here is the code --
if it is Greek to you, let me know and I can try to explain it better:

-- some utility functions, boorrrring!
local yield = coroutine.yield

local function yieldAll(coro)
   for e in coro do yield(e) end
end

function makeTable(iterator)
   local t = {}; for e in iterator do t[#t+1] = e end
   return t
end

function flatten(obj)
   return coroutine.wrap(function()
      if type(obj)~="table" then
         yield(obj)
      else
         for _,e in ipairs(obj) do
            yieldAll(flatten(e))
         end
      end
   end)
end

-- Okay, now the meat of it:

function fold(tab, operator)
   local seed = tab[1]
   for i=2,#tab do
      seed = operator(seed, tab[i])
   end
   return seed
end

function cartesian(t1, t2)
   local c = {}
   for _,i in ipairs(t1) do
      for _,j in ipairs(t2) do
         c[#c+1] = {i,j}
      end
   end
   return c
end

--- Example use
local groups = { {'a','b'}, {1,2,3}, {'p','q','r'} } -- add as many as you want
local product = fold(groups, cartesian)
for _,p in ipairs(product) do
   local t = makeTable(flatten(p)) --> e.g. {a,2,q}
   print(unpack(t))
end

And voila! the output:
a       1       p
a       1       q
a       1       r
a       2       p
a       2       q
a       2       r
a       3       p
a       3       q
a       3       r
b       1       p
b       1       q
b       1       r
b       2       p
b       2       q
b       2       r
b       3       p
b       3       q
b       3       r

Best,
Paul


Reply | Threaded
Open this post in threaded view
|

Re: factorial table expansion

R.A.Ward
In reply to this post by R.A.Ward
On Sun Apr 2, 2006 20:06, Paul Chuisano wrote:

>Ah, okay, you are computing a cartesian product of some sets. There's
>a snazzy, functional programming way of doing it using a 'fold' and
>just a simple pairwise cartesian product function. Here is the code --
>if it is Greek to you, let me know and I can try to explain it better:

That looks brilliant.  It will take me some time to understand it, but
I'm looking forward to that.
Thanks!
Rob