Comp.lang.fortran challenge

Having Ruby fun with the comp.lang.fortran folks:

  http://tinyurl.com/38o8ex
  http://tinyurl.com/2pw22q

Please riff a better Ruby answer...

Regards,

···

--
Bil Kleb
http://fun3d.larc.nasa.gov

Bil Kleb wrote:

Having Ruby fun with the comp.lang.fortran folks:

http://tinyurl.com/38o8ex
http://tinyurl.com/2pw22q

Please riff a better Ruby answer...

My current answer to the challenge...

require 'scanf'
require 'open-uri'

def write_uvs(u,v)
    u = u[0...v.size] # limit U's size to V's
    puts u, v # write Us & Vs
    u.zip(v).each do |u_line,v_line| # zip Us & Vs together
      u_value, v_value = u_line.scanf("%14c %f").last, v_line.scanf("%14c %f").last
      printf "#{u_line[/.*=/].sub(/U/,'UV')} %7.3f\n", u_value*v_value # write UV
    end
end

u, v = , # initialize U & V arrays

open 'http://home.earthlink.net/~dave_gemini/demo.in' do |iostream|
    iostream.each_line do |line|
      case line
      when /^time/ then # found time delimiter
        write_uvs(u,v) and u.clear and v.clear
        puts "\n" + line.sub( /time\s*:/, 'for time' ) + "\n" # write time
      when /^U/ then # add to U array
        u << line
      when /^V/ then # add to V array
        v << line unless v.size == u.size # limit V's size to U's
      end
    end
end

write_uvs(u,v)

Later,

···

--
Bil Kleb
http://tufte-latex.googlecode.com

