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,

On Mon, Nov 12, 2007 at 10:30:06AM +0900, Bil K. 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
  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’))

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

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

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

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

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

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

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

Please riff a better Ruby answer…

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

James Edward G. 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

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 K. 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_valuev_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 K. 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:

James Edward G. 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

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

Later,

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

James Edward G. 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

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

Sure can. Try it out.

James Edward G. II

James Edward G. II wrote:

On Nov 12, 2007, at 8:10 AM, Bil K. 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’ 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,

Aaron P. 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,

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

James Edward G. II wrote:

On Nov 12, 2007, at 8:10 AM, Bil K. 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 G. II

James Edward G. 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,

James Edward G. 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,

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

is sufficient because of your

  next if us.empty? or vs.empty?

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 G. II