How to get a script to give a value to an input prompt? - matlab

I have a collection of smaller scripts foo1, foo2, etc. and a script master.m that runs them all, like this:
% master.m
run foo1
run foo2
Let's say foo1 calls for input somewhere by saying a = input('Gimme a number\n');.
I thought that if I put the value(s) I wanted on new lines after the run command that they would be entered as input, but they don't. I've also tried enclosing them as a string, i.e. '5'. That doesn't work either.
Is their another function I should use? I looked at the help file for input, but there's no output function. Presumably there's something like write or writetostdio somewhere.
How do I give user input to a script that is being called by another script without touching the keyboard? Can I put the values I want to input in the master.m file?
EDIT:
Because there's some confusion, I'll try to clear it up.
The scripts foo1 and foo2 will NOT be passing values back and forth. Every script will be run independently. Instead, I'm trying to test a program for a range of user behaviours (which are responses to prompts via input in foo1). These are normally typed on the keyboard, but I want my master.m file to tell foo1 what the user inputs are.
Sorry if this is confusing, but hopefully that clears it up.

Modifying existing code to accommodate both manual input and testing inputs is trivial:
function foo1(niterations)
if nargin == 0
niterations = round(input('How many iterations? '));
end
for ii = 1:numel(niterations)
% Run the thing
fprintf('Running some random program with %d iterations! Yay!\n', niterations(ii));
end
end
Using this approach we can do:
>> foo1
How many iterations? 2
Running some random program with 2 iterations! Yay!
or
>> foo1(2)
Running some random program with 2 iterations! Yay!
or
>> foo1([1, 3, 5, 7, 9])
Running some random program with 1 iterations! Yay!
Running some random program with 3 iterations! Yay!
Running some random program with 5 iterations! Yay!
Running some random program with 7 iterations! Yay!
Running some random program with 9 iterations! Yay!
This is far more logical than trying to pipe things from text files, use evalin to poof things into workspaces, or whatever automagical approach is required to accommodate using scripts in this fashion.

Ok, this is a bit ugly... but might be a work-around if for some reason foo1.m etc. have to remain as scripts.
The idea is to replace each instance of input with a newly defined function myInput which checks if a variable PROMPT_VALUE has been set in the base work-space; and returns that if so, and otherwise passes through to the built-in input. For example:
% myInput.m
function [ valueOut ] = myInput( promptString )
W = evalin('caller','whos'); %or 'base'
doesPVexist = ismember('PROMPT_VALUE',[W(:).name]);
if doesPVexist
valueOut = evalin('caller', 'PROMPT_VALUE');
else
valueOut = input(promptString);
end
end
Assuming we have the following sub-scripts:
% foo1.m
a = myInput('Number to double: ');
disp(2*a);
% foo2.m
b = myInput('Number to halve: ');
disp(b/2);
We can test the approach as follows:
% master.m
clearvars;
PROMPT_VALUE=5;
run foo1.m;
PROMPT_VALUE=3;
run foo2.m
If you run this as-is it will take the PROMPT_VALUE as inputs to each of the subscripts (returning 10, and 1.5). If those lines are commented out it will look for input from the user.

Related

How to write a single Octave script with function definitions compatible with Matlab scripts?

