How to resolve the algorithm Active object step by step in the Nim programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Active object step by step in the Nim programming language

Table of Contents

Problem Statement

In object-oriented programming an object is active when its state depends on clock. Usually an active object encapsulates a task that updates the object's state. To the outer world the object looks like a normal object with methods that can be called from outside. Implementation of such methods must have a certain synchronization mechanism with the encapsulated task in order to prevent object's state corruption. A typical instance of an active object is an animation widget. The widget state changes with the time, while as an object it has all properties of a normal widget. The task Implement an active integrator object. The object has an input and output. The input can be set using the method Input. The input is a function of time. The output can be queried using the method Output. The object integrates its input over the time and the result becomes the object's output. So if the input is K(t) and the output is S, the object state S is changed to S + (K(t1) + K(t0)) * (t1 - t0) / 2, i.e. it integrates K using the trapeze method. Initially K is constant 0 and S is 0. In order to test the object: Verify that now the object's output is approximately 0 (the sine has the period of 2s). The accuracy of the result will depend on the OS scheduler time slicing and the accuracy of the clock.

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Active object step by step in the Nim programming language

Source code in the nim programming language

# Active object.
# Compile with "nim c --threads:on".

import locks
import os
import std/monotimes

type

  # Function to use for integration.
  TimeFunction = proc (t: float): float {.gcsafe.}

  # Integrator object.
  Integrator = ptr TIntegrator
  TIntegrator = object
    k: TimeFunction                 # The function to integrate.
    dt: int                         # Time interval in milliseconds.
    thread: Thread[Integrator]      # Thread which does the computation.
    s: float                        # Computed value.
    lock: Lock                      # Lock to manage concurrent accesses.
    isRunning: bool                 # True if integrator is running.

#---------------------------------------------------------------------------------------------------

proc newIntegrator(f: TimeFunction; dt: int): Integrator =
  ## Create an integrator.

  result = cast[Integrator](allocShared(sizeof(TIntegrator)))
  result.k = f
  result.dt = dt
  result.s = 0
  result.lock.initLock()
  result.isRunning = false

#---------------------------------------------------------------------------------------------------

proc process(integrator: Integrator) {.thread, gcsafe.} =
  ## Do the integration.

  integrator.isRunning = true
  let start = getMonotime().ticks
  var t0: float = 0
  var k0 = integrator.k(0)
  while true:
    sleep(integrator.dt)
    withLock integrator.lock:
      if not integrator.isRunning:
        break
      let t1 = float(getMonoTime().ticks - start) / 1e9
      let k1 = integrator.k(t1)
      integrator.s += (k1 + k0) * (t1 - t0) / 2
      t0 = t1
      k0 = k1

#---------------------------------------------------------------------------------------------------

proc start(integrator: Integrator) =
  ## Start the integrator by launching a thread to do the computation.
  integrator.thread.createThread(process, integrator)

#---------------------------------------------------------------------------------------------------

proc stop(integrator: Integrator) =
  ## Stop the integrator.

  withLock integrator.lock:
    integrator.isRunning = false
  integrator.thread.joinThread()

#---------------------------------------------------------------------------------------------------

proc setInput(integrator: Integrator; f: TimeFunction) =
  ## Set the function.
  withLock integrator.lock:
    integrator.k = f

#---------------------------------------------------------------------------------------------------

proc output(integrator: Integrator): float =
  ## Return the current output.
  withLock integrator.lock:
    result = integrator.s

#---------------------------------------------------------------------------------------------------

proc destroy(integrator: Integrator) =
  ## Destroy an integrator, freing the resources.

  if integrator.isRunning:
    integrator.stop()
  integrator.lock.deinitLock()
  integrator.deallocShared()

#---------------------------------------------------------------------------------------------------

from math import PI, sin

# Create the integrator and start it.
let integrator = newIntegrator(proc (t: float): float {.gcsafe.} = sin(PI * t), 1)
integrator.start()
echo "Integrator started."
sleep(2000)
echo "Value after 2 seconds: ", integrator.output()

# Change the function to use.
integrator.setInput(proc (t: float): float {.gcsafe.} = 0)
echo "K function changed."
sleep(500)

# Stop the integrator and display the computed value.
integrator.stop()
echo "Value after 0.5 more second: ", integrator.output()
integrator.destroy()


  

You may also check:How to resolve the algorithm Mouse position step by step in the AutoHotkey programming language
You may also check:How to resolve the algorithm Hofstadter Q sequence step by step in the JavaScript programming language
You may also check:How to resolve the algorithm Semordnilap step by step in the Tcl programming language
You may also check:How to resolve the algorithm Greatest subsequential sum step by step in the M4 programming language
You may also check:How to resolve the algorithm Elementary cellular automaton/Random number generator step by step in the Pascal programming language