Sunday, December 03, 2023

Java 21: Sequenced Collections

Introduced in Java 21, a SequencedCollection is a Collection whose elements have a defined encounter order i.e. it has first and last elements, and the elements between them have successors and predecessors. Some examples include List, Deque, SortedSet, and LinkedHashSet.

The SequencedCollection interface provides methods to add, retrieve, and remove elements at either end of the collection. It also has a reversed() method which provides a reverse-ordered view of the original collection.

Similarly, the new SequencedMap interface is a map that has a well-defined encounter order, supports operations at both ends, and is reversible. Examples include LinkedHashMap and TreeMap.

Example usage:

var set = new LinkedHashSet<String>(Arrays.asList("a", "b", "c"));

set instanceof SequencedCollection
==> true

set.getFirst()
==> "a"

set.getLast()
==> "c"

set.reversed()
==> [c, b, a]

Saturday, December 02, 2023

Java 21: Unnamed Classes

Java 21 introduces Unnamed Classes (a preview language feature) that allow you to write small programs without having an enclosing class declaration.

Here is the classic Hello World program that we were all taught when starting to learn Java:

public class HelloWorld { 
  public static void main(String[] args) { 
    System.out.println("Hello, World!");
  }
}

There is a lot of clutter here. Using an unnamed class, this can be simplified to:

void main() { 
  System.out.println("Hello, World!");
}

Not only is the enclosing class not required, but the main method has also been enhanced so that it does not need to be public, static or require any arguments.

You can also add fields and methods to an unnamed class, as shown below:

private static final String GREETING = "Hello, World!";

private String getGreeting() {
  return GREETING;
}

void main() { 
  System.out.println(getGreeting());
}

Since an unnamed class cannot be instantiated or referenced by name, it is only useful as a standalone program or as an entry point to a program.

Saturday, November 25, 2023

Java 21: String Templates

In Java 21, String Templates have been introduced as a preview language feature, that allow text and expressions to be composed safely and efficiently, without using the + operator.

Here is an example:

int x = 5, y = 6;

String s = STR."\{x} plus \{y} is equal to \{x + y}";

// evaluates to: "5 plus 6 is equal to 11"

In this example, STR is a template processor. The template is \{x} plus \{y} is equal to \{x + y} and \{x} is one of the embedded expressions in the template. The STR template processor is defined in the Java Platform (and is automatically imported into every Java source file), and it performs string interpolation by evaluating the embedded expressions.

More examples:

// you can invoke methods, access fields, use ternaries
String s = STR."\{user.name}: Access \{user.hasAccess() ? "Granted" : "Denied"}";

// multi-line template expression
String xml = STR."""
<book>
  <author>\{author}</author>
  <title>\{title}</title>
</book>
""";

FMT Template Processor

FMT is like STR but it also interprets format specifiers which appear to the left of embedded expressions. For example:

double val = 4999.4567;

FormatProcessor.FMT."The value is %,.2f\{val}";

// evaluates to: "The value is 4,999.46"

It's quite easy to create your own Template Processor by implementing StringTemplate.Processor. This is useful if you want to validate inputs before composing the string. It's also possible to return an object of any type, not just String. For instance, a SQL Template processor could first sanitise the input to prevent a SQL injection attack, and then return a PreparedStatement instead of a String.

Sunday, September 03, 2023

Linear and Polynomial Regression in kdb+/q

In this post, I'll describe how you can implement linear and polynomial regression in kdb+/q to determine the equation of a line of best fit (also known as a trendline) through the data on a scatter plot.

Consider the following scatter plot:

Our aim is to estimate a function of a line that most closely fits the data.

The vector of estimated polynomial regression coefficients (using ordinary least squares estimation) can be obtained using the following formula (for information about how this formula is derived, see Regression analysis [Wikipedia]):

b = (XTX)−1XTy

This can be translated into q as follows:

computeRegressionCoefficients:{
    xt:flip x;
    xt_x:xt mmu x;
    xt_x_inv:inv xt_x;
    xt_y:xt mmu y;
    xt_x_inv mmu xt_y}

Linear:
In order to perform linear regression, we have to first create a matrix X with a column of 1s and a column containing the x-values. The output of linear regression will be a vector of 2 coefficients and the equation of the trendline will be of the form: y = b1x + b0

computeLinearRegressionCoefficients:{
    computeRegressionCoefficients[flip (1f;x);y]}

Polynomial:
In order to fit a polynomial line, all we have to do is take the matrix X from the linear regression model and add more columns corresponding to the order of the polynomial desired. For example, for quadratic regression, we will add a column for x2 on the right side of the matrix X. The output of quadratic regression will be a vector of 3 coefficients and the equation of the curve will be of the form: y = b2x2 + b1x + b0

// quadratic
computeQuadraticRegressionCoefficients:{
    computeRegressionCoefficients[flip (1f;x;x*x);y]}

// cubic
computeCubicRegressionCoefficients:{
    computeRegressionCoefficients[flip (1f;x;x*x;x*x*x);y]}

// generalisation of polynomial regression for any order
computePolynomialRegressionCoefficients:{[x;y;order]
    computeRegressionCoefficients[flip x xexp/: til order+1;y]}

Related post:
Matrix Operations in kdb+/q

Saturday, September 02, 2023

Python: Printing the Stdout/Stderr of a Subprocess

This is how you can run a subprocess in python and print out its stdout and stderr:

import subprocess

proc = subprocess.Popen(["/path/to/myscript", "arg1", "arg2"], 
            stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
for line in proc.stdout:
    print(line.decode().rstrip())
proc.wait()
if proc.returncode != 0:
    print("Command failed with status:", proc.returncode)

Check out the subprocess documentation for more information.

Related post:
Python Cheat Sheet