Counting Sort

Counting sort – counting sort algorithm. What? Yes! Just like that!

The algorithm involves at least two arrays, the first is a list of integers to be sorted, the second is an array of size = (maximum number – minimum number) + 1, initially containing only zeros. Next, the numbers from the first array are sorted out, the index in the second array is obtained by the element-number, which is incremented by one. After going through the entire list, we will get a completely filled second array with the number of repetitions of numbers from the first. The algorithm has a serious overhead – the second array also contains zeros for numbers that are not in the first list, the so-called. memory overhead.

After getting the second array, iterate over it and write the sorted version of the number by index, decrementing the counter to zero. Initially, the zero counter is ignored.

An unoptimized example of how the counting sort algorithm works:

  1. Input array 1,9,1,4,6,4,4
  2. Then the array to count will be 0,1,2,3,4,5,6,7,8,9 (minimum number 0, maximum 9)
  3. With total counters 0,2,0,0,3,0,1,0,0,1
  4. Total sorted array 1,1,4,4,4,6,9

Algorithm code in Python 3:

print("Counting Sort")

numbers = [42, 89, 69, 777, 22, 35, 42, 69, 42, 90, 777]

minimal = min(numbers)
maximal = max(numbers)
countListRange = maximal - minimal
countListRange += 1
countList = [0] * countListRange

print(numbers)
print(f"Minimal number: {minimal}")
print(f"Maximum number: {maximal}")
print(f"Count list size: {countListRange}")

for number in numbers:
    index = number - minimal
    countList[index] += 1

replacingIndex = 0
for index, count in enumerate(countList):
    for i in range(count):
        outputNumber = minimal + index
        numbers[replacingIndex] = outputNumber
        replacingIndex += 1

print(numbers)

Due to the use of two arrays, the time complexity of the algorithm is O(n + k)

Links

https://gitlab.com/demensdeum/algorithms/-/tree/master/sortAlgorithms/countingSort

Sources

https://www.youtube.com/watch?v=6dk_csyWif0
https://www.youtube.com/watch?v=OKd534EWcdk
https://en.wikipedia.org/wiki/Counting_sort
https://rosettacode.org/wiki/Sorting_algorithms/Counting_sort
https://pro-prof.com/forums/topic/%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC-%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B8-%D0%BF%D0%BE%D0%B4%D1%81%D1%87%D0%B5%D1%82%D0%BE%D0%BC

Bogosort

Pseudo sort or swamp sort, one of the most useless sorting algorithms.

It works like this:
1. Input is an array of numbers
2. An array of numbers is shuffled randomly (shuffle)
3. Checking if the array is sorted
4. If not sorted, then the array is shuffled again
5. All this action is repeated until the array is sorted randomly.

As you can see, the performance of this algorithm is terrible, smart people think that even O(n * n!) there is a chance to get stuck throwing dice for the glory of the god of chaos for many years, the array will not be sorted, or maybe sorted?

Implementation

For the TypeScript implementation, I needed to implement the following functions:
1. Shuffling an array of objects
2. Comparing arrays
3. Generating a random number between zero and a number (sic!)
4. Seal of progress, as the sorting seems to run indefinitely

Below is the TypeScript implementation code:

const printoutProcess = (numbers: number[], sortedNumbers: number[], numberOfRuns: number) => console.log(`Still trying to sort: ${numbers}, current shuffle ${sortedNumbers}, try number: ${numberOfRuns}`);
const randomInteger = (maximal: number) => Math.floor(Math.random() * maximal);
const isEqual = (lhs: any[], rhs: any[]) => lhs.every((val, index) => val === rhs[index]);
const shuffle = (array: any[]) => {
    for (var i = 0; i < array.length; i++) { var destination = randomInteger(array.length-1); vartemp = array[i]; array[i] = array[destination]; array[destination] = temp; } } let numbers: number[] = Array.from({length: 10}, ()=>randomInteger(10));
const originalNumbers = [...numbers];
const sortedNumbers = [...numbers].sort();

let numberOfRuns = 1;

