Akka Framing by Size - java

how can i frame Flow<ByteString, ByteString, NotUsed> by size? All examples I have found assumes that there is some delimiter, which is not my case, I just need to frame by length / size.

Framing via Framing.delimiter does require a designated delimiter, and there doesn't seem to be any built-in stream operator that does framing simply by a fixed chunk size. One of the challenges in coming up with a custom framing/chunking solution is to properly handle the last chunk of elements.
One solution would be to assemble a custom GraphStage like the "chunking" example illustrated in the Akka Stream-cookbook:
import akka.stream.stage.{GraphStage, GraphStageLogic, InHandler, OutHandler}
import akka.stream.{Attributes, Inlet, Outlet, FlowShape}
import akka.util.ByteString
class Chunking(val chunkSize: Int) extends GraphStage[FlowShape[ByteString, ByteString]] {
val in = Inlet[ByteString]("Chunking.in")
val out = Outlet[ByteString]("Chunking.out")
override val shape = FlowShape.of(in, out)
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic = new GraphStageLogic(shape) {
private var buffer = ByteString.empty
setHandler(in, new InHandler {
override def onPush(): Unit = {
val elem = grab(in)
buffer ++= elem
emitChunk()
}
override def onUpstreamFinish(): Unit = {
if (buffer.isEmpty)
completeStage()
else {
if (isAvailable(out)) emitChunk()
}
}
})
setHandler(out, new OutHandler {
override def onPull(): Unit = {
if (isClosed(in)) emitChunk()
else pull(in)
}
})
private def emitChunk(): Unit = {
if (buffer.isEmpty) {
if (isClosed(in)) completeStage() else pull(in)
}
else {
val (chunk, nextBuffer) = buffer.splitAt(chunkSize)
buffer = nextBuffer
push(out, chunk)
}
}
}
}
Note that emitChunk() handles the fixed-size chunking and onUpstreamFinish() is necessary for processing the last chunk of elements in the internal buffer.
Test-running with a sample text file "/path/to/file" which has content as below:
Millions of people worldwide are in for a disastrous future of hunger, drought and disease, according to a draft report from the United Nations' Intergovernmental Panel on Climate Change, which was leaked to the media this week.
import akka.actor.ActorSystem
import akka.stream.scaladsl._
import java.nio.file.Paths
implicit val system = ActorSystem("system")
implicit val executionContext = system.dispatcher
val chunkSize = 32
FileIO.fromPath(Paths.get("/path/to/file")).
via(new Chunking(chunkSize)).
map(_.utf8String).
runWith(Sink.seq)
// res1: scala.concurrent.Future[Seq[String]] = Future(Success(Vector(
// "Millions of people worldwide are",
// " in for a disastrous future of h",
// "unger, drought and disease, acco",
// "rding to a draft report from the",
// " United Nations' Intergovernment",
// "al Panel on Climate Change, whic",
// "h was leaked to the media this w",
// "eek."
// )))