If I write this:
clc
clear
close all
format long
fprintf( 1, 'Starting...\n' )
function results = do_thing()
results = 1;
end
results = do_thing()
And run it with Octave, it works correctly:
Starting...
results = 1
But if I try to run it with Matlab 2017b, it throws this error:
Error: File: testfile.m Line: 13 Column: 1
Function definitions in a script must appear at the end of the file.
Move all statements after the "do_thing" function definition to before the first local function
definition.
Then, if I fix the error as follows:
clc
clear
close all
format long
fprintf( 1, 'Starting...\n' )
results = do_thing()
function results = do_thing()
results = 1;
end
It works correctly on Matlab:
Starting...
results =
1
But now, it stopped working with Octave:
Starting...
error: 'do_thing' undefined near line 8 column 11
error: called from
testfile at line 8 column 9
This problem was explained on this question: Run octave script file containing a function definition
How to fix it without having to create a separate and exclusive file for the function do_thing()?
Is this issue fixed on some newer version of Matlab as 2019a?
The answer is in the comments, but for the sake of clarity:
% in file `do_thing.m`
function results = do_thing()
results = 1;
end
% in your script file
clc; clear; close all; format long;
fprintf( 1, 'Starting...\n' );
results = do_thing();
Accompanying explanatory rant:
The canonical and safest way to define functions is to define them in their own file, and make this file accessible in octave / matlab's path.
Octave has supported 'dynamic' function definitions (i.e. in the context of a script or the command-line) since practically forever. However, for the purposes of compatibility, since matlab did not support this, most people did not use it, and quite sensibly relied on the canonical way instead.
Matlab has recently finally introduced dynamic function definitions too, but has opted to implement them explicitly in a way that breaks compatibility with octave, as you describe above. (rant: this may be a coincidence and an earnest design decision, but I do note that it also happens to go against prior matlab conventions regarding nested functions, which were allowed to be defined anywhere within their enclosing scope).
In a sense, nothing has changed. Matlab was incompatible with advanced octave functionality, and now that it has introduced its own implementation of this functionality, it is still incompatible. This is a blessing in disguise. Why? Because, if you want intercompatible code, you should rely on the canonical form and good programming practices instead of littering your scripts with dynamic functions, which is what you should be doing anyway.
Octave's implementation of local functions in scripts is different from Matlab's. Octave requires that local functions in scripts be defined before their use. But Matlab requires that local functions in scripts all be defined at the end of the file.
So you can use local functions in scripts on both applications, but you can't write a script that will work on both. So just use functions if you want code that will work on both Matlab and Octave.
Examples:
Functions at end
disp('Hello world')
foo(42);
function foo(x)
disp(x);
end
In Matlab R2019a:
>> myscript
Hello world
42
In Octave 5.1.0:
octave:1> myscript
Hello world
error: 'foo' undefined near line 2 column 1
error: called from
myscript at line 2 column 1
Functions before use
disp('Hello world')
function foo(x)
disp(x);
end
foo(42);
In Matlab R2019a:
>> myscript
Error: File: myscript.m Line: 7 Column: 1
Function definitions in a script must appear at the end of the file.
Move all statements after the "foo" function definition to before the first local function definition.
In Octave 5.1.0:
octave:2> myscript
Hello world
42
How it works
Note that technically the functions here in Octave are not "local functions", but "command-line functions". Instead of defining a function that is local to the script, they define global functions that come into existence when the function statement is evaluated.
The following code works on both Matlab and Octave:
if exist('do_nothing') == 0
disp('function not yet defined, run script again')
else
do_nothing
end
%====
function results = do_nothing()
results = 1;
end
When run on octave, the first attempt exits with the message, but subsequent attempts succeed. On Matlab, it works the first time. While this works on both platforms, it is less than ideal, since it requires that much of the script code be placed inside an "if" statement block.

run script command in Matlab

