【问题标题】:Dynamically type array in Matlab to Fortran将 Matlab 中的动态类型数组转换为 Fortran
【发布时间】:2019-06-21 11:44:24
【问题描述】:

Matlab 具有动态类型数组的能力。比如matlab代码是

function testing1
clc;
close all;
    chrom_len = 35;


function out = newChromosome(len)
genes_pool = struct(...
    'gene',       {'#', 'U-', 'Rs', '+', '-', '*', '/', '^'}, ...
    'stackDepth', {0,   0,    1,    2,   2,   2,  2,  2},...
    'deltaStack', {1,   1,    0,   -1,  -1,   -1, -1, -1});

function gene = newGene(stackDepth)
    % Select an appropriate gene
    done = false;    
    while ~done
        ind = randi([1 numel(genes_pool)], 1, 1);

        if genes_pool(ind).stackDepth <= stackDepth
            done = true;
        end
    end
    % Generate output

    gene = genes_pool(ind);
        disp('start');
        disp('gene.gene is ');
        disp(gene.gene);
         disp('stop');
    if gene.gene == '#'
        gene.gene = round(randn(1,1) * 5);
        disp('new gene.gene is ');
        disp(gene.gene);
        disp('the gene is ');
        disp(gene);
    end
   end

 genes = {}; stack = [];
 stackDepth = 0;    
 i = 1;
 while i <= len || (i > len && stackDepth ~= 1)
     gene = newGene(stackDepth);
 %    disp('outside gene');
 %    disp(gene);
    class(gene.gene) 
    stackDepth = stackDepth + gene.deltaStack;
 %    disp('stackDepth');
 %    disp(stackDepth);
    genes = [genes, gene.gene];
 %   disp('genes');
 %    disp(genes);
    stack = [stack, stackDepth];
 %    disp('stack')
 %   disp(stack);
    i = i + 1;
    if strcmp(gene.gene, 'X') && rand(1,1) < 0.5
        genes = [genes, randi([2 4], 1)]; stackDepth = stackDepth + 1;
        stack = [stack, stackDepth];
        genes = [genes, '^']; stackDepth = stackDepth - 1;
        stack = [stack, stackDepth];
    end
    return;
 end
 out = struct('genes', {genes}, 'stack', {stack});
 return; 
end

newChromosome(2) 
end

第一次运行 Matlab 的输出(我用的是 GNU Octave 也是一样的)是,

start
gene.gene is
U-
stop
ans = char 

第二次运行Matlab的输出是,

start
gene.gene is
#
stop
new gene.gene is
-11
the gene is

scalar structure containing the fields:

gene = -11
stackDepth = 0
deltaStack =  1
ans = double

当我将 Matlab 翻译成 Fortran 时,我想复制输出,以便输出 Fortran 与 Matlab 中的类型相同。 gene.gene 结果可以是字符或双精度。这意味着,它可以有两种类型。 是否可以在 Fortran 中做同样的事情?如何在 Fortran 中动态键入变量?我相信这与类型转换有关。 到目前为止,我的 Fortran 解决方案是,

function newchromosome(clen) result(out1)
implicit none

 type garray
 character*2 :: gene; 
 integer     :: stackdepth; 
 integer     :: deltastack;
 end type 

 type(garray), dimension(8) :: genespool
 type(garray), dimension(1) :: gene2

  integer,intent(in) :: clen;
  integer :: out1;
  integer :: inttest;

  genespool = [garray('#',0,1),garray('X',0,1),garray('U-',1,0), &
         garray('+',2,-1),garray('-',2,-1),garray('*',2,-1), &
         garray('/',2,-1),garray('^',2,-1) ]

  gene2 = [garray('s',0,0) ]  

  out1 = clen;
  inttest = newgene(2); 

  contains

  function newgene(stackdepth) result(out2)
  integer, intent(in) :: stackdepth;
  integer :: out2;
  logical :: done;  
  integer :: ind;
  real    :: rnd1;
  character*2, dimension(:), allocatable:: answer2;
  character*2 :: answer;

 answer = 'ye'
 out2=0;
 allocate(answer2(1)); 
!  gene=0;
!  gene = stackdepth;

  done = .FALSE.

  do while (done .EQV. .FALSE.)
    call random_number(rnd1);
    ind = nint(rnd1*size(genespool));  
    if (genespool(ind)%stackdepth <= stackdepth) then
          done = .True.
    end if         
  end do

  ! Generate output
  print*, "genespool(ind)  ", genespool(ind);    
  print*, "gene 2          ", gene2;
 gene2=genespool(ind)
  print*, "new gene 2      ",gene2;
  print*, "new gene2.gene     ",gene2%gene;
  answer2=gene2%gene;

  print*, "test 2 ", answer;
  if ( gene2(1)%gene == '#' ) then
    call random_number(rnd1);
  !  gene2%gene = nint(rnd1*5);   !<------ problem (convert integer to string integer)
  endif  
  return;      
  end function newgene 
end function newchromosome

program testing1
! ------ unit declaration ----------------------------------------------
use iso_fortran_env
implicit none
! ----------------------------------------------------------------------
! ------ variable declaration ------------------------------------------
integer                 :: chromlen;
integer                 :: newchromosome;
integer                 :: test;

  chromlen = 35; 
  test = 0;
  test=int(newChromosome(chromlen));
  print*, "newChromosome is ", test;
 flush( output_unit )

 end program testing1