do {
    if (numberOfRuns % 1000 == 0) {
        printoutProcess(originalNumbers, numbers, numberOfRuns);
    }
    shuffle(numbers);
    numberOfRuns++;
} while (isEqual(numbers, sortedNumbers) == false)

console.log(`Success!`);
console.log(`Run number: ${numberOfRuns}`)
console.log(`Original numbers: ${originalNumbers}`);
console.log(`Current numbers: ${originalNumbers}`);
console.log(`Sorted numbers: ${sortedNumbers}`);

You can use VSCode and kakumei’s TypeScript Debugger plugin for debugging.

How long

Output of the algorithm:

Still trying to sort: 5,4,8,7,5,0,2,9,7,2, current shuffle 2,9,7,8,0,7,4,5,2 ,5, try number: 144000
src/bogosort.ts:1
Still trying to sort: 5,4,8,7,5,0,2,9,7,2, current shuffle 8,7,0,2,4,7,2,5,9,5, try number: 145000
src/bogosort.ts:2
Still trying to sort: 5,4,8,7,5,0,2,9,7,2, current shuffle 7,5,2,4,9,8,0,5,2,7, try number: 146000
src/bogosort.ts:2
Still trying to sort: 5,4,8,7,5,0,2,9,7,2, current shuffle 0,2,7,4,9,5,7,5,8,2, try number: 147000
src/bogosort.ts:2
Still trying to sort: 5,4,8,7,5,0,2,9,7,2, current shuffle 5,9,7,8,5,4,2,7,0,2, try number: 148000
src/bogosort.ts:2
Success!
src/bogosort.ts:24
Run number: 148798
src/bogosort.ts:25
Original numbers: 5,4,8,7,5,0,2,9,7,2
src/bogosort.ts:26
Current numbers: 5,4,8,7,5,0,2,9,7,2
src/bogosort.ts:27
Sorted numbers: 0,2,2,4,5,5,7,7,8,9

For an array of 10 numbers, Bogosort shuffled the original array 148798 times, too much right?
The algorithm can be used as a training one, to understand the capabilities of the language with which to work on the market. Personally, I was surprised to learn that vanilla JS and TS still do not have their own algorithm for shuffling arrays, generating an integer in a range, accessing object hashes for quick comparison.

Links

https://gitlab.com/demensdeum /algorithms/-/tree/master/sortAlgorithms/bogosort
https://www.typescriptlang.org/
https://marketplace.visualstudio.com/items?itemName= kakumei.ts-debug

Sources

https://www.youtube.com/watch?v=r2N3scbd_jg
https://en.wikipedia.org/wiki/Bogosort

GoF Patterns

List of most important OOP patterns in computer programming aka Gang of Four Design Patterns.

Creational patterns

Structural patterns

Behavioral patterns

Interpreter Pattern

What’s included

The Interpreter Pattern is a Behavioral Design Pattern. This pattern allows you to implement your own programming language by working with an AST tree, the vertices of which are terminal and non-terminal expressions that implement the Interpret method, which provides the functionality of the language.

  • Terminal expression – e.g. string constant – “Hello World”
  • Non-terminal expression – e.g. Print(“Hello World”), contains Print and an argument from the Terminal expression “Hello World”

What’s the difference? The difference is that the interpretation on terminal expressions ends, and for non-terminal expressions it continues deep into all incoming nodes/arguments. If the AST tree consisted only of non-terminal expressions, then the application would never complete, because some end of any process is required, this end is what terminal expressions are, they usually contain data, for example, strings.

An example of an AST tree is below:


Dcoetzee, CC0, via Wikimedia Commons

As you can see, terminal expressions are constant and variable, non-terminal expressions are the rest.

What is not included

The implementation of the Interpreter does not parse the string input of the language into the AST tree. It is enough to implement classes of terminal, non-terminal expressions, Interpret methods with the Context argument at the input, form an AST tree from expressions, run the Interpret method at the root expression. The context can be used to store the state of the application at runtime.

Implementation

