Containers Array¶

some refs https://www.sandordargo.com/blog/2023/04/12/vector-of-unique-pointers

In [1]:
import ROOT
In [2]:
import fortranmagic
%load_ext fortranmagic
import os
import sys

import numpy as np

if sys.platform.startswith("win"):
        # Depends of system, python builds, and compilers compatibility.
        # See below.
    f_config = "--fcompiler=gnu95 --compiler=mingw32"
else:
        # For Unix, compilers are usually more compatible.
    f_config = ""

    # Disable only deprecated NumPy API warning without disable any APIs.
f_config += " --extra '-DNPY_NO_DEPRECATED_API=0'"

%fortran_config {f_config}
New default arguments for %fortran:
	 --extra '-DNPY_NO_DEPRECATED_API=0'

c++¶

use it in real compiler such as gcc, clang or msvc: https://visualstudio.microsoft.com/de/vs/community/

In [3]:
%%cpp -d
#include <iostream>
#include <vector>
#include <memory>

using namespace std;
class Geometry {
public:
    Geometry() {}
    virtual ~Geometry() = default;
    virtual double getArea() = 0;
    virtual double getCircumference() = 0;
};

class Rectangle1 :public Geometry {
public:
    Rectangle1(double width, double height) :width(width), height(height) {//when exist c calles the standard constructor of the parent class
    }
    //virtual ~Rectangle() {}//destructor if not used leave it out
    virtual double getArea() override {
        return width * height;
    }
    virtual double getCircumference() override {
        return 2 * (width + height);
    }
protected: //can be only accessed by this class and children

private: //can only be accessed by this class
    double width;
    double height;
};

class Square :public Rectangle1 {
public:
    Square(double l) :Rectangle1(l, l) {
    }
};

class Disc :public Geometry {
public:
    Disc(double r) :r(r) {
    }
    virtual double getArea() {
        return 3.1415926 * r * r;
    }
    virtual double getCircumference() {
        return 2 * 3.1415926 * r;
    }
protected:
    double r;
};
In [4]:
%%cpp
//void main()
{
    Rectangle1 r(2.1, 3.1);
    Square s(3.1);
    Disc d(2.1);

    cout << r.getArea() << endl;
    cout << r.getCircumference() << endl;
    cout << endl;

    cout << s.getArea() << endl;
    cout << s.getCircumference() << endl;
    cout << endl;

    cout << d.getArea() << endl;
    cout << d.getCircumference() << endl;

    std::vector<std::shared_ptr<Geometry>> v;
    v.push_back(std::make_shared<Disc>(2.1));
    v.push_back(std::make_shared<Rectangle1>(2.1, 3.1));
    v.push_back(std::make_shared<Square>(3.1));

    for (auto i : v)
    {
        std::cout << i->getArea() << std::endl;
    }
}
6.51
10.4

9.61
12.4

13.8544
13.1947
13.8544
6.51
9.61

javascript¶

In [5]:
%%js //the next line is only necessary in jupyter notebooks
element.setAttribute('style', 'white-space: pre;');console.log=function(text){element.textContent+=text+"\n"}

class Geometry{
    constructor() {
        if (this.constructor == Geometry) {
            throw new Error("Abstract classes can't be instantiated.");
        }
    }
    getArea(){
        throw new Error("Method 'getArea()' must be implemented.");
    }
    getCircumference(){
        throw new Error("Method 'getCircumference()' must be implemented.");
    }
}

class Rectangle extends Geometry{
    constructor(width, height){
        super();
        this.width=width
        this.height=height
    }
    getArea(){
        return this.width*this.height;
    }
    getCircumference(){
        return 2*(this.width+this.height);
    }
}

class Square extends Rectangle{
     constructor(l){
        super(l,l);
    }
}

class Disc extends Geometry{
     constructor(r){
        super();
        this.r=r;
    }
    getArea(){
        return Math.PI*this.r*this.r;
    }
    getCircumference(){
        return 2*Math.PI*this.r;
    }
}

let m=[];

m.push(new Rectangle(2.1,3.1))
m.push(new Square(3.1))
m.push(new Disc(2.1))


for(let i in m){
    console.log(m[i].getArea())
    
}

Python¶

In [6]:
from abc import ABC, abstractmethod
import math

class Geometry(ABC):
    @abstractmethod
    def getArea(self):
        pass
    def getCircumference(self):
        pass

class Rectangle(Geometry):
    def __init__(self,width, height):
        self.width=width
        self.height=height
        super().__init__()
    def getArea(self):
        return self.width*self.height
    def getCircumference(self):
        return 2*(self.width+self.height)

class Square(Rectangle):
    def __init__(self,l):
        super().__init__(l,l);

class Disc(Geometry):
    def __init__(self,r):
        self.r=r
        super().__init__();
    def getArea(self):
        return math.pi*self.r*self.r
    def getCircumference(self):
        return 2*math.pi*self.r;