I am running a script in another directory.
Assume I have the following code:
arr = [10;20;30];
run(script); % script= path to the script file + scriptfile.mat ..
x = arr(2);
It gave me the following error:
Undefined function 'arr' for input arguments of type 'double'.
After debugging the code, I found that run(script) .. run the script and then clear all variables .. such as arr.
Is there any way to make run command doesn't clear all variables..
Edit: the following is the original code..
xValues =[2;4;6];
yValues =[10;15;20;30;40];
for var1 =1:size(xValues,1)
results =[];
for var2 =1: size(yValues,1)
run(strcat('C:\Users\as\Desktop\study',num2str(xValues(var1)),'folder\',num2str(yValues(var2)),'folder\file1.m'));
results(var2,1) = yValues(var2);
end
end
Thanks,
Here is an example, erase clear command in your script file:
testing.m
arr = [10;20;30];
run('ScriptFile.m')
x = arr(2);
ScriptFile.m
disp('Hello World');
Command Window
Hello World
After the implementation x holds number 20.
It is clear all inside your script doing the mess I believe.
As for how to avoid it:
Simply remove it. This is generally the easiest and best solution.
Write file to the disk, run script, load from disk. You need a hardcoded file name.
Create "data_holding_function" that has persistent cell array, you load your data there and then restore it after script. You can make the function perform both loading (when you have some input) and unloading (when you don't).

Matlab / Octave - trouble getting started with functions, is there a function main equivalent?

I'm trying to get started with Matlab / Octave and having a difficult time figuring how to organize a program into functions. Currently I'm trying to write a simple program that adds two numbers together and displays the result, with the adding being done by a function. I would have figured this would have worked:
% test.m
close all;
clear all;
num1 = 2;
num2 = 2;
result = myAdd(num1, num2);
disp(result); % this should display 4 ??
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function retval = myAdd(var1, var2)
retval = var1 + var2;
end
Running the above with Octave 4.0.0, I get the following errors:
error: 'myAdd' undefined near line 7 column 10
error: called from
test at line 7 column 8
I have tried also putting the function first and the test part second, and also putting the function in a separate file and having a main.m file in the same directory call the myAdd function, all result in errors.
So here are my questions:
-Does Matlab / Octave have a main equivalent ??
-How does the interpreter know where to start? Does it automatically go to the first line in the program, or is there a certain function name you can use to make it start with that function as function main() is in C/C++ ??
-In a Python program of significant size, my usual practice is to organize things as follows:
# some_python_program.py
import abc
import xyz
###################################################################################################
def main():
# stuff to get program started here
# end main
###################################################################################################
def function1():
# specific function here
# end function
###################################################################################################
def function2():
# specific function here
# end function
###################################################################################################
if __name__ == "__main__":
main()
Is there a way to do the equivalent in Matlab/Octave ??
If somebody could provide some direction as to a main equivalent and/or how to organize functions in Matlab/Octave please advise, thanks.
Matlab/Octave can be a bit confusing in this way if you're coming from a language like python. In order to define a function (without using anonymous functions), you need to create a separate file with the name of that function, which can then be called using the command line.
For example, you would like to create a function called myadd. You should create a file named myadd.m whose contents will be:
function out = myadd(a,b)
out = a+b;
end
Then, as long as your file is on your path (save it to your MATLAB folder or put it in your current working directory), you can call it from the Command Window as follows:
>> myadd(5,6)
ans =
11
Only one function will be made publicly available per file (the one whose name matches the file name). However, you can still define multiple functions per file if you plan to use only that function. For example, if you have a file named foo.m, you can do the following:
function out = foo(a,b)
out = fun(a,b);
end
function out = fun(a,b)
out = a * b;
end
This will allow you to call foo(5,6) from the Command Window, but fun(5,6) will result in an error: Undefined function or variable 'fun'.
Read more about local functions and nested functions.
Hope this is helpful!

Control flow within an eval function in Matlab

If I include a continue as a parameter of an eval() instruction, it does not work as expected. For example, when executing the following code:
listParam = {'a','b','c'};
a = 17;
b = NaN;
c = 4;
for ii=1:numel(listParam),
eval(['if isnan(',listParam{ii},'), continue; end']);
disp(['The parameter ', listParam{ii}, ' is not a NaN.']);
end
It will prompt the error:
Error: A CONTINUE may only be used within a FOR or WHILE loop.
Anybody knows why?
Note: I know that I should avoid eval() and the previous example could be refactored in a much better coding; but I found a weird behaviour and I am curious what is happening.
The expression you pass to eval must be a valid matlab expression on it's own, any surrounding code is not considered. This means each continue must be surrounded by a loop. Either put the surrounding for within your eval or put the continue outside.
As #Daniel has pointed out, eval is called by the script, while it is not directly controlled by the for loop. You can think it as: the continue in eval would move the program counter to the head of the code inside eval, but not that of the for loop; this of course would fail, as Matlab does not allow jumping between lines.
A continue can only appear directly inside a for or while loop. However, you can hack the code like this:
for ii=1:numel(listParam),
eval(['if isnan(',listParam{ii},'), x=1; else, x=0; end']);
if x
continue;
end
disp(['The parameter ', listParam{ii}, ' is not a NaN.']);
end
Strangely, x happens to appear in the script's stack. However, this is far from a good piece of code. Never use this method.
Edit: about the "control" scope of eval.
I'm not talking about the variable scope / workspace of eval. Hints can be found in several documentations like this and this. In short, eval uses the "current" workspace.
However, I found the following things interesting:
Running continue directly in eval
for ii = 1:2
eval('continue')
ii+10
end
This simply fails, as shown in the question. The error is Error: A CONTINUE may only be used within a FOR or WHILE loop. which means the continue inside eval cannot find any loop (the for loop).
Calling a separate script in a for loop
for ii = 1:2
foo
ii+10
end
while script foo.m is
ii
continue
First of all, in foo.m Mlint gives a red-line warning, which usually indicates an error that can stop the code from running, saying that CONTINUE is only valid in a FOR or WHILE loop. But pressing F5 on foo.m does not have any problem - in fact running a single continue anywhere does not crash the code.
Running the main script gives output
ii =
1
ii =
2
>>
....so foo.m catches the for loop?
eval('foo') - I really don't understand Matlab
for ii = 1:2
eval('foo')
ii+10
end
The result surprised me a bit.
ii =
1
ans =
11
ii =
2
ans =
12
>>
Thought: eval runs the code in an independent control flow, but shares its workspace with the current one. It is (something but not exactly) like an isolated world model, in which (here in Matlab) different pieces of code can interact with the same set of variables, but cannot interact with each other in the sense of control flow.
Unfortunately, I was unable to find any existing resources as reference to prove this idea.
This does not change my solution: in any case, try to avoid using eval.

How can I suppress the output of a command in octave?

In Octave I can suppress or hide the output of an instruction adding a semicolon to the end of a line:
octave:1> exp([0 1])
ans = [ 1.0000 2.7183 ]
octave:2> exp([0 1]);
octave:3>
Now, how can I suppress the output if the function displays text (e.g. using disp() or print()) before returning its value? In other words, I want to be able to do this:
disp("Starting...");
% hide text the may get displayed after this point
% ...
% show all text again after this point
disp("Done!");
You can modify the PAGER variable (which is now a function) to redirect standard output. On Unix systems, you can redirect it to /dev/null. On Windows, I tried simply redirecting to a Python program that does nothing, and it works decently. (Basically, any program that ignores the input will do)
PAGER('/dev/null');
page_screen_output(1);
page_output_immediately(1);
You can just change it back after you're done. And maybe encapsulate this whole procedure in a function.
oldpager = PAGER('/dev/null');
oldpso = page_screen_output(1);
oldpoi = page_output_immediately(1);
% Call function here
PAGER(oldpager);
page_screen_output(oldpso);
page_output_immediately(oldpoi);
You can also simply run your scripts non-interactively, and redirect the output normally.
octave script.m > /dev/null
A quick hack of your problem and maybe not even worth mentioning is overloading the disp function like so:
function disp(x)
end
Then the original disp function is not called but yours instead in which no output is generated.
I also tried to somehow redirect stdout of octave, but unsuccessful. I hope that this dirty solution maybe will suffice in your situation^^
It's a very old question, but still, I've encountered the same problem and here is the trick that can help. One can use evalc to wrap a problematic function call. E.g. you have a code:
[a, b] = verbose_func(x,y);
Now you can do it:
evalc('[a, b] = verbose_func(x,y)');
and make it silent.
Funny, but it even works with other eval inside. I mean we can have:
code_str = '[a, b] = verbose_func(x,y)';
eval(code_str);
which is verbose. Now:
code_str = '[a, b] = verbose_func(x,y)';
evalc('eval(code_str)');
and this is not.