Something like (in Scala, disclaimer: only mentally compiled) this, using statefulMapConcat, which allows
emitting zero or more frames per input element
maintaining state from element to element of what's yet to be emitted
val frameSize: Int = ???
require(frameSize > 0, "frame size must be positive")
Flow[ByteString].statefulMapConcat { () =>
var carry: ByteString = ByteString.empty
{ in =>
val len = carry.length + in.length
if (len < frameSize) {
// append to carry and emit nothing
carry = carry ++ in
Nil
} else if (len == frameSize) {
if (carry.nonEmpty) {
carry = ByteString.empty
List(carry ++ in)
} else List(in)
} else {
if (carry.isEmpty) {
val frames = len / frameSize
val (emit, suffix) = in.splitAt(frames * frameSize)
carry = suffix
emit.grouped(frameSize)
} else {
val (appendToCarry, inn) = in.splitAt(frameSize - carry.length)
val first = carry ++ appendToCarry
val frames = inn.length / frameSize
if (frames > 0) {
val (emit, suffix) = inn.splitAt(frames * frameSize)
carry = suffix
Iterator.single(first) ++ emit.grouped(frameSize)
} else {
carry = inn
List(first)
}
}
}
}
If in Java, note that carry ++ in can be expressed as carry.concat(in). It may be useful, in order to get around the restriction in Java around closing over non-final variables, to use a 1-element ByteString[] (e.g. ByteString[] carry = { ByteString.empty }).

Related

Bluetooth LE - ScanResult returns the same timestamp for the same device

I want to get the advertisement milliseconds of the devices by subtracting the two timestamps of the same device. But both timestamps are the same value. Could someone help?
override fun onScanResult(callbackType: Int, result: ScanResult) {
val timeStampFirst = result.timestampNanos
val tag = deviceMap.computeIfAbsent(result.device.address) {
val newTag = BleTag(result.device.name ?: "Unbekannt", result.device.address, result.rssi , result.scanRecord?.bytes, result.timestampNanos,"0 Sek.")
deviceList.add(newTag)
newTag
}
tag.name = result.device.name ?: "Unbekannt"
tag.rssi = result.rssi
tag.advertisementData = result.scanRecord?.bytes
tag.timeStampFirst = result.timestampNanos
deviceList.forEach {
if(it.mac == result.device.address){
val timeStampSecond = result.timestampNanos
val advertisementMillis = timeStampSecond - timeStampFirst
Log.e("Advertisement ms", advertisementMillis)
}
}
Log.e(resultTime.toString(),"")
deviceList.sortBy {
result.rssi
}
recyclerView.adapter?.notifyDataSetChanged()
//menu.findItem(R.id.count).title = "Geräte: " + deviceList.size
super.onScanResult(callbackType, result)
}
To show the problem and the solution I have commented out all source code that is not necessary for the calculation of the time interval between two consecutive advertisement.
override fun onScanResult(callbackType: Int, result: ScanResult) {
val timeStampFirst = result.timestampNanos
// val tag = deviceMap.computeIfAbsent(result.device.address) {
// val newTag = BleTag(result.device.name ?: "Unbekannt", result.device.address, result.rssi , result.scanRecord?.bytes, result.timestampNanos,"0 Sek.")
// deviceList.add(newTag)
// newTag
// }
// tag.name = result.device.name ?: "Unbekannt"
// tag.rssi = result.rssi
// tag.advertisementData = result.scanRecord?.bytes
// tag.timeStampFirst = result.timestampNanos
// deviceList.forEach {
// if(it.mac == result.device.address){
val timeStampSecond = result.timestampNanos
// will always be ZERO
val advertisementMillis = timeStampSecond - timeStampFirst
Log.e("Advertisement ms", advertisementMillis)
// }
// }
// Log.e(resultTime.toString(),"")
// deviceList.sortBy {
// result.rssi
// }
// recyclerView.adapter?.notifyDataSetChanged()
//menu.findItem(R.id.count).title = "Geräte: " + deviceList.size
// super.onScanResult(callbackType, result)
}
As you use for both timestamps the value of the current advertisement the result will always be 0.
But the object from the deviceList does not help either, because it already contains the data from the current advertisement.
In pseudo code you would have to do the following to find the interval between two consecutive advertisement:
onNewAdvertismentReceived
If Broadcaster seen before
Retrieve timestamp from the advertisment beforehand
Calculate the interval from both timestamps(old,new)
Else
First time Broadcaster seen
Not possible to calculate interval
Fi

"map(From)' in 'Mapper' clashes with 'map(Object)' in 'CursorToMessageImpl'; both methods have same erasure, yet neither overrides the other

This is code in kotlin. Showing error Type inference failed: inline fun T.apply(block: T.() -> Unit): T cannot be applied to receiver: Message arguments: (Message.() -> Any) .
**map(From)' in 'Mapper' clashes with 'map(Object)' in 'CursorToMessageImpl'; both methods have same erasure, yet neither overrides the other
**
class CursorToMessageImpl #Inject constructor(
private val context: Context,
private val cursorToPart: CursorToPart,
private val keys: KeyManager,
private val permissionManager: PermissionManager,
private val preferences: Preferences) : CursorToMessage
{
private val uri = Uri.parse("content://mms-sms/complete-conversations")
private val projection = arrayOf(
MmsSms.TYPE_DISCRIMINATOR_COLUMN,
MmsSms._ID,
Mms.DATE,
Mms.DATE_SENT,
Mms.READ,
Mms.THREAD_ID,
Mms.LOCKED,
Sms.ADDRESS,
Sms.BODY,
Sms.SEEN,
Sms.TYPE,
Sms.STATUS,
Sms.ERROR_CODE,
Mms.SUBJECT,
Mms.SUBJECT_CHARSET,
Mms.SEEN,
Mms.MESSAGE_TYPE,
Mms.MESSAGE_BOX,
Mms.DELIVERY_REPORT,
Mms.READ_REPORT,
MmsSms.PendingMessages.ERROR_TYPE,
Mms.STATUS
)
override fun map(from: Pair<Cursor, CursorToMessage.MessageColumns>): Message {
val cursor = from.first
val columnsMap = from.second
return Message().apply {
type = when {
cursor.getColumnIndex(MmsSms.TYPE_DISCRIMINATOR_COLUMN) != -1 -> cursor.getString(columnsMap.msgType)
cursor.getColumnIndex(Mms.SUBJECT) != -1 -> "mms"
cursor.getColumnIndex(Sms.ADDRESS) != -1 -> "sms"
else -> "unknown"
}
id = keys.newId()
threadId = cursor.getLong(columnsMap.threadId)
contentId = cursor.getLong(columnsMap.msgId)
date = cursor.getLong(columnsMap.date)
dateSent = cursor.getLong(columnsMap.dateSent)
read = cursor.getInt(columnsMap.read) != 0
locked = cursor.getInt(columnsMap.locked) != 0
subId = if (columnsMap.subId != -1) cursor.getInt(columnsMap.subId)
else -1
when (type) {
"sms" -> {
address = cursor.getString(columnsMap.smsAddress) ?: ""
boxId = cursor.getInt(columnsMap.smsType)
seen = cursor.getInt(columnsMap.smsSeen) != 0
body = columnsMap.smsBody
.takeIf { column -> column != -1 } // The column may not be set
?.let { column -> cursor.getString(column) } ?: "" // cursor.getString() may return null
errorCode = cursor.getInt(columnsMap.smsErrorCode)
deliveryStatus = cursor.getInt(columnsMap.smsStatus)
}
"mms" -> {
address = getMmsAddress(contentId)
boxId = cursor.getInt(columnsMap.mmsMessageBox)
date *= 1000L
dateSent *= 1000L
seen = cursor.getInt(columnsMap.mmsSeen) != 0
mmsDeliveryStatusString = cursor.getString(columnsMap.mmsDeliveryReport) ?: ""
errorType = if (columnsMap.mmsErrorType != -1) cursor.getInt(columnsMap.mmsErrorType) else 0
messageSize = 0
readReportString = cursor.getString(columnsMap.mmsReadReport) ?: ""
messageType = cursor.getInt(columnsMap.mmsMessageType)
mmsStatus = cursor.getInt(columnsMap.mmsStatus)
val subjectCharset = cursor.getInt(columnsMap.mmsSubjectCharset)
subject = cursor.getString(columnsMap.mmsSubject)
?.takeIf { it.isNotBlank() }
?.let(_root_ide_package_.app.google.android.mms.pdu_alt.PduPersister::getBytes)
?.let { _root_ide_package_.app.google.android.mms.pdu_alt.EncodedStringValue(subjectCharset, it).string } ?: ""
textContentType = ""
attachmentType = Message.AttachmentType.NOT_LOADED
parts.addAll(cursorToPart.getPartsCursor(contentId)?.map { cursorToPart.map(it) } ?: listOf())
}
else -> -1
}
}
}
**and interference mapper is :-**
interface Mapper<in From, out To> {
fun map(from: From): To
}
I'm not 100% sure this is your issue, but since else -> -1 in your when statement doesn't accomplish anything, try removing it. A when statement doesn't have to be exhaustive when it isn't being forced to be evaluated as an expression (by assigning its result to a variable or property).
else -> -1 at the bottom of your when statement causes it to be a when expression that returns Any. Usually, the compiler can interpret a lambda ending in an expression other than Unit as having an implicit return of Unit if there are no overloads that it would otherwise match. But there may be some cases where the involved classes are complex enough to prevent it from deducing that.

arrayListOf(), sortedWith, compareBy Java equivalent

I'm converting a Kotlin based Android app into a Java based one. But got a problem with several Kotlin's methods, especially with the arrayListOf(), sortedWith(), compareBy() methods. The converting tools from Android Studio gave even more confusing result.
The method in Kotlin:
fun getSupportedVideoSize(mediaCodec: MediaCodec, mime: String, preferredResolution: Size): Size {
if (mediaCodec.codecInfo.getCapabilitiesForType(mime)
.videoCapabilities.isSizeSupported(preferredResolution.width, preferredResolution.height))
return preferredResolution
val resolutions = arrayListOf(
Size(176, 144),
Size(320, 240),
Size(320, 180),
Size(640, 360),
Size(720, 480),
Size(1280, 720),
Size(1920, 1080)
)
val pix = preferredResolution.width * preferredResolution.height
val preferredAspect = preferredResolution.width.toFloat() / preferredResolution.height.toFloat()
val nearestToFurthest = resolutions.sortedWith(compareBy(
{
pix - it.width * it.height
},
{
val aspect = if (it.width < it.height) it.width.toFloat() / it.height.toFloat()
else it.height.toFloat()/it.width.toFloat()
(preferredAspect - aspect).absoluteValue
}))
for (size in nearestToFurthest) {
if (mediaCodec.codecInfo.getCapabilitiesForType(mime).videoCapabilities.isSizeSupported(size.width, size.height))
return size
}
throw RuntimeException("Couldn't find supported resolution")
}
Converted method in Java:
public static Size getSupportedVideoSize(MediaCodec mediaCodec, String mime, Size preferredResolution) {
if (mediaCodec.getCodecInfo().getCapabilitiesForType(mime).getVideoCapabilities().isSizeSupported(preferredResolution.getWidth(), preferredResolution.getHeight())) {
return preferredResolution;
} else {
ArrayList<Size> resolutions = new ArrayList<>();
final int pix = preferredResolution.getWidth() * preferredResolution.getHeight();
final float preferredAspect = (float)preferredResolution.getWidth() / (float)preferredResolution.getHeight();
}
for (nearestToFurthest: Size size) {
if (mediaCodec.getCodecInfo().getCapabilitiesForType(mime).getVideoCapabilities().isSizeSupported(size.width, size.height)) {
return size;
}
}
}
I don't know Kotlin but I assume these would be equivalent:
arrayListOf --> List.of
(this is unmodiafiable list, if you really want arraylist, use new ArrayList<>(Arrays.asList(...)) )
sortedWith(compareBy(...)) --> sort([Comparator or lambda expression])

How can I feed a sparse placeholder in a TensorFlow model from Java

I'm trying to calculate the best match for a given address with the kNN algorithm in TensorFlow, which works pretty good, but when I'm trying to export the model and use it in our Java Environment I got stuck on how to feed the sparse placholders from Java.
Here is a pretty much stripped down version of the python part, which returns the smallest distance between the test name and the best reference name. So far this work's as expected. When I export the model and import it in my Java program it always returns the same value (distance of the placeholders default). I asume, that the python function sparse_from_word_vec(word_vec) isn't in the model, which would totally make sense to me, but then how should i make this sparse tensor? My input is a single string and I need to create a fitting sparse tensor (value) to calculate the distance. I also searched for a way to generate the sparse tensor on the Java side, but without success.
import tensorflow as tf
import pandas as pd
d = {'NAME': ['max mustermann',
'erika musterfrau',
'joseph haydn',
'johann sebastian bach',
'wolfgang amadeus mozart']}
df = pd.DataFrame(data=d)
input_name = tf.placeholder_with_default('max musterman',(), name='input_name')
output_dist = tf.placeholder(tf.float32, (), name='output_dist')
test_name = tf.sparse_placeholder(dtype=tf.string)
ref_names = tf.sparse_placeholder(dtype=tf.string)
output_dist = tf.edit_distance(test_name, ref_names, normalize=True)
def sparse_from_word_vec(word_vec):
num_words = len(word_vec)
indices = [[xi, 0, yi] for xi,x in enumerate(word_vec) for yi,y in enumerate(x)]
chars = list(''.join(word_vec))
return(tf.SparseTensorValue(indices, chars, [num_words,1,1]))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
t_data_names=tf.constant(df['NAME'])
reference_names = [el.decode('UTF-8') for el in (t_data_names.eval())]
sparse_ref_names = sparse_from_word_vec(reference_names)
sparse_test_name = sparse_from_word_vec([str(input_name.eval().decode('utf-8'))]*5)
feeddict={test_name: sparse_test_name,
ref_names: sparse_ref_names,
}
output_dist = sess.run(output_dist, feed_dict=feeddict)
output_dist = tf.reduce_min(output_dist, 0)
print(output_dist.eval())
tf.saved_model.simple_save(sess,
"model-simple",
inputs={"input_name": input_name},
outputs={"output_dist": output_dist})
And here is my Java method:
public void run(ApplicationArguments args) throws Exception {
log.info("Loading model...");
SavedModelBundle savedModelBundle = SavedModelBundle.load("/model", "serve");
byte[] test_name = "Max Mustermann".toLowerCase().getBytes("UTF-8");
List<Tensor<?>> output = savedModelBundle.session().runner()
.feed("input_name", Tensor.<String>create(test_names))
.fetch("output_dist")
.run();
System.out.printl("Nearest distance: " + output.get(0).floatValue());
}
I was able to get your example working. I have a couple of comments on your python code before diving in.
You use the variable output_dist for 3 different value types throughout the code. I'm not a python expert, but I think it's bad practice. You also never actually use the input_name placeholder, except for exporting it as an input. Last one is that tf.saved_model.simple_save is deprecated, and you should use the tf.saved_model.Builder instead.
Now for the solution.
Looking at the libtensorflow jar file using the command jar tvf libtensorflow-x.x.x.jar (thanks to this post), you can see that there are no useful bindings for creating a sparse tensor (maybe make a feature request?). So we have to change the input to a dense tensor, then add operations to the graph to convert it to sparse. In your original code the sparse conversion was on the python side which means that the loaded graph in java wouldn't have any ops for it.
Here is the new python code:
import tensorflow as tf
import pandas as pd
def model():
#use dense tensors then convert to sparse for edit_distance
test_name = tf.placeholder(shape=(None, None), dtype=tf.string, name="test_name")
ref_names = tf.placeholder(shape=(None, None), dtype=tf.string, name="ref_names")
#Java Does not play well with the empty character so use "/" instead
test_name_sparse = tf.contrib.layers.dense_to_sparse(test_name, "/")
ref_names_sparse = tf.contrib.layers.dense_to_sparse(ref_names, "/")
output_dist = tf.edit_distance(test_name_sparse, ref_names_sparse, normalize=True)
#output the index to the closest ref name
min_idx = tf.argmin(output_dist)
return test_name, ref_names, min_idx
#Python code to be replicated in Java
def pad_string(s, max_len):
return s + ["/"] * (max_len - len(s))
d = {'NAME': ['joseph haydn',
'max mustermann',
'erika musterfrau',
'johann sebastian bach',
'wolfgang amadeus mozart']}
df = pd.DataFrame(data=d)
input_name = 'max musterman'
#pad dense tensor input
max_len = max([len(n) for n in df['NAME']])
test_input = [list(input_name)]*len(df['NAME'])
#no need to pad, all same length
ref_input = list(map(lambda x: pad_string(x, max_len), [list(n) for n in df['NAME']]))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
test_name, ref_names, min_idx = model()
#run a test to make sure the model works
feeddict = {test_name: test_input,
ref_names: ref_input,
}
out = sess.run(min_idx, feed_dict=feeddict)
print("test output:", out)
#save the model with the new Builder API
signature_def_map= {
"predict": tf.saved_model.signature_def_utils.predict_signature_def(
inputs= {"test_name": test_name, "ref_names": ref_names},
outputs= {"min_idx": min_idx})
}
builder = tf.saved_model.Builder("model")
builder.add_meta_graph_and_variables(sess, ["serve"], signature_def_map=signature_def_map)
builder.save()
And here is the java to load and run it. There is probably a lot of room for improvement here (java isn't my main language), but it gives you the idea.
import org.tensorflow.Graph;
import org.tensorflow.Session;
import org.tensorflow.Tensor;
import org.tensorflow.TensorFlow;
import org.tensorflow.SavedModelBundle;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
public class Test {
public static byte[][] makeTensor(String s, int padding) throws Exception
{
int len = s.length();
int extra = padding - len;
byte[][] ret = new byte[len + extra][];
for (int i = 0; i < len; i++) {
String cur = "" + s.charAt(i);
byte[] cur_b = cur.getBytes("UTF-8");
ret[i] = cur_b;
}
for (int i = 0; i < extra; i++) {
byte[] cur = "/".getBytes("UTF-8");
ret[len + i] = cur;
}
return ret;
}
public static byte[][][] makeTensor(List<String> l, int padding) throws Exception
{
byte[][][] ret = new byte[l.size()][][];
for (int i = 0; i < l.size(); i++) {
ret[i] = makeTensor(l.get(i), padding);
}
return ret;
}
public static void main(String[] args) throws Exception {
System.out.println("Loading model...");
SavedModelBundle savedModelBundle = SavedModelBundle.load("model", "serve");
List<String> str_test_name = Arrays.asList("Max Mustermann",
"Max Mustermann",
"Max Mustermann",
"Max Mustermann",
"Max Mustermann");
List<String> names = Arrays.asList("joseph haydn",
"max mustermann",
"erika musterfrau",
"johann sebastian bach",
"wolfgang amadeus mozart");
//get the max length for each array
int pad1 = str_test_name.get(0).length();
int pad2 = 0;
for (String var : names) {
if(var.length() > pad2)
pad2 = var.length();
}
byte[][][] test_name = makeTensor(str_test_name, pad1);
byte[][][] ref_names = makeTensor(names, pad2);
//use a with block so the close method is called
try(Tensor t_test_name = Tensor.<String>create(test_name))
{
try (Tensor t_ref_names = Tensor.<String>create(ref_names))
{
List<Tensor<?>> output = savedModelBundle.session().runner()
.feed("test_name", t_test_name)
.feed("ref_names", t_ref_names)
.fetch("ArgMin")
.run();
System.out.println("Nearest distance: " + output.get(0).longValue());
}
}
}
}

Convert Seq[Byte] in Scala to byte[]/ InputStream

Have Seq[Byte] in scala . How to convert it to java byte[] or Input Stream ?
wouldn't
val a: Seq[Byte] = List()
a.toArray
do the job?
You can copy the contents of a Seq With copyToArray.
val myseq: Seq[Byte] = ???
val myarray = new Array[Byte](myseq.size)
myseq.copyToArray(myarray)
Note that this will iterate through the Seq twice, which may be undesirable, impossible, or just fine, depending on your use.
A sensible option:
val byteSeq: Seq[Byte] = ???
val byteArray: Array[Byte] = bSeq.toArray
val inputStream = java.io.ByteArrayInputStream(byteArray)
A less sensible option:
object HelloWorld {
implicit class ByteSequenceInputStream(val byteSeq: Seq[Byte]) extends java.io.InputStream {
private var pos = 0
val size = byteSeq.size
override def read(): Int = pos match {
case `size` => -1 // backticks match against the value in the variable
case _ => {
val result = byteSeq(pos).toInt
pos = pos + 1
result
}
}
}
val testByteSeq: Seq[Byte] = List(1, 2, 3, 4, 5).map(_.toByte)
def testConversion(in: java.io.InputStream): Unit = {
var done = false
while (! done) {
val result = in.read()
println(result)
done = result == -1
}
}
def main(args: Array[String]): Unit = {
testConversion(testByteSeq)
}
}

Categories