我添加了一些虚拟变量,例如“answer2”,仅用于调试目的。我用箭头标记了我在 FORTRAN 中的代码由于 Matlab 动态类型声明而导致麻烦的地方。在 FORTRAN 中,不可能有一个既是字符又是双精度(实数)的变量。在 FORTRAN 中,我不能像在 Matlab 中那样拥有 U- 和 -11,因为在 FORTRAN 中将gene2 类型声明为字符。 Matlab 是灵活的,FORTRAN 是严格的。在 FORTRAN 中,如何让gene2.gene 接受“真实类型”-11 而不会导致错误?有没有更好的方法为异构数组声明进行类型声明,例如 %ptr 或 class(*)?

【问题讨论】:

  • 您有一些 Fortran 代码可以讨论吗? Fortran 是静态类型语言,但可能存在一些多态性 (class(*))。但这在这里可能没有帮助。需要确定的是 Fortran 代码。它可能只是一个XY problem
  • 我添加了 fortran 代码解决方案。由于发生动态变量的matlab代码行的性质,我在卡住的地方用箭头标记了。也就是说,它既可以是字符,也可以是双精度。
  • 请注意,您的语法很奇怪。您不需要那些分号 (;)。 Matlab不需要,Fortran也不需要,这点和Matlab差不多。
  • 那么函数newgenenewchromosome返回的最终答案或结果应该是什么?一个数字还是一个字符串?你不只需要整数到字符串的转换吗? stackoverflow.com/questions/1262695/…我没有看到要在任何地方设置的函数结果。
  • 好吧,我不知道fortran中分号的原因。但是,如果您不想在输出窗口中看到每个变量的输出,matlab 确实需要它。

标签: arrays dynamic types casting fortran


【解决方案1】:

嗯,我想我终于理解了你的代码了。而且,如果我这样做了,您想要的是让组件 gene%gene 能够在需要时显示字符或数字。

不过,您绝对不需要/不想模拟动态类型或任何困难的东西。您可以将组件维护为字符类型,如果需要存储整数,则将其转换为文本。在 Fortran 中,将其他类型转换为字符是使用您习惯的相同 I/O 语句完成的,但您传递的是字符变量而不是单元号。像这样:

write(gene2%gene, '(i0)') int(rnd1 * 5);

此语句会将传递的表达式的整数值写入字符组件。在这种情况下,(i0) 格式将使用数字所需的最小空间。如果你需要存储一个实变量而不是一个整数,使用相同的原则;但是您可能需要增加字符组件的长度并使用不同的格式,可能是(g0)


尽管这在技术上解决了您的问题,但我还是以一种更“Fortran-ish”的方式编写了您的 Matlab 程序的一个端口。您可以将其作为练习来学习一些您可能不熟悉的语言概念和结构。

将功能包装到模块中:

module genetics
  implicit none

  ! use a constant, so it will be easier to refactor when needed
  integer, parameter :: g_charlen = 2

  type gene
    character(g_charlen) :: gene
    integer :: depth
    integer :: delta
  end type

  ! initializing in a data statement looks nicer in this case
  type(gene) :: pool(8)
  data pool%gene  / '#', 'U-', 'Rs',  '+',  '-',  '*',  '/',  '^'/
  data pool%depth /   0,    0,    1,    2,    2,    2,    2,    2/
  data pool%delta /   1,    1,    0,   -1,   -1,   -1,   -1,   -1/

  ! or whatever implementation you may have
  type chromosome
    character(g_charlen) :: gene
    integer :: stack
  end type

contains

  ! there is no need for nested procedures in this case
  function new_gene(depth) result(out)
    integer, intent(in) :: depth
    type(gene) :: out
    real :: rnd

    associate(filtered => pack(pool, pool%depth <= depth))
      if(size(filtered) < 1) error stop 'there is no suitable gene in the pool'
      call random_number(rnd)
      out = filtered(int(rnd * size(filtered)) + 1)
    end associate
    if(out%gene == '#') then
      call random_number(rnd)
      write(out%gene, '(i0)') int(rnd * 5) ! <- here is the line
    end if
  end

  ! or whatever implementation you may have
  function new_chromosome(clen) result(out)
    integer, intent(in) :: clen
    type(chromosome), allocatable :: out(:)
    type(gene) :: g
    integer :: i, depth
    real :: rnd
    character(g_charlen) :: gch

    allocate(out(0))
    depth = 0
    i = 1
    do while(i <= clen .or. depth /= 1)
      g = new_gene(depth)
      depth = depth + g%delta
      out = [out, chromosome(g%gene, depth)]
      i = i + 1
      if(g%gene == 'X') then
        call random_number(rnd)
        if(rnd >= 0.5) cycle
        call random_number(rnd)
        write(gch, '(i0)') int(rnd * 3) + 2;
        out = [out, chromosome(gch, depth + 1), chromosome('^', depth - 1)]
      end if
    end do
  end
end

您可以使用以下代码测试代码:

program test
  use :: genetics
  implicit none

  type(chromosome), allocatable :: c1(:)
  integer :: i

  call random_seed
  c1 = new_chromosome(10)
  do i = 1, size(c1)
    print *, c1(i)
  end do
end

一个可能的输出是:

 1            1
 U-           2
 *            1
 U-           2
 1            3
 2            4
 -            3
 U-           4
 U-           5
 ^            4
 /            3
 Rs           3
 -            2
 0            3
 -            2
 ^            1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-10
    • 1970-01-01
    • 2015-07-19
    • 2015-05-05
    • 1970-01-01
    相关资源
    最近更新 更多