I have problem using the results of a subroutine in the main program. I wrote this code:
Program RK4
implicit none
real k1,k2,k3,k4,h,t,R
integer i,n
real a
read*,n,h
t=0
R=0
Do i=1,n
call Scale_Factor(h,n,t,a)
k1=h*(1/a(t))
k2=h*(1/a(t+h/2.0))
k3=h*(1/a(t+h/2.0))
k4=h*(1/a(t+h))
t=t+h
R=R+(k1+2*k2+2*k3+k4)*(1/6.0)
write(*,*)t,R
End Do
end program
!-----------------------------------------
SUBROUTINE Scale_Factor(h,n,t,a)
implicit none
real t,a,k1,k2,k3,k4,h,g
integer i,n
t=0
a=0.001
Do i=1,n
k1=h*g(a)
k2=h*g(a+k1/2.0)
k3=h*g(a+k2/2.0)
k4=h*g(a+k3)
t=t+h
a=a+(k1+2*k2+2*k3+k4)*(1/6.0)
write(*,*)t,a
END DO
END SUBROUTINE
!-------------------------
FUNCTION g(a)
implicit none
real a,g
g=sqrt((1.0/a)+(1.0/a**2))
END FUNCTION
The subroutine solves a differential equation and produces a for each t. I need to call the result of the subroutine in the main program and use a(t) in the main program. I wanted to define a(t) as an array but since t is real, I could not do it. Can anyone help me?
You have a system
R'(t)=f(a(t))
a'(t)=g(a(t))
that is semi-coupled. To integrate both functions together, use a coupled RK4 method of the principal form
rk4step(R,a,h)
k1a = h*g(a)
k1R = h*f(a)
k2a = h*g(a+k1a/2)
k2R = h*f(a+k1a/2)
k3a = h*g(a+k2a/2)
k3R = h*f(a+k2a/2)
k4a = h*g(a+k3a)
k4R = h*f(a+k3a)
a += (k1a+2*k2a+2*k3a+k4a)/6
R += (k1R+2*k2R+2*k3R+k4R)/6
return R,a
The better approach is to use vector-valued states and functions to avoid repetitions of similar steps.
Related
I have experience in python but am new to IDL. I am trying to write a function that will return two bins. I want to use the min function to get my bin edges. My issue is that I am trying to use the min_subscript argument to denote each bin edge, and I can't figure out how to do this in a for loop. I want to write my code so that each loop has 2 different min_subscript variables (the two edges of the bin), and these variables are written into their own arrays. Here is my code:
FUNCTION DBIN, radius, data, wbin, radbin, databin
FOR i = 0, N_ELEMENTS(radius)-1 DO BEGIN
l = lonarr(N_ELEMENTS(radius))
m = lonarr(N_ELEMENTS(radius))
junk1 = min(abs(radius - radius[i]), l[i])
junk2 = min(abs(radius - (radius[i] + wbin)), m[i])
radbin = lonarr(N_ELEMENTS(radius))
radbin[i] = radius[l[i]:m[i]]
databin = lonarr(N_ELEMENTS(data))
databin[i] = total(data[l[i]:m[i]])
ENDFOR
END
wbin is the desired bin width. The junk variables only exist for the purpose of getting the min_subscripts at those locations. The min_subscripts are the l[i]'s and the m[i]'s.
I appreciate any help!!
The min_subscript argument is trying to pass a value back to you, so you must pass a "named variable" to it. Named variables have pass by reference behavior. So you have to do it in two steps, something like:
junk1 = min(abs(radius - radius[i]), li)
l[i] = li
Above, li is a named variable, so it can receive and pass back the value. Then you can put it in your storage array.
I know this is a simple question, but for some reason I can't find a straight answer that works no matter where I look.
Basically, I have 4 values that were found in one m file, and I want to run them through a separate m file and retrieve the output from it.
I tried something like these, but none worked:
result = generate(nrow,ncol,a,b);
function result = generate(nrow,ncol,a,b);
result = #generate(nrow,ncol,a,b);
The final value in the m file "generate" is called result, and I'm trying to carry that across to my initial m file.
Any advice as to what I'm doing wrong would be greatly appreciated! Please and thank you
if your file generate.m defines a function it should have itself the following structure (which takes into account the fact that you have four returned values)
function [ret1 ret2 ret3 ret4] = generate(nrow,ncol,a,b)
.... % # Some processing of yours
ret1 = ... ; % # Returned values are eventually set
ret2 = ... ;
ret3 = ... ;
ret4 = ... ;
end
The function should be called (e.g. in your main script) as
[ret1 ret2 ret3 ret4] = generate(nrow,ncol,a,b);
now you have the variables ret1,ret2,ret3,ret4 available in the caller scope.
Be aware that the file generate.m must be in the current matlab PATH.
I just started learning Haskell, but the absence of loops is infinitely frustrating right now. I figured out how to write loops for functions. My problem, however, is that I want to output some results while iterating the loop. It seems that I have to use debug to perform this simple task.
So right now I would just appreciate an example of how to print out a string 10 times in the main structure.
In other words, I want to do this 10 times:
main = do
putStrLn "a string"
Thanks. I feel this will be very illuminating for my task.
You could define a recursive function that prints "a string" n times (n being the parameter of the function), like this:
printStringNTimes 0 = return ()
printStringNTimes n =
do
putStrLn "a string"
printStringNTimes (n-1)
main = printStringNTimes 10
A somewhat more general approach would be to define a function that repeats any IO action n times:
repeatNTimes 0 _ = return ()
repeatNTimes n action =
do
action
repeatNTimes (n-1) action
main = repeatNTimes 10 (putStrLn "a string")
The above function already exists in Control.Monad under the name replicateM_.
Well Haskell's IO is a bit tricky when you're just starting out since it's based on monads.
Your problem though has a simple solution:
main = replicateM_ 10 $ putStrLn "a string"
This is using the combinator replicateM_ from Control.Monad
It has lots of useful functions for composing and executing monadic actions.
I am also a beginner of Haskell, and I have a solution that is less elegant and yet is pragmatically useful.
main = do
putStr result
where
string = "a string"
result = concat [string ++ "\n" | i <- [1,2..10]]
So here, we have defined a list, the elements of which are the strings that you want to print out followed by a new line character.
I think the most imperative looking form of doing a for loop is:
for list action = mapM_ action list
main :: IO Int
main = do
for [0..10] (\ i -> do
print(i^2)
)
return 0
This actually looks pretty much like C code to me.
Doing something like to this allows you to loop a specific function, making it more reusable (instead of writing it out for each new thing you want to loop).
loop :: Int -> (IO()) -> IO()
loop 0 _ = return ()
loop n f =
do
f
loop (n - 1) f
Examples:
main = do
loop 5 (do
putStr "hello "
putStrLn "there")
main = do
loop 3 (do
loop 4 (putStrLn "Hi")
putStrLn ""
)
my solution:
n = 10
doSomething () = putStrLn "a string"
main = sequence (replicate n (doSomething()))
sequence: sequentially solve each IO a in a list
replicate n ele: build a list which repeats ele for n times, like take n (repeat ele)
I'm developing a simulator of sorts as a hobby project. The specific function i'm having trouble with takes a row from a matrix and supplies to a function every 50'th millisecond, but I'm a novice with Matlab scripting and need some help.
Each time the timer clicks, the next row in the matrix should be supplied to the function "simulate_datapoint()". Simulate_datapoint() takes the row, performs some calculation magic and updates a complex "track" object in the tracks array.
Is this a completely backwards way of trying to solve this problem or am I close to a working solution? Any help would be greatly appreciated.
Here's what I have right now that doesn't work:
function simulate_data(data)
if ~ismatrix(data)
error('Input must be a matrix.')
end
tracks = tracks_init(); % create an array of 64 Track objects.
data_size = size(data,1); % number of rows in data.
i = 0;
running = 1;
t = timer('StartDelay', 1, 'Period', 0.05, 'TasksToExecute', data_size, ...
'ExecutionMode', 'fixedRate');
t.StopFcn = 'running = 0;';
t.TimerFcn = 'i = i+1; simulate_datapoint(tracks, data(i,:));';
disp('Starting timer.')
start(t);
while(running==1)
% do nothing, wait for timer to finish.
end
delete(t);
disp('Execution complete.')
end
You're very close to a working prototype. A few notes.
1) Your string specified MATLAB functions for the timerFn and stopFn don't share the same memory address, so the variable "i" is meaningless and not shared across them
2) Use waitfor(myTimer) to wait... for the timer.
The following code should get you started, where I used "nested functions" which do share scope with the calling function, so they know about and share variables with the calling scope:
function simulate
iterCount = 0;
running = true;
t = timer('StartDelay', 1, 'Period', 0.05, 'TasksToExecute', 10, ...
'ExecutionMode', 'fixedRate');
t.StopFcn = #(source,event)myStopFn;
t.TimerFcn = #(source,event)myTimerFn;
disp('Starting timer.')
start(t);
waitfor(t);
delete(t);
disp('Execution complete.')
% These are NESTED functions, they have access to variables in the
% calling function's (simulate's) scope, like "iterCount"
% See: http://www.mathworks.com/help/matlab/matlab_prog/nested-functions.html
function myStopFn
running = false;
end
function myTimerFn
iterCount = iterCount + 1;
disp(iterCount);
end
end
I'm trying to optimize some code here, and wrote two different simple subroutines that will subtract one vector from another. I pass a pair of vectors to these subroutines and the subtraction is then performed. The first subroutine uses an intermediary variable to store the result whereas the second one does an inline operation using the '-=' operator. The full code is located at the bottom of this question.
When I use purely real numbers, the program works fine and there are no issues. However, if I am using complex operands, then the original vectors (the ones originally passed to the subroutines) are modified! Why does this program work fine for purely real numbers but do this sort of data modification when using complex numbers?
Note my process:
Generate random vectors (either real or complex depending on the commented out code)
Print the main vectors to the screen
Perform the first subroutine subtraction (using the third variable intermediary within the subroutine)
Print the main vectors to the screen again to prove that they have not changed, no matter the use of real or complex vectors
Perform the second subroutine subtraction (using the inline computation method)
Print the main vectors to the screen again, showing that #main_v1 has changed when using complex vectors, but will not change when using real vectors (#main_v2 is unaffected)
Print the final answers to the subtraction, which are always the correct answers, regardless of real or complex vectors
The issue arises because in the case of the second subroutine (which is quite a bit faster), I don't want the #main_v1 vector changed. I need that vector to do further calculations down the road, so I need it to stay the same.
Any idea on how to fix this, or what I'm doing wrong? My entire code is below, and should be functional. I've been using the CLI syntax shown below to run the program. I choose 5 just to keep everything easy for me to read.
c:\> bench.pl 5 REAL
or
c:\> bench.pl 5 IMAG
#!/usr/local/bin/perl
# when debugging: add -w option above
#
use strict;
use warnings;
use Benchmark qw (:all);
use Math::Complex;
use Math::Trig;
use Time::HiRes qw (gettimeofday);
system('cls');
my $dimension = $ARGV[0];
my $type = $ARGV[1];
if(!$dimension || !$type){
print "bench.pl <n> <REAL | IMAG>\n";
print " <n> indicates the dimension of the vector to generate\n";
print " <REAL | IMAG> dictates to use real or complex vectors\n";
exit(0);
}
my #main_v1;
my #main_v2;
my #vector_sum1;
my #vector_sum2;
for($a=1;$a<=$dimension;$a++){
my $r1 = sprintf("%.0f", 9*rand)+1;
my $r2 = sprintf("%.0f", 9*rand)+1;
my $i1 = sprintf("%.0f", 9*rand)+1;
my $i2 = sprintf("%.0f", 9*rand)+1;
if(uc($type) eq "IMAG"){
# Using complex vectors has the issue
$main_v1[$a] = cplx($r1,$i1);
$main_v2[$a] = cplx($r2,$i2);
}elsif(uc($type) eq "REAL"){
# Using real vectors shows no issue
$main_v1[$a] = $r1;
$main_v2[$a] = $r2;
}else {
print "bench.pl <n> <REAL | IMAG>\n";
print " <n> indicates the dimension of the vector to generate\n";
print " <REAL | IMAG> dictates to use real or complex vectors\n";
exit(0);
}
}
# cmpthese(-5, {
# v1 => sub {#vector_sum1 = vector_subtract(\#main_v1, \#main_v2)},
# v2 => sub {#vector_sum2 = vector_subtract_v2(\#main_v1, \#main_v2)},
# });
# print "\n";
print "main vectors as defined initially\n";
print_vector_matlab(#main_v1);
print_vector_matlab(#main_v2);
print "\n";
#vector_sum1 = vector_subtract(\#main_v1, \#main_v2);
print "main vectors after the subtraction using 3rd variable\n";
print_vector_matlab(#main_v1);
print_vector_matlab(#main_v2);
print "\n";
#vector_sum2 = vector_subtract_v2(\#main_v1, \#main_v2);
print "main vectors after the inline subtraction\n";
print_vector_matlab(#main_v1);
print_vector_matlab(#main_v2);
print "\n";
print "subtracted vectors from both subroutines\n";
print_vector_matlab(#vector_sum1);
print_vector_matlab(#vector_sum2);
sub vector_subtract {
# subroutine to subtract one [n x 1] vector from another
# result = vector1 - vector2
#
my #vector1 = #{$_[0]};
my #vector2 = #{$_[1]};
my #result;
my $row = 0;
my $dim1 = #vector1 - 1;
my $dim2 = #vector2 - 1;
if($dim1 != $dim2){
syswrite STDOUT, "ERROR: attempting to subtract vectors of mismatched dimensions\n";
exit;
}
for($row=1;$row<=$dim1;$row++){$result[$row] = $vector1[$row] - $vector2[$row]}
return(#result);
}
sub vector_subtract_v2 {
# subroutine to subtract one [n x 1] vector from another
# implements the inline subtraction method for alleged speedup
# result = vector1 - vector2
#
my #vector1 = #{$_[0]};
my #vector2 = #{$_[1]};
my $row = 0;
my $dim1 = #vector1 - 1;
my $dim2 = #vector2 - 1;
if($dim1 != $dim2){
syswrite STDOUT, "ERROR: attempting to subtract vectors of mismatched dimensions\n";
exit;
}
for($row=1;$row<=$dim1;$row++){$vector1[$row] -= $vector2[$row]} # subtract inline
return(#vector1);
}
sub print_vector_matlab { # for use with outputting square matrices only
my (#junk) = (#_);
my $dimension = #junk - 1;
print "V=[";
for($b=1;$b<=$dimension;$b++){
# $temp_real = sprintf("%.3f", Re($junk[$b][$c]));
# $temp_imag = sprintf("%.3f", Im($junk[$b][$c]));
# $temp_cplx = cplx($temp_real,$temp_imag);
print "$junk[$b];";
# print "$temp_cplx,";
}
print "];\n";
}
I've even tried modifying the second subroutine so that it has the following lines, and it STILL alters the #main_v1 vector when using complex numbers...I am completely confused as to what's going on.
#result = #vector1;
for($row=1;$row<=$dim1;$row++){$result[$row] -= $vector2[$row]}
return(#result);
and I've tried this too...still modifies #main_V1 with complex numbers
for($row-1;$row<=$dim1;$row++){$result[$row] = $vector1[$row]}
for($row=1;$row<=$dim1;$row++){$result[$row] -= $vector2[$row]}
return(#result);
Upgrade Math::Complex to at least version 1.57. As the changelog explains, one of the changes in that version was:
Add copy constructor and arrange for it to be called appropriately, problem found by David Madore and Alexandr Ciornii.
In Perl, an object is a blessed reference; so an array of Math::Complexes is an array of references. This is not true of real numbers, which are just ordinary scalars.
If you change this:
$vector1[$row] -= $vector2[$row]
to this:
$vector1[$row] = $vector1[$row] - $vector2[$row]
you'll be good to go: that will set $vector1[$row] to refer to a new object, rather than modifying the existing one.