m=[]
m.append(Rectangle(2.1,3.1))
m.append(Square(3.1))
m.append(Disc(2.1))

for el in m:
    print(el.getArea())
6.510000000000001
9.610000000000001
13.854423602330987
In [7]:
%%fortran

module shapes_mod
  use iso_fortran_env, only : real64
  implicit none
  private
  public :: geometry, rectangle1, square, disc
  public :: make_rectangle1, make_square, make_disc
  public :: box, push_back

  ! Abstract base "class"
  type, abstract :: geometry
  contains
    procedure(getArea_if),  deferred :: getArea
    procedure(getCirc_if),  deferred :: getCircumference
  end type geometry

  abstract interface
    pure function getArea_if(self) result(a)
      import :: geometry, real64
      class(geometry), intent(in) :: self
      real(real64) :: a
    end function getArea_if

    pure function getCirc_if(self) result(c)
      import :: geometry, real64
      class(geometry), intent(in) :: self
      real(real64) :: c
    end function getCirc_if
  end interface

  ! Rectangle: concrete subclass
  type, extends(geometry) :: rectangle1
     private
     real(real64) :: w, h
  contains
     procedure :: getArea          => rect_area
     procedure :: getCircumference => rect_circ
  end type rectangle1

  ! Square: subclass of Rectangle1
  type, extends(rectangle1) :: square
    ! Inherits area and circumference; no overrides needed
  end type square

  ! Disc: concrete subclass
  type, extends(geometry) :: disc
     private
     real(real64) :: r
  contains
     procedure :: getArea          => disc_area
     procedure :: getCircumference => disc_circ
  end type disc

  ! Simple container element to allow mixed dynamic types in one array
  type :: box
     class(geometry), allocatable :: obj
  end type box

contains

  ! "Constructors" (factory functions)
  pure function make_rectangle1(width, height) result(x)
    real(real64), intent(in) :: width, height
    type(rectangle1) :: x
    x%w = width
    x%h = height
  end function make_rectangle1

  pure function make_square(l) result(x)
    real(real64), intent(in) :: l
    type(square) :: x
    ! Access to parent components is allowed within this module
    x%w = l
    x%h = l
  end function make_square

  pure function make_disc(rr) result(x)
    real(real64), intent(in) :: rr
    type(disc) :: x
    x%r = rr
  end function make_disc

  ! Implementations of virtuals
  pure function rect_area(self) result(a)
    class(rectangle1), intent(in) :: self
    real(real64) :: a
    a = self%w * self%h
  end function rect_area

  pure function rect_circ(self) result(c)
    class(rectangle1), intent(in) :: self
    real(real64) :: c
    c = 2.0_real64 * (self%w + self%h)
  end function rect_circ

  pure function disc_area(self) result(a)
    class(disc), intent(in) :: self
    real(real64) :: a
    real(real64), parameter :: pi = acos(-1.0_real64)
    a = pi * self%r * self%r
  end function disc_area

  pure function disc_circ(self) result(c)
    class(disc), intent(in) :: self
    real(real64) :: c
    real(real64), parameter :: pi = acos(-1.0_real64)
    c = 2.0_real64 * pi * self%r
  end function disc_circ

  ! A minimal push_back for a vector-like array of boxes
  subroutine push_back(vec, g)
    type(box), allocatable, intent(inout) :: vec(:)
    class(geometry), intent(in)           :: g
    type(box), allocatable :: tmp(:)
    integer :: n
    if (.not. allocated(vec)) then
      allocate(vec(1))
      allocate(vec(1)%obj, source=g)
    else
      n = size(vec)
      allocate(tmp(n+1))
      tmp(1:n) = vec
      allocate(tmp(n+1)%obj, source=g)
      call move_alloc(tmp, vec)
    end if
  end subroutine push_back

end module shapes_mod


! program and subroutine exchanged due to jupyternotebook

! program main
subroutine main()
  use iso_fortran_env, only : real64
  use shapes_mod
  implicit none

  type(rectangle1) :: r
  type(square)     :: s
  type(disc)       :: d
  type(box), allocatable :: v(:)
  integer :: i

  r = make_rectangle1(2.1_real64, 3.1_real64)
  s = make_square(3.1_real64)
  d = make_disc(2.1_real64)

  print *, r%getArea()
  print *, r%getCircumference()
  print *

  print *, s%getArea()
  print *, s%getCircumference()
  print *

  print *, d%getArea()
  print *, d%getCircumference()

  call push_back(v, make_disc(2.1_real64))
  call push_back(v, make_rectangle1(2.1_real64, 3.1_real64))
  call push_back(v, make_square(3.1_real64))

  do i = 1, size(v)
    print *, v(i)%obj%getArea()
  end do
! end program
end subroutine main
In [8]:
main()
   6.5100000000000007     
   10.400000000000000     

   9.6100000000000012     
   12.400000000000000     

   13.854423602330987     
   13.194689145077131     
   13.854423602330987     
   6.5100000000000007     
   9.6100000000000012