Design matrix macro interpretation - spss

After study the macro section from a SPSS book, I'm still having trouble to understand why/how this code works
DEFINE !Combinations (Set = !TOKENS(1)
/Len = !TOKENS(1) )
INPUT PROGRAM.
!LET !Str = " ".
!LET !LisVar = "".
!DO !I = 1 !TO !Len
!LET !Ind = !CONCAT("#",!LENGTH(!Str))
LOOP !Ind = 0 TO !Set.
!LET !Str = !CONCAT(!Str," ")
!LET !LisVar = !CONCAT(!LisVar," ",!Ind)
!DOEND
VECTOR X(!Len).
DO REPEAT L = !LisVar /X = X1 TO !CONCAT("X",!Len).
COMPUTE X = L.
END REPEAT.
END CASE.
!DO !I = 1 !TO !Len
END LOOP.
!DOEND
END FILE.
END INPUT PROGRAM.
EXECUTE.
!ENDDEFINE.
Using the following parameters
!Combinations Set = 1 Len = 2.
I would have two loops (#1 and #2) going from 0 to 1, which would give me the following set (0,0)(0,1)(1,0)(1,1), but what I don't understand is
i) The first !DOEND shouldn't be at the end, outside the loop?
ii) Why I need this
!DO !I = 1 !TO !Len
END LOOP.
instead of a simple END LOOP?

It seems the point is not for the loop to run !Len times separately, but to have a hierarchy of loops that's !Len levels deep. So the macro first starts the loops, then adds the syntax to run within the loops (at the bottom of the loop hierarchy) and then closes all the loops.
That's why the loop command is enclosed in a !do macro loop, and so is the end loop command.

Related

Reliable way of getting the exact decimals from any number