I'm confused as to why the data needs to be retained in memory..... But
here is a little something I put together. It does maintain the
datastructures in memory before calculating the results.

  require 'open-uri'
  
  class PhilCollins
    attr_writer :time
    alias :time :time=
  
    def initialize(io)
      @uv_by_t = Hash.new { |h,t| h[t] = Hash.new { |n,a| n[a] = } }
      @time = 10
      io.each_line do |line|
        line.gsub!(/:\s*(\d+)[^\d]*$/, '(\1)')
        line.gsub!(/([UV])\s*\(([^)]*)\)\s=\s(.*)$/, '\1[[\2]] << \3')
        line.downcase!
        begin; instance_eval(line); rescue Exception; end
      end
    end
  
    def u; @uv_by_t[@time]; end
    alias :v :u
  
    def inspect
      @uv_by_t.sort_by { |t,v| t }.map { |t,v|
        "for time: #{t}\n" +
        v.map { |args,vals|
          "UV(#{args.join(',')}) = #{vals[0] * vals[1]}" if vals.length == 2
        }.compact.join("\n")
      }.join("\n\n")
    end
  end
  
  p PhilCollins.new(open('http://home.earthlink.net/~dave_gemini/demo.in&#39;\))

PS, don't try this script at home! It's very dangerous! :smiley:

···

On Mon, Nov 12, 2007 at 10:30:06AM +0900, Bil Kleb wrote:

Having Ruby fun with the comp.lang.fortran folks:

http://tinyurl.com/38o8ex
http://tinyurl.com/2pw22q

Please riff a better Ruby answer...

--
Aaron Patterson
http://tenderlovemaking.com/

That little challenge made me wish for some Ruby 1.9 elements, like an ordered Hash.

James Edward Gray II

#!/usr/bin/env ruby -wKU

us, vs = Array.new, Array.new
DATA.each do |line|
   if line =~ /^time\s*:\s*(.+?)\s*$/
     [us, vs].each { |array| array.clear }
     puts "for time #{$1}"
     puts
   elsif line =~ /^([UV])(\s*\([^)]+\))\s*=\s*([\d.]+)\s*$/
     ($1 == "U" ? us : vs) << [$2, $3.to_f]
     puts line
   end

   if line =~ /^\s*$/ or DATA.eof?
     next if us.empty? or vs.empty?
     us.each do |sig, value|
       next unless v = vs.assoc(sig)
       puts "UV%s = %.2f" % [sig, value * v.last]
     end
     puts
   end
end

__END__

···

On Nov 11, 2007, at 7:30 PM, Bil Kleb wrote:

Having Ruby fun with the comp.lang.fortran folks:

http://tinyurl.com/38o8ex
http://tinyurl.com/2pw22q

Please riff a better Ruby answer...

====================
time: 00 minutes

velocity U in m/s

U ( 1, 1, 1) = 12.34
U ( 1, 1, 2) = 10.00
U ( 1, 1, 3) = 11.01
U ( 1, 2, 1) = 10.05
U ( 1, 2, 2) = 12.40
U ( 1, 2, 3) = 11.20
U ( 1, 3, 1) = 12.80
U ( 1, 3, 2) = 10.30
U ( 1, 3, 3) = 11.25

velocity V in m/s

V ( 1, 1, 1) = 11.40
V ( 1, 1, 2) = 12.00
V ( 1, 1, 3) = 13.50
V ( 1, 2, 1) = 11.00
V ( 1, 2, 2) = 11.70
V ( 1, 2, 3) = 11.25
V ( 1, 3, 1) = 11.50
V ( 1, 3, 2) = 10.60
V ( 1, 3, 3) = 11.23

====================
time : 30 minutes

velocity U in m/s

U ( 1, 1, 1) = 13.30
U ( 1, 1, 2) = 11.00
U ( 1, 1, 3) = 11.30
U ( 1, 2, 1) = 10.00
U ( 1, 2, 2) = 12.30
U ( 1, 2, 3) = 10.10
U ( 1, 3, 1) = 10.90
U ( 1, 3, 2) = 11.40
U ( 1, 3, 3) = 11.75

velocity V in m/s

V ( 1, 1, 1) = 12.40
V ( 1, 1, 2) = 11.00
V ( 1, 1, 3) = 11.60
V ( 1, 2, 1) = 11.20
V ( 1, 2, 2) = 11.90
V ( 1, 2, 3) = 11.35
V ( 1, 3, 1) = 12.50
V ( 1, 3, 2) = 11.60
V ( 1, 3, 3) = 13.20

Bil Kleb wrote:
[snip]

Yeah ... it wasn't clear to me than anyone had set what the limits were. If the code only has to deal with little chunks of data like

···

====================
time: 00 minutes

velocity U in m/s

U ( 1, 1, 1) = 12.34
U ( 1, 1, 2) = 10.00
U ( 1, 1, 3) = 11.01
U ( 1, 2, 1) = 10.05
U ( 1, 2, 2) = 12.40
U ( 1, 2, 3) = 11.20
U ( 1, 3, 1) = 12.80
U ( 1, 3, 2) = 10.30
U ( 1, 3, 3) = 11.25

velocity V in m/s

V ( 1, 1, 1) = 11.40
V ( 1, 1, 2) = 12.00
V ( 1, 1, 3) = 13.50
V ( 1, 2, 1) = 11.00
V ( 1, 2, 2) = 11.70
V ( 1, 2, 3) = 11.25
V ( 1, 3, 1) = 11.50
V ( 1, 3, 2) = 10.60
V ( 1, 3, 3) = 11.23

"little" being defined as nine U values and nine V values per time step, I don't see why one would do this in awk or Ruby when Fortran could do it. It's been about 18 years since I read or wrote any Fortran, but I didn't know awk at the time and so, presented with a problem like this, would have coded it in Fortran. I think the real challenge here in any language is to scale this up to way more than nine U and V values per time step -- something where you'd actually need some kind of efficient data structure. :slight_smile:

Oops. @time should be nil, but that shouldn't change the output....

···

On Mon, Nov 12, 2007 at 12:20:32PM +0900, Aaron Patterson wrote:

On Mon, Nov 12, 2007 at 10:30:06AM +0900, Bil Kleb wrote:
> Having Ruby fun with the comp.lang.fortran folks:
>
> http://tinyurl.com/38o8ex
> http://tinyurl.com/2pw22q
>
> Please riff a better Ruby answer...

I'm confused as to why the data needs to be retained in memory..... But
here is a little something I put together. It does maintain the
datastructures in memory before calculating the results.

  require 'open-uri'
  
  class PhilCollins
    attr_writer :time
    alias :time :time=
  
    def initialize(io)
      @uv_by_t = Hash.new { |h,t| h[t] = Hash.new { |n,a| n[a] = } }
      @time = 10

--
Aaron Patterson
http://tenderlovemaking.com/

James Edward Gray II wrote:

That little challenge made me wish for some Ruby 1.9 elements, like an ordered Hash.

Nice; can it handle the

  require 'open-uri'
  open 'http://home.earthlink.net/~dave_gemini/demo.in&#39;

data which has some unequal (u,v) sets? -- see the 19th
post in http://tinyurl.com/2pw22q

Later,

···

--
Bil

Aaron Patterson wrote:

I'm confused as to why the data needs to be retained in memory..... But
here is a little something I put together. It does maintain the
datastructures in memory before calculating the results.

No prize for Phil, he didn't tweak the time output line
or echo the U and V lines... :wink:

Later,

···

--
Bil Kleb
http://fun3d.larc.nasa.gov

Sure can. Try it out.

James Edward Gray II

···

On Nov 12, 2007, at 8:10 AM, Bil Kleb wrote:

James Edward Gray II wrote:

That little challenge made me wish for some Ruby 1.9 elements, like an ordered Hash.

Nice; can it handle the

require 'open-uri'
open 'http://home.earthlink.net/~dave_gemini/demo.in&#39;

data which has some unequal (u,v) sets?

James Edward Gray II wrote:

Nice; can it handle the data which has some unequal (u,v) sets?

Sure can. Try it out.

Sure enough. Why didn't you use a case? E.g.,

require 'open-uri'
us, vs = Array.new, Array.new
open 'http://home.earthlink.net/~dave_gemini/demo.in&#39; do |ios|
   ios.each_line do |line|
     case line
     when /time\s*:\s*(.*)/ then # output time
       puts "for time #{$1}"
       puts
     when /(U|V)(.*?)\s*=\s*([\d.]+)/ then # capture and echo U & V lines
       ($1 == "U" ? us : vs) << [ $2, $3.to_f ]
       puts line
     when /^\s*$/, ios.eof? then # output UVs and reset U & V arrays
       next if us.empty? or vs.empty?
       us.each do |coordinates, u|
         next unless v = vs.assoc(coordinates)
         puts "UV%s = %7.3f" % [coordinates, u * v.last]
       end
       puts
       [us, vs].each { |array| array.clear }
     end
   end
end

Later,

···

On Nov 12, 2007, at 8:10 AM, Bil Kleb wrote:

--
Bil Kleb
http://fun3d.larc.nasa.gov

James Edward Gray II wrote:

Nice; can it handle the data which has some unequal (u,v) sets?

Sure can. Try it out.

Sure enough. Why didn't you use a case? E.g.,

Well, I don't think it's the same. Is it?

    case line

    when /^\s*$/, ios.eof? then # output UVs and reset U & V arrays

Won't that check if the contents of line match the Regexp or if the contents of line match the true/false returned by eof?(). That's not what we want.

James Edward Gray II

···

On Nov 12, 2007, at 7:11 PM, Bil Kleb wrote:

On Nov 12, 2007, at 8:10 AM, Bil Kleb wrote:

James Edward Gray II wrote:

Well, I don't think it's the same. Is it?

Seems to work at least according to the anti-pattern of
testing: guru scans output.

    when /^\s*$/, ios.eof? then # output UVs and reset U & V arrays

Won't that check if the contents of line match the Regexp or if the contents of line match the true/false returned by eof?(). That's not what we want.

You're of course correct, but apparently the ios.eof? isn't
needed anyway... In fact, simply

     else # output UVs and reset U & V arrays

is sufficient because of your

       next if us.empty? or vs.empty?

Later,

···

--
Bil Kleb
http://fun3d.larc.nasa.gov

That's true only if the document contains a blank line after all of the data. My pasted content from the original email did not, so that didn't seem a safe assumption to make.

James Edward Gray II

···

On Nov 12, 2007, at 9:05 PM, Bil Kleb wrote:

James Edward Gray II wrote:

    when /^\s*$/, ios.eof? then # output UVs and reset U & V arrays

Won't that check if the contents of line match the Regexp or if the contents of line match the true/false returned by eof?(). That's not what we want.

You're of course correct, but apparently the ios.eof? isn't
needed anyway... In fact, simply

    else # output UVs and reset U & V arrays

is sufficient because of your

      next if us.empty? or vs.empty?

James Edward Gray II wrote:

That's true only if the document contains a blank line after all of the data. My pasted content from the original email did not, so that didn't seem a safe assumption to make.

Roger.

Later,

···

--
Bil Kleb
http://fun3d.larc.nasa.gov