lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Francesco Abbate wrote:
> I better thought about this problem and the __call metamethod does not
> make the affair since, for assignments, the syntax:
> m(i,j) = value
> will be invalid.

I've gotta get your GSL shell installed. I wrote a similar thing a few
years back but I never followed through to the end. I had to ditch GSL
anyway due to its license (which I mistakenly thought was LGPL when I
started the project). But I kept the Lua part, switching to another
vector/matrix package.

Well, you've inspired me to do some crazy coding. I use the __call
metamethod on a tensor (matrix of possibly more dimensions) to return an
element-reference object whose own __call metamethod allows access to
the element. I also provide set() and get() functions may be used for
the element-reference object. Finally, just for fun, I overload __index
and __newindex to get or set the element, but that requires a dummy index.

Below is the bottom portion of the code, followed by a run. The full
code follows that. I like the way that recursion, varargs and the
metamethods work together. A fuller code base would have checks on the
dimensions of items so that sub-tensors could be set, etc.

Enjoy!

-- Here we go...
p = tensor(2,3,4)
print(p:tostring())

-- Using call interface.
p(2,3,4)(234)        -- __call with a value sets the element.
print(p(2,3,4)())    -- __call without a value gets the element.
print(p:tostring())

-- Using a dummy index to set/get values:
local _ = true   -- Can be anything except nil.
p(1,2,3)[_] = 123
print(p(1,2,3)[_])
print(p:tostring())

-- Using set/get directly.
p(1,2,2):set(122)
print(p(1,2,2):get())
print(p:tostring())

Output:
{{{0,0,0,0},{0,0,0,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0},{0,0,0,0}}}
234
{{{0,0,0,0},{0,0,0,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0},{0,0,0,234}}}
123
{{{0,0,0,0},{0,0,123,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0},{0,0,0,234}}}
122
{{{0,0,0,0},{0,122,123,0},{0,0,0,0}},{{0,0,0,0},{0,0,0,0},{0,0,0,234}}}

The full code:

function elem_ref_set(ref, val)
   ref.t[ref.i] = val
   return val
end

function elem_ref_get(ref)
   return ref.t[ref.i]
end

elem_ref_mt = {
   __index = function (t, k)
                if k == 'get' then return elem_ref_get end
                if k == 'set' then return elem_ref_set end
                return t.t[t.i]
             end,
   __newindex = function (t, k, v)
                   t.t[t.i] = v
                end,
   __call = function (t, val, ...)
               if val == nil then
                  return t.t[t.i]
               end

               t.t[t.i] = val
               return val
            end
}

function elem_ref(t, i, ...)
   if type(t[i]) ~= 'table' then
      return setmetatable({ t = t, i = i }, elem_ref_mt)
   end

   return elem_ref(t[i], ...)
end

function tensor_tostring(m)
   if type(m) ~= 'table' then
      return tostring(m)
   end

   local t = { "{" }
   for i, row in ipairs(m) do
      if i > 1 then t[#t+1] = "," end
      t[#t+1] = tensor_tostring(row)
   end
   t[#t+1] = "}"
   return table.concat(t)
end

tensor_mt = {
   __call = function (m, ...)
               return elem_ref(m, ...)
            end,
   __index = { tostring = tensor_tostring },
}

function tensor_new(_,N,...)
   if not N then
      return 0
   else
      local m = {}
      for i = 1, N do
         m[i] = tensor_new(_, ...)
      end
      return setmetatable(m, tensor_mt)
   end
end

-- This is for creation of tensors. This has nothing to do
-- with setting/getting elements.
tensor = setmetatable({}, { __call = tensor_new })

-- Here we go...
p = tensor(2,3,4)
print(p:tostring())

-- Using call interface.
p(2,3,4)(234)        -- __call with a value sets the element.
print(p(2,3,4)())    -- __call without a value gets the element.
print(p:tostring())

-- Using a dummy index to set/get values:
local _ = true   -- Can be anything except nil.
p(1,2,3)[_] = 123
print(p(1,2,3)[_])
print(p:tostring())

-- Using set/get directly.
p(1,2,2):set(122)
print(p(1,2,2):get())
print(p:tostring())


______________________________________________________________________________________
The information contained in this email transmission may contain proprietary and business 
sensitive information.  If you are not the intended recipient, you are hereby notified that 
any review, dissemination, distribution or duplication of this communication is strictly 
prohibited.  Unauthorized interception of this e-mail is a violation of law.  If you are not 
the intended recipient, please contact the sender by reply email and immediately destroy all 
copies of the original message.

Any technical data and/or information provided with or in this email may be subject to U.S. 
export controls law.  Export, diversion or disclosure contrary to U.S. law is prohibited.  
Such technical data or information is not to be exported from the U.S. or given to any foreign
person in the U.S. without prior written authorization of Elbit Systems of America and the 
appropriate U.S. Government agency.