how to tackle HEX in torch7? - lua

I'm using async-tcp client to connect to server and receive data(an array).
client.ondata(function(data)
print('received:',data)
end)
If data type is HEX, I can get data but it is all gibberish.
It seems that there is something wrong with encoding.
If data type is note HEX, I can also get data but it is string.
I have no idea to convert the 'array string' to tensor.
'0.001 0.002 0.003' -> torch.Tensor({{0.001, 0.002, 0.003}}) ??
What should I do ?
Thank you
==================================================
EDIT
string.byte
client.ondata(function(data)
print('received number:',#data)
for i = 1, #data do
print('received:', string.byte(data, i))
end
end)

If you know the format ahead of time, you can use the match function to get the list of values from a string, which you can then convert to the table and the Tensor:
local str = "0.001 0.002 0.003"
torch.Tensor({{str:match("(%d+%.%d*)%s+(%d+%.%d*)%s+(%d+%.%d*)")}})
This returns:
0.001 *
1.0000 2.0000 3.0000
[torch.DoubleTensor of size 1x3]
If the number is in the hex format, you can use tonumber function to convert, for example, tonumber("0x12") == 18.

Related

Convert bytes to signed integers in lua 5.1.5

I'm looking for how to turn bytes into a signed int using lua 5.1.5, so far I've only been able to find solutions for lua 5.2 onward, and they are not backward compatible.
I have solutions for how to turn bytes into unsigned integers, like so:
payload_t.temperature=tonumber(utility.hex2str(string.sub(payload,32,33)),16)
First of all I'll assume that you actually have a byte string rather than a hex string given; if your string is a hex string, you can trivially convert it to a byte string using gsub:
function hex2bytes(str)
-- assert that it is indeed a string of hex digit pairs
assert(#str % 2 == 0 and not str:match"[^%x]")
return str:gsub("%x%x", function(hex) return tonumber(hex, 16) end)
end
Now, let's convert this byte string to an integer. I'll assume little endian (least significant byte first); should your string be big endian (most significant byte first) you'll have to reverse it using str:reverse() before you read it.
Reading an unsigned integer is pretty straightforward:
function bytes2uint(str)
local uint = 0
for i = 1, #str do
uint = uint + str:byte(i) * 0x100^(i-1)
end
return uint
end
I'll assume your integers are stored using Two's complement. In this case the higher 2^n values (equivalent to the first bit being set or the value being >= 2^(n-1)) the uint can take represent negative numbers, with the smallest value (2^(n-1)) representing the largest negative value (-2^(n-1)). Thus you can simply subtract the unsigned value from 2^n, the (exclusive) max value for the uint:
function bytes2int(str)
local uint = bytes2uint(str)
local max = 0x100 ^ #str
if uint >= max / 2 then
return uint - max
end
return uint
end

Converting byte value correctly

I am having a hard time getting the correct value that I need.
I get from my characteristic vales from:
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor ...
I can read and print off the values with:
let values = characteristic.value
for val in values! {
print("Value", num)
}
This gets me:
"Value 0" // probe state not important
"Value 46" // temp
"Value 2" // see below
The problem is that the temp is not 46.
Below is a snippet of instructions on how I need to convert the byte to get the actual temp.
The actual temp was around 558 ºF.
Here are a part of the instructions:
Description: temperature data that is valid only if the temperature stat is normal
byte[1] = (unsigned char)temp;
byte[2] = (unsigned char)(temp>>8);
byte[3] = (unsigned char)(temp>>16);
byte[4] = (unsigned char)(temp>>24);
I can't seem to get the correct temp? Please let me know what I am doing wrong.
According to the description, value[1] ... value[4] are the least significant to most significant bytes of the (32-bit integer) temperature, so this is how you would recreate
that value from the bytes:
if let value = characteristic.value, value.count >= 5 {
let tmp = UInt32(value[1]) + UInt32(value[2]) << 8 + UInt32(value[3]) << 16 + UInt32(value[4]) << 24
let temperature = Int32(bitPattern: tmp)
}
The bit-fiddling is done in unsigned integer arithmetic to avoid
an overflow. Assuming that the temperature is a signed value,
this value is then converted to a signed integer with the same
bit representation.
The instructions tell you the answer. You are getting 46 in byte 1, then 2 in byte 2. The instructions say to leave byte 1 alone, but for byte 2 we are to shift the results as temp>>8 — which means "multiply by 256" (because 2^8 is 256). Well, what is
46+256×2
It is 558, just the result we're looking for.

How do I fill up a number's decimal places with zeroes?

Assume the following numbers:
local a = 2
local b = 3.1
local c = 1.43
local d = 1.0582
My goal is to round these numbers to two decimal places. The result should be this, respectively:
a = 2.00
b = 3.10
c = 1.43
d = 1.06 or 1.05
Obviously I understand that any number with trailing decimal zeroes will get rounded. 2.00 will be 2. But I need the numbers as strings, and to make it visually more appealing, I would need these two decimal places.
Here's a function I use to round to two decimal places:
function round(num, numDecimalPlaces)
local mult = 10^(numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
This works fine for test cases c and d, but will produce wrong results with a and b: it won't fill up with zeroes. I understand it is because the rounding function takes the numbers and calculates them - therefore the excess zeroes get cut off.
But that is exactly not my goal - not cutting them off.
I've tried string manipulation, by checking if and where a . is in a number, but that didn't work at all, for any case. My method:
local zei
if i < 100 then
if tostring(i):find("%.") == nil then
zei = round(i, 2) .. ".00" --No decimal point found, append .00
else
zei = round(i, 2) --Found decimal point, round to 2
end
if tostring(i):find("%.")+2 == tostring(i):len() then
zei = round(i, 2) .. "0" --Found point, but only one trailing number, append 0
end
else
zei = round(i, 0) --Number is over 100, no decimal points needed
end
The above 100 case is just for aesthetics and not relevant here. Where zei is the displayed string, and i is one of the test case numbers.
Summary
How would I round a number to two decimal places, but append trailing zeroes, even if they were excess, e.g. 2.30? I understand I need strings for this.
Contradicting question: Strip off excess zeroes
You don't round numbers. You create string representations of those numbers. That would be done by string.format, with an appropriate format. Like this:
string.format("%.2f", a);

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.

Format string to number with minimum length in lua

For example I need number with minimum 3 digit
"512" --> 512
"24" --> 24.0
"5" --> 5.00
One option is write small function. Using answers here for my case it will be something like this
function f(value, w)
local p = math.ceil(math.log10(value))
local prec = value <= 1 and w - 1 or p > w and 0 or w - p
return string.format('%.' .. prec .. 'f', value)
end
print(f(12, 3))
But may be it is possible just using string.format() or any other simple way?
Ok, it seems this case beyond the string.format power. Thanks to #Schollii, this is my current variant
function f(value, w)
local p = math.ceil(math.log10(value))
local prec = value <= 1 and w - 1 or p > w and 0 or w - p
return string.format('%.' .. prec .. 'f', value)
end
print(f(12, 3))
There is no format code specifically for this since string.format uses printf minus a few codes (like * which would hace simplified the solution I give below). So you have to implement yourself, for example:
function f(num, w)
-- get number of digits before decimal
local intWidth = math.ceil(math.log10(num))
-- if intWidth > w then ... end -- may need this
local fmt='%'..w..'.' .. (w-intWidth) .. 'f'
return string.format(fmt, num)
end
print(f(12, 4))
print(f(12, 3))
print(f(12, 2))
print(f(512, 3))
print(f(24, 3))
print(f(5, 3))
You should probably handle case where integer part doesn't fit in field width given (return ceil or floor?).
You can't. Maximum you can reach - specify floating point precision or digit number, but you can't force output to be like your example. Lua uses C like printf with few limitations reference. Look here for full specifiers list link. Remember unsupported ones.
Writing a function would be the best and only solution, especially as your task looks strange, as it doesn't count decimal dot.

Resources