comp.lang.fortran challenge

B

Bil Kleb

Bil said:
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,
 
M

M. Edward (Ed) Borasky

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. :)
 
A

Aaron Patterson

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! :-D
 
A

Aaron Patterson

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

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

James Edward Gray II

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 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__
====================
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
 
B

Bil Kleb

James said:
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,
 
B

Bil Kleb

Aaron said:
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... ;)

Later,
 
J

James Edward Gray II

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
 
B

Bil Kleb

James said:
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.
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,
 
J

James Edward Gray II

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?

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
 
B

Bil Kleb

James said:
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,
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,123
Latest member
Layne6498
Top