I'm having problem returning spesific amount of decimal numbers from this function, i would like it to get that info from "dec" argument, but i'm stuck with this right now.
Edit: Made it work with the edited version bellow but isn't there a better way?
local function remove_decimal(t, dec)
if type(dec) == "number" then
for key, num in pairs(type(t) == "table" and t or {}) do
if type(num) == "number" then
local num_to_string = tostring(num)
local mod, d = math.modf(num)
-- find only decimal numbers
local num_dec = num_to_string:sub(#tostring(mod) + (mod == 0 and num < 0 and 3 or 2))
if dec <= #num_dec then
-- return amount of deciamls in the num by dec
local r = d < 0 and "-0." or "0."
local r2 = r .. num_dec:sub(1, dec)
t[key] = mod + tonumber(r2)
end
end
end
end
return t
end
By passing the function bellow i want a result like this:
result[1] > 0.12
result[2] > -0.12
result[3] > 123.45
result[4] > -1.23
local result = remove_decimal({0.123, -0.123, 123.456, -1.234}, 2)
print(result[1])
print(result[2])
print(result[3])
print(result[4])
I tried this but it seems to only work with one integer numbers and if number is 12.34 instead of 1.34 e.g, the decimal place will be removed and become 12.3. Using other methods
local d = dec + (num < 0 and 2 or 1)
local r = tonumber(num_to_string:sub(1, -#num_to_string - d)) or 0
A good approach is to find the position of the decimal point (the dot, .) and then extract a substring starting from the first character to the dot's position plus how many digits you want:
local function truncate(number, dec)
local strnum = tostring(number)
local i, j = string.find(strnum, '%.')
if not i then
return number
end
local strtrn = string.sub(strnum, 1, i+dec)
return tonumber(strtrn)
end
Call it like this:
print(truncate(123.456, 2))
print(truncate(1234567, 2))
123.45
1234567
To bulk-truncate a set of numbers:
local function truncate_all(t, dec)
for key, value in pairs(t) do
t[key] = truncate(t[key], dec)
end
return t
end
Usage:
local result = truncate_all({0.123, -0.123, 123.456, -1.234}, 2)
for key, value in pairs(result) do
print(key, value)
end
1 0.12
2 -0.12
3 123.45
4 -1.23
One could use the function string.format which is similar to the printf functions from C language. If one use the format "%.2f" the resulting string will contain 2 decimals, if one use "%.3f" the resulting string will be contain 3 decimals, etc. The idea is to dynamically create the format "%.XXXf" corresponding to the number of decimal needed by the function. Then call the function string.format with the newly created format string to generate the string "123.XXX". The last step would be to convert back the string to a number with the function tonumber.
Note that if one want the special character % to be preserved when string.format is called, you need to write %%.
function KeepDecimals (Number, DecimalCount)
local FloatFormat = string.format("%%.%df", DecimalCount)
local String = string.format(FloatFormat, Number)
return tonumber(String)
end
The behavior seems close to what the OP is looking for:
for Count = 1, 5 do
print(KeepDecimals(1.123456789, Count))
end
This code should print the following:
1.1
1.12
1.123
1.1235
1.12346
Regarding the initial code, it's quite straight-forward to integrate the provided solution. Note that I renamed the function to keep_decimal because in my understanding, the function will keep the requested number of decimals, and discard the rest.
function keep_decimal (Table, Count)
local NewTable = {}
local NewIndex = 1
for Index = 1, #Table do
NewTable[NewIndex] = KeepDecimal(Table[Index], Count)
NewIndex = NewIndex + 1
end
return NewTable
end
Obviously, the code could be tested easily, simply by copy and pasting into a Lua interpreter.
Result = keep_decimal({0.123, -0.123, 123.456, -1.234}, 2)
for Index = 1, #Result do
print(Result[Index])
end
This should print the following:
0.12
-0.12
123.46
-1.23
Edit due to the clarification of the need of truncate:
function Truncate (Number, Digits)
local Divider = Digits * 10
local TruncatedValue = math.floor(Number * Divider) / Divider
return TruncatedValue
end
On my computer, the code is working as expected:
> Truncate(123.456, 2)
123.45

Generating star pattern in LUA

I am new to programming in LUA. And I am not able to solve this question below.
Given a number N, generate a star pattern such that on the first line there are N stars and on the subsequent lines the number of stars decreases by 1.
The pattern generated should have N rows. In every row, every fifth star (*) is replaced with a hash (#). Every row should have the required number of stars (*) and hash (#) symbols.
Sample input and output, where the first line is the number of test cases
This is what I tried.. And I am not able to move further
function generatePattern()
n = tonumber(io.read())
i = n
while(i >= 1)
do
j = 1
while(j<=i)
do
if(j<=i)
then
if(j%5 == 0)
then
print("#");
else
print("*");
end
print(" ");
end
j = j+1;
end
print("\n");
i = i-1;
end
end
tc = tonumber(io.read())
for i=1,tc
do
generatePattern()
end
First, just the stars without hashes. This part is easy:
local function pattern(n)
for i=n,1,-1 do
print(string.rep("*", i))
end
end
To replace each 5th asterisk with a hash, you can extend the expression with the following substitution:
local function pattern(n)
for i=n,1,-1 do
print((string.rep("*", i):gsub("(%*%*%*%*)%*", "%1#")))
end
end
The asterisks in the pattern need to be escaped with a %, since * holds special meaning within Lua patterns.
Note that string.gsub returns 2 values, but they can be truncated to one value by adding an extra set of parentheses, leading to the somewhat awkward-looking form print((..)).
Depending on Lua version the metamethod __index holding rep for repeats...
--- Lua 5.3
n=10
asterisk='*'
print(asterisk:rep(n))
-- puts out: **********
#! /usr/bin/env lua
for n = arg[1], 1, -1 do
local char = ''
while #char < n do
if #char %5 == 4 then char = char ..'#'
else char = char ..'*'
end -- mod 5
end -- #char
print( char )
end -- arg[1]
chmod +x asterisk.lua
./asterisk.lua 15
Please do not follow this answer since it is bad coding style! I would delete it but SO won't let me. See comment and other answers for better solutions.
My Lua print adds newlines to each printout, therefore I concatenate each character in a string and print the concatenated string out afterwards.
function generatePattern()
n = tonumber(io.read())
i = n
while(i >= 1)
do
ouput = ""
j = 1
while(j<=i)
do
if(j%5 == 0)
then
ouput=ouput .. "#";
else
ouput=ouput .. "*";
end
j = j+1;
end
print(ouput);
i = i-1;
end
end
Also this code is just yours minimal transformed to give the correct output. There are plenty of different ways to solve the task, some are faster or more intuitive than others.

How to implement combinations tail-recursively?

I'm teaching myself Lua by reading Ierusalimschy's Programming in Lua (4th edition), and doing the exercises. Exercise 6.5 is
Write a function that takes an array and prints all combinations of the elements in the array.
After this succinct statement the book gives a hint that makes it clear that what one is expected to do is to write a function that prints all the C(n, m) combinations of m elements from an array of n elements.
I implemented the combinations function shown below:
function combinations (array, m)
local append = function (array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local _combinations
_combinations = function (array, m, prefix)
local n = #array
if n < m then
return
elseif m == 0 then
print(table.unpack(prefix))
return
else
local deleted = {table.unpack(array, 2, #array)}
_combinations(deleted, m - 1, append(prefix, array[1]))
_combinations(deleted, m, prefix)
end
end
_combinations(array, m, {})
end
It works OK, but it is not tail-recursive.
Can someone show me a tail-recursive function that does the same thing as combinations above does?
(For what it's worth, I am using Lua 5.3.)
NB: I realize that the exercise does not require that the function be tail-recursive. This is a requirement I have added myself, out of curiosity.
EDIT: I simplified the function slightly, but removing a couple of nested functions that were not adding much.
There is a third option, one that doesn't have a snake eating it's tail. Although recursion with tail-calls don't lead to stack overflow, I avoid doing so out of personal preference. I use a while loop and a stack that holds the information for each iteration. Within the loop you pop the next task from the stack, do the work, then push next task onto the stack. I feel it looks cleaner and it's easier to visualize the nesting.
Here is how I would translate your code into the way I would write it:
function combinations(sequence, item)
local function append(array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local stack = {}
local node = { sequence, item, {} }
while true do
local seq = node[ 1 ]
local itm = node[ 2 ]
local pre = node[ 3 ]
local n = #seq
if itm == 0 then
print(table.unpack(pre))
elseif n < itm then
-- do nothing
else
local reserve = {table.unpack(seq, 2, #seq)}
table.insert(stack, { reserve, itm, pre })
table.insert(stack, { reserve, itm-1, append(pre, seq[ 1 ]) })
end
if #stack > 0 then
node = stack[ #stack ] -- LIFO
stack[ #stack ] = nil
else
break
end
end
end
You can use this while-loop stack/node technique for just about any recursive method. Here is an example where it's applied to printing deeply nested tables: https://stackoverflow.com/a/42062321/5113346
My version, using your input example gives the same output:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5.
Forgive me if it doesn't work with other passed params because I didn't try to solve the answer to the exercise but rather just rewrite the code in your original post.
OK, I think I found one way to do this:
function combinations (array, m)
local dropfirst = function (array)
return {table.unpack(array, 2, #array)}
end
local append = function (array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local _combinations
_combinations = function (sequence, m, prefix, queue)
local n = #sequence
local newqueue
if n >= m then
if m == 0 then
print(table.unpack(prefix))
else
local deleted = dropfirst(sequence)
if n > m then
newqueue = append(queue, {deleted, m, prefix})
else
newqueue = queue
end
return _combinations(deleted, m - 1,
append(prefix, sequence[1]),
newqueue)
end
end
if #queue > 0 then
newqueue = dropfirst(queue)
local newargs = append(queue[1], newqueue)
return _combinations(table.unpack(newargs))
end
end
_combinations(sequence, m, {}, {})
end
This version is, I think, tail-recursive. Unfortunately, it does not print out the results in as nice an order as did my original non-tail-recursive version (not to mention the added complexity of the code), but one can't have everything!
EDIT: Well, no, one can have everything! The version below is tail-recursive, and prints its results in the same order as does the original non-tail-recursive version:
function combinations (sequence, m, prefix, stack)
prefix, stack = prefix or {}, stack or {}
local n = #sequence
if n < m then return end
local newargs, newstack
if m == 0 then
print(table.unpack(prefix))
if #stack == 0 then return end
newstack = droplast(stack)
newargs = append(stack[#stack], newstack)
else
local deleted = dropfirst(sequence)
if n > m then
newstack = append(stack, {deleted, m, prefix})
else
newstack = stack
end
local newprefix = append(prefix, sequence[1])
newargs = {deleted, m - 1, newprefix, newstack}
end
return combinations(table.unpack(newargs)) -- tail call
end
It uses the following auxiliary functions:
function append (sequence, item)
local copy = {table.unpack(sequence)}
copy[#copy + 1] = item
return copy
end
function dropfirst (sequence)
return {table.unpack(sequence, 2, #sequence)}
end
function droplast (sequence)
return {table.unpack(sequence, 1, #sequence - 1)}
end
Example:
> combinations({1, 2, 3, 4, 5}, 3)
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
Ironically, this version achieves tail-recursion by implementing its own stack, so I am not sure it is ultimately any better than the non-tail-recursive version... Then again, I guess the function's stack actually lives in the heap (right?), because Lua's tables are passed around by reference (right?), so maybe this is an improvement, after all. (Please correct me if I'm wrong!)

Parsing an input file which contains polynomials

Hello experienced pythoners.
The goal is simply to read in my own files which have the following format, and to then apply mathematical operations to these values and polynomials. The files have the following format:
m1:=10:
m2:=30:
Z1:=1:
Z2:=-1:
...
Some very similar variables, next come the laguerre polynomials
...
F:= (12.58295)*L(0,x)*L(1,y)*L(6,z) + (30.19372)*L(0,x)*L(2,y)*L(2,z) - ...:
Where L stands for a laguerre polynomial and takes two arguments.
I have written a procedure in Python which splits apart each line into a left and right hand side split using the "=" character as a divider. The format of these files is always the same, but the number of laguerre polynomials in F can vary.
import re
linestring = open("file.txt", "r").read()
linestring = re.sub("\n\n","\n",str(linestring))
linestring = re.sub(",\n",",",linestring)
linestring = re.sub("\\+\n","+",linestring)
linestring = re.sub(":=\n",":=",linestring)
linestring = re.sub(":\n","\n",linestring)
linestring = re.sub(":","",linestring)
LINES = linestring.split("\n")
for LINE in LINES:
LINE = re.sub(" ","",LINE)
print "LINE=", LINE
if len(LINE) <=0:
next
PAIR = LINE.split("=")
print "PAIR=", PAIR
LHS = PAIR[0]
RHS = PAIR[1]
print "LHS=", LHS
print "RHS=", RHS
The first re.sub block just deals with formatting the file and discarding characters that python will not be able to process; then a loop is performed to print 4 things, LINE, PAIR, LHS and RHS, and it does this nicely. using the example file from above the procedure will print the following:
LINE= m1=1
PAIR= ['m1', '1']
LHS= m1
RHS= 1
LINE= m2=1
PAIR= ['m2', '1']
LHS= m2
RHS= 1
LINE= Z1=-1
PAIR= ['Z1', '-1']
LHS= Z1
RHS= -1
LINE= Z2=-1
PAIR= ['Z2', '-1']
LHS= Z2
RHS= -1
LINE= F= 12.5*L(0,x)L(1,y) + 30*L(0,x)L(2,y)L(2,z)
PAIR=['F', '12.5*L(0,x)L(1,y) + 30*L(0,x)L(2,y)L(2,z)']
LHS= F
RHS= 12.5*L(0,x)L(1,y) + 30*L(0,x)L(2,y)L(2,z)
My question is what is the next best step to process this output and use it in a mathematical script, especially assigning the L to mean a laguerre polynomial? I tried putting the LHS and RHS into a dictionary, but found it troublesome to put F in it due to the laguerre polynomials.
Any ideas are welcome. Perhaps I am overcomplicating this and there is a much simpler way to parse this file.
Many thanks in advance
Your parsing algorithm doesn't seem to work correctly, as the RHS of your variables dont produce the expected result.
Also the first re.sub block where you want to format the file seems overly complicated. Assuming every statement in your input file is terminated by a colon, you could get rid of all whitespace and newlines and seperate the statements using the following code:
linestring = open('file.txt','r').read()
strippedstring = linestring.replace('\n','').replace(' ','')
statements = re.split(':(?!=)',strippedstring)[:-1]
Then you iterate over the statements and split each one in LHS and RHS:
for st in statements:
lhs,rhs = re.split(':=',st)
print 'lhs=',lhs
print 'rhs=',rhs
In the next step, try to distinguish normal float variables and polynomials:
#evaluate rhs
try:
#interpret as numeric constant
f = float(rhs)
print " ",f
except ValueError:
#interpret as laguerre-polynomial
summands = re.split('\+', re.sub('-','+-',rhs))
for s in summands:
m = re.match("^(?P<factor>-?[0-9]*(\.[0-9]*)?)(?P<poly>(\*?L\([0-9]+,[a-z]\))*)", s)
if not m:
print ' polynomial misformatted'
continue
f = m.group('factor')
print ' factor: ',f
p = m.group('poly')
for l in re.finditer("L\((?P<a>[0-9]+),(?P<b>[a-z])\)",p):
print ' poly: L(%s,%s)' % (l.group("a"),l.group("b"))
This should work for your given example file.

How can I better parse variable time stamp information in Fortran?

I am writing code in gfortran to separate a variable time stamp into its separate parts of year, month, and day. I have written this code so the user can input what the time stamp format will be (ie. YEAR/MON/DAY, DAY/MON/YEAR, etc). This creates a total of 6 possible combinations. I have written code that attempts to deal with this, but I believe it to be ugly and poorly done.
My current code uses a slew of 'if' and 'goto' statements. The user provides 'tsfo', the time stamp format. 'ts' is a character array containing the time stamp data (as many as 100,000 time stamps). 'tsdelim' is the delimiter between the year, month, and day. I must loop from 'frd' (the first time stamp) to 'nlines' (the last time stamp).
Here is the relevant code.
* Choose which case to go to.
first = INDEX(tsfo,tsdelim)
second = INDEX(tsfo(first+1:),tsdelim) + first
if (INDEX(tsfo(1:first-1),'YYYY') .ne. 0) THEN
if (INDEX(tsfo(first+1:second-1),'MM') .ne. 0) THEN
goto 1001
else
goto 1002
end if
else if (INDEX(tsfo(1:first-1),'MM') .ne. 0) THEN
if (INDEX(tsfo(first+1:second-1),'DD') .ne. 0) THEN
goto 1003
else
goto 1004
end if
else if (INDEX(tsfo(1:first-1),'DD') .ne. 0) THEN
if (INDEX(tsfo(first+1:second-1),'MM') .ne. 0) THEN
goto 1005
else
goto 1006
end if
end if
first = 0
second = 0
* Obtain the Julian Day number of each data entry.
* Acquire the year, month, and day of the time stamp.
* Find 'first' and 'second' and act accordingly.
* Case 1: YYYY/MM/DD
1001 do i = frd,nlines
first = INDEX(ts(i),tsdelim)
second = INDEX(ts(i)(first+1:),tsdelim) + first
read (ts(i)(1:first-1), '(i4)') Y
read (ts(i)(first+1:second-1), '(i2)') M
read (ts(i)(second+1:second+2), '(i2)') D
* Calculate the Julian Day number using a function.
temp1(i) = JLDYNUM(Y,M,D)
end do
goto 1200
* Case 2: YYYY/DD/MM
1002 do i = frd,nlines
first = INDEX(ts(i),tsdelim)
second = INDEX(ts(i)(first+1:),tsdelim) + first
read (ts(i)(1:first-1), '(i4)') Y
read (ts(i)(second+1:second+2), '(i2)') M
read (ts(i)(first+1:second-1), '(i2)') D
* Calculate the Julian Day number using a function.
temp1(i) = JLDYNUM(Y,M,D)
end do
goto 1200
* Onto the next part of the code
1200 blah blah blah
I believe this code will work, but I do not think it is a very good method. Is there a better way to go about this?
It is important to note that the indices 'first' and 'second' must be calculated for each time stamp as the month and day can both be represented by 1 or 2 integers. The year is always represented by 4.
With only six permutations to handle I would just build a look-up table with the whole tsfo string as the key and the positions of year, month and day (1st, 2nd or 3rd) as the values. Any unsupported formats should produce an error, which I haven't coded below. When subsequently you loop though your ts list and split an item you know which positions to cast to the year, month and day integer variables:
PROGRAM timestamp
IMPLICIT NONE
CHARACTER(len=10) :: ts1(3) = ["2000/3/4 ","2000/25/12","2000/31/07"]
CHARACTER(len=10) :: ts2(3) = ["3/4/2000 ","25/12/2000","31/07/2000"]
CALL parse("YYYY/DD/MM",ts1)
print*
CALL parse("DD/MM/YYYY",ts2)
CONTAINS
SUBROUTINE parse(tsfo,ts)
IMPLICIT NONE
CHARACTER(len=*),INTENT(in) :: tsfo, ts(:)
TYPE sti
CHARACTER(len=10) :: stamp = "1234567890"
INTEGER :: iy = -1, im = -1, id = -1
END TYPE sti
TYPE(sti),PARAMETER :: stamps(6) = [sti("YYYY/MM/DD",1,2,3), sti("YYYY/DD/MM",1,3,2),&
sti("MM/DD/YYYY",2,3,1), sti("DD/MM/YYYY",3,2,1),&
sti("MM/YYYY/DD",2,1,3), sti("DD/YYYY/MM",3,1,2)]
TYPE(sti) :: thisTsfo
INTEGER :: k, k1, k2
INTEGER :: y, m, d
CHARACTER(len=10) :: cc(3)
DO k=1,SIZE(stamps)
IF(TRIM(tsfo) == stamps(k)%stamp) THEN
thisTsfo = stamps(k)
EXIT
ENDIF
ENDDO
print*,thisTsfo
DO k=1,SIZE(ts)
k1 = INDEX(ts(k),"/")
k2 = INDEX(ts(k),"/",BACK=.TRUE.)
cc(1) = ts(k)(:k1-1)
cc(2) = ts(k)(k1+1:k2-1)
cc(3) = ts(k)(k2+1:)
READ(cc(thisTsfo%iy),'(i4)') y
READ(cc(thisTsfo%im),'(i2)') m
READ(cc(thisTsfo%id),'(i2)') d
PRINT*,ts(k),y,m,d
ENDDO
END SUBROUTINE parse
END PROGRAM timestamp
I would encode the different cases in another way, like this:
module foo
implicit none
private
public encode_datecode
contains
integer function encode_datecode(datestr, sep)
character(len=*), intent(in) :: datestr, sep
integer :: first, second
character(len=1) :: c1, c2, c3
first = index(datestr, sep)
second = index(datestr(first+1:), sep) + first
c1 = datestr(1:1)
c2 = datestr(first+1:first+1)
c3 = datestr(second+1:second+1)
foo = num(c1) + 3*num(c2) + 9*num(c3)
end function encode_datecode
integer function num(c)
character(len=1) :: c
if (c == 'Y') then
num = 0
else if (c == 'M') then
num = 1
else if (c == 'D') then
num = 2
else
stop "Illegal character"
end if
end function num
end module foo
and then handle the legal cases (21, 15, 19, 7, 11, 5) in a SELECT statement.
This takes advantage of the fact that there won't be a 'YDDY/MY/YM' format.
If you prefer better binary or decimal readability, you can also multiply by four or by 10 instead of 3.

Resources