Participants in the pattern:

  • Client – returns AST tree and runs Interpret(context) on root node (Client)
  • Context – contains the state of the application, passed to expressions when interpreted (Context)
  • Abstract expression – an abstract class containing the method Interpret(context) (Expression)
  • Terminal expression is a final expression, a descendant of an abstract expression (TerminalExpression)
  • A non-terminal expression is not a final expression, contains pointers to nodes deep into the AST tree, subordinate nodes usually affect the result of interpreting a non-terminal expression (NonTerminalExpression)

C# Client Example

class Application {
        static void Main(string[] args)
        {
            var context = new Context();
            var initialProgram = new PerformExpression(
                new IExpression[] {
                    new SetExpression("alpha", "1"),
                    new GetExpression("alpha"),
                    new PrintExpression(
                        new IExpression[] {
                            new ConstantExpression("Hello Interpreter Pattern")
                        }
                    )
                }
            );
            System.Console.WriteLine(initialProgram.interpret(context));
        }
}

Example of an Abstract Expression in C#

interface IExpression
{
    String interpret(Context context);
}

C# Terminal Expression Example (String Constant)

class ConstantExpression : TerminalExpression
{
    private String constant;

    public ConstantExpression(String constant) {
        this.constant = constant;
    }

    override public String interpret(Context context) {
        return constant;
    }
}

Example of a Non-Terminal Expression in C# (Launching and concatenating the results of subordinate nodes, using the delimiter “;”

class PerformExpression : NonTerminalExpression
{
    public PerformExpression(IExpression[] leaves) : base(leafs) {
        this.leafs = leaves;
    }
    
    override public String interpret(Context context) {
        var output = "";
        foreach (var leaf in leaves) {
            output += leaf.interpret(context) + ";";
        }
        return output;
    }
}

Functionally, can you?

As you know, all Turing-complete languages ​​are equivalent. Can the Object-Oriented pattern be transferred to a Functional Programming language?

You can, for the experiment, let’s take the FP language for the web called Elm. There are no classes in Elm, but there are Records and Types, so the following records and types are involved in the implementation:

  • Expression – enumeration of all possible language expressions (Expression)
  • Subordinate expression – an expression that is subordinate to a non-terminal expression (ExpressionLeaf)
  • Context – a record that stores the state of the application (Context)
  • Functions that implement the Interpret(context) methods – all the necessary functions that implement the functionality of Terminal, Non-Terminal expressions
  • Auxiliary records of the Interpreter state – necessary for the correct operation of the Interpreter, store the state of the Interpreter, the context

For example function that implements the interpretation for the entire set of possible expressions on Elm:

run input =
  case input.expression of
    Constant text ->
      {
        output = text
        context = input.context
      }
    Perform leafs ->
      let inputs = List.map (\leaf -> { expressionLeaf = leaf, context = input.context } ) leafs in
        let startLeaf = { expressionLeaf = (Node (Constant "")), context = { variables = Dict.empty } } in
          let outputExpressionInput = List.foldl mergeContextsAndRunLeafs startLeaf inputs in
            {
              output = (runExpressionLeaf outputExpressionInput).output,
              context = input.context
            }
    Print printExpression ->
      run
      {
        expression = printExpression,
        context = input.context
      }
    Set key value ->
      let variables = Dict.insert key value input.context.variables in
      {
        output="OK",
        context = { variables = variables }
      }
    get key ->
      {
        output = Maybe.withDefault("No value for key: " ++ key)(Dict.get key input.context.variables),
        context = input.context
      }

What about parsing?

Parsing source code into an AST tree is not part of the Interpreter pattern, there are several approaches to parsing source code, but more on that some other time.
In the implementation of the Interpreter for Elm, I wrote the simplest parser into the AST tree, consisting of two functions – parsing a vertex, parsing subordinate vertices.

parseLeafs: ParseLeafsState -> ParseLeafsState
parseLeafs state =
    let tokensQueue = state.tokensQueue in
        let popped = pop state.tokensQueue in
            let tokensQueueTail = tail state.tokensQueue in
                if popped == "Nothing" then
                    state
                else if popped == "Perform(" then
                    {
                        tokensQueue = tokensQueue,
                        result = (state.result++[Node(parse tokensQueue)])
                    }
                else if popped == ")" then
                    parseLeafs {
                        tokensQueue = tokensQueueTail,
                        result = state.result
                    }
                else if popped == "Set" then
                    let key = pop tokensQueueTail in
                        let value = pop(tail tokensQueueTail) in
                            parseLeafs {
                                tokensQueue = tail(tail tokensQueueTail),
                                result = (state.result++[Node(Set key value)])
                            }
                else if popped == "Get" then
                    let key = pop tokensQueueTail in
                        parseLeafs {
                            tokensQueue = tail tokensQueueTail,
                            result = (state.result++[Node(Get key)])
                        }
                else
                    parseLeafs {
                        tokensQueue = tokensQueueTail,
                        result = (state.result++[Node(Constant popped)])
                    }

parse tokensQueue =
    let popped = pop tokensQueue in
        let tokensQueueTail = tail tokensQueue in
            if popped == "Perform(" then
                Perform(
                    parseLeafs {
                        tokensQueue = tokensQueueTail,
                        result = []
                    }
                ).result
            else if popped == "Set" then
                let key = pop tokensQueueTail in
                    let value = pop(tail tokensQueueTail) in
                        set key value
            else if popped == "Print" then
                Print(parse tokensQueueTail)
            else
                Constant popped

Links

https://gitlab.com/demensdeum /patterns/-/tree/master/interpreter/elm
https://gitlab.com/demensdeum/patterns/ -/tree/master/interpreter/csharp

Sources

https://en.wikipedia.org/wiki/Interpreter_pattern
https://elm-lang.org/
https://docs.microsoft.com/en-us/dotnet /csharp/

RGB Image to Grayscale

In this article I will describe algorithm of converting RGB image buffer to Grayscale
And this is done quite simply, each pixel of the color channel of the buffer is converted according to a certain formula, and the output is a gray image.
Average method:

const average = (red + green + blue) / 3;
red = average;
green = average;
blue = average;

Add the 3 color channels and divide by 3.

However, there is another method – the weighted average method, it takes into account the human color perception:

const luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue;
red = luminance;
green = luminance;
blue = luminance;

What is the best method to use? Choose one that suits you better for a particular task. Next, a comparison of methods using a test color grid:

Example JavaScript + HTML 5

function rgb2grayscale(
    image,
    canvas,
    weightedAverage
) {
    const context = canvas.getContext('2d');

    const imageWeight = image.width;
    const imageHeight = image.height;

    canvas.width = imageWeight;
    canvas.height = imageHeight;

    context.drawImage(image, 0, 0);

    let pixels = context
        .getImageData(
            0,
            0,
            imageWeight,
            imageHeight
        );

    for (let y = 0; y & lt; pixels.height; y++) {
        for (let x = 0; x & lt; pixels.width; x++) {
            const i = (y * 4) * pixels.width + x * 4;

            let red = pixels.data[i];
            let green = pixels.data[i + 1];
            let blue = pixels.data[i + 2]

            const average = (red + green + blue) / 3;
            const luminance = 0.2126 * red +
                0.7152 * green +
                0.0722 * blue;

            red = weightedAverage ? luminance : average;
            green = weightedAverage ? luminance : average;
            blue = weightedAverage ? luminance : average;

            pixels.data[i] = red;
            pixels.data[i + 1] = green;
            pixels.data[i + 2] = blue;
        }
    }
    context
        .putImageData(
            pixels,
            0,
            0,
            0,
            0,
            pixels.width,
            pixels.height
        );
}

References

https://www.baeldung.com/cs/convert-rgb-to-grayscale
https://twitter.com/mudasobwa/status/1528046455587495940
https://rosettacode.org/wiki/Grayscale_image

Links

http://papugi.demensdeum.repl.co/

Thanks

Thanks to Aleksei Matiushkin (https://twitter.com/mudasobwa) for showing Rosetta Code