Smalltalk weird printing error - smalltalk

In order to "pad" a number I'm printing so that it's always a fixed number of characters, I'm making a padding string based off how many integers and in the given number:
pad := ' '.
(freqVal < 10) ifTrue: [ pad := ' ' ].
((freqVal < 100) & (freqVal > 9)) ifTrue: [ pad := ' ' ].
((freqVal < 1000) & (freqVal > 99)) ifTrue: [ pad := ' ' ].
stdout<<pad<<freqVal<<<<nl
However, the printed result always makes the variable pad into a letter instead of spaces like I'm assigning its value to. If I add pad displayNl before the last line it prints out a letter for some reason instead of just spaces.
Any ideas why this might be occurring?

I don't know Gnu-Smalltalk in particular. Surely there are some handy String methods or formatters you could reuse for this purpose though. My advice would be to first convert the number into a String and then format it with blank-padding. That way you will avoid type conversion Problems which you've experienced
new String method (preferrably an existing one in your ST Distribution):
withLeading: aCharacter size: anInteger
(anInteger < self size) ifTrue: [^self copyFrom: 1 to: anInteger].
^((self species new: anInteger - self size) atAllPut: aCharacter ), self
usage example
9 asString withLeading: ($ ) size: 10 "result ' 9'"
10 asString withLeading: ($ ) size: 10 "result ' 10'"
999 asString withLeading: ($ ) size: 10 "result ' 999'"

Related

Using forall() predicate in minizinc as assignment statement without 'constraint'

I have a Minizinc program for generating the optimal charge/discharge schedule for a grid-connected battery, given a set of prices by time-interval.
My program works (sort of; subject to some caveats), but my question is about two 'constraint' statements which are really just assignment statements:
constraint forall(t in 2..T)(MW_SETPOINT[t-1] - SALE[t] = MW_SETPOINT[t]);
constraint forall(t in 1..T)(PROFIT[t] = SALE[t] * PRICE[t]);
These just mean Energy SALES is the delta in MW_SETPOINT from t-1 to 1, and PROFIT is SALE * PRICE for each interval. So it seems counterintuitive to me to declare them as 'constraints'. But I've been unable to formulate them as assignment statements without throwing syntax errors.
Question:
Is there a more idiomatic way to declare such assignment statements for an array which is a function of other params/variables? Or is making assignments for arrays in constraints the recommended/idiomatic way to do it in Minizinc?
Full program for context:
% PARAMS
int: MW_CAPACITY = 10;
array[int] of float: PRICE;
% DERIVED PARAMS
int: STARTING_MW = MW_CAPACITY div 2; % integer division
int: T = length(PRICE);
% DECISION VARIABLE - MW SETPOINT EACH INTERVAL
array[1..T] of var 0..MW_CAPACITY: MW_SETPOINT;
% DERIVED/INTERMEDIATE VARIABLES
array[1..T] of var -1*MW_CAPACITY..MW_CAPACITY: SALE;
array[1..T] of var float: PROFIT;
var float: NET_PROFIT = sum(PROFIT);
% CONSTRAINTS
%% If start at 5MW, and sell 5 first interval, setpoint for first interval is 0
constraint MW_SETPOINT[1] = STARTING_MW - SALE[1];
%% End where you started; opt schedule from arbitrage means no net MW over time
constraint MW_SETPOINT[T] = STARTING_MW;
%% these are really justassignment statements for SALE & PROFIT
constraint forall(t in 2..T)(MW_SETPOINT[t-1] - SALE[t] = MW_SETPOINT[t]);
constraint forall(t in 1..T)(PROFIT[t] = SALE[t] * PRICE[t]);
% OBJECTIVE: MAXIMIZE REVENUE
solve maximize NET_PROFIT;
output["DAILY_PROFIT: " ++ show(NET_PROFIT) ++
"\nMW SETPOINTS: " ++ show(MW_SETPOINT) ++
"\nMW SALES: " ++ show(SALE) ++
"\n$/MW PRICES: " ++ show(PRICE)++
"\nPROFITS: " ++ show(PROFIT)
];
It can be run with
minizinc opt_sched_hindsight.mzn --solver org.minizinc.mip.coin-bc -D "PRICE = [29.835, 29.310470000000002, 28.575059999999997, 28.02416, 28.800690000000003, 32.41052, 34.38542, 29.512390000000003, 25.66587, 25.0499, 26.555529999999997, 28.149440000000002, 30.216509999999996, 32.32415, 31.406609999999997, 36.77642, 41.94735, 51.235209999999995, 50.68137, 64.54481, 48.235170000000004, 40.27663, 34.93675, 31.10404];"```
You can play with Array Comprehensions: (quote from the docs)
Array comprehensions have this syntax:
<array-comp> ::= "[" <expr> "|" <comp-tail> "]"
For example (with the literal equivalents on the right):
[2*i | i in 1..5] % [2, 4, 6, 8, 10]
Array comprehensions have more flexible type and inst requirements than set comprehensions (see Set Comprehensions).
Array comprehensions are allowed over a variable set with finite type,
the result is an array of optional type, with length equal to the
cardinality of the upper bound of the variable set. For example:
var set of 1..5: x;
array[int] of var opt int: y = [ i * i | i in x ];
The length of array will be 5.
Array comprehensions are allowed where the where-expression
is a var bool. Again the resulting array is of optional
type, and of length equal to that given by the generator expressions. For example:
var int x;
array[int] of var opt int: y = [ i | i in 1..10 where i != x ];
The length of the array will be 10.
The indices of an evaluated simple array comprehension are
implicitly 1..n, where n is the length of the evaluated
comprehension.
Example:
int: MW_CAPACITY = 10;
int: STARTING_MW = MW_CAPACITY div 2;
array [int] of float: PRICE = [1.0, 2.0, 3.0, 4.0];
int: T = length(PRICE);
array [1..T] of var -1*MW_CAPACITY..MW_CAPACITY: SALE;
array [1..T] of var 0..MW_CAPACITY: MW_SETPOINT = let {
int: min_i = min(index_set(PRICE));
} in
[STARTING_MW - sum([SALE[j] | j in min_i..i])
| i in index_set(PRICE)];
array [1..T] of var float: PROFIT =
[SALE[i] * PRICE[i]
| i in index_set(PRICE)];
solve satisfy;
Output:
~$ minizinc test.mzn
SALE = array1d(1..4, [-10, -5, 0, 0]);
----------
Notice that index_set(PRICE) is nothing else but 1..T and that min(index_set(PRICE)) is nothing else but 1, so one could write the above array comprehensions also as
array [1..T] of var 0..MW_CAPACITY: MW_SETPOINT =
[STARTING_MW - sum([SALE[j] | j in 1..i])
| i in 1..T];
array [1..T] of var float: PROFIT =
[SALE[i] * PRICE[i]
| i in 1..T];

Can one define a one dimensional image inline?

I would like to describe a very simple image (really a vector) of length 2, like (1,2) for the purpose of some linear algebra.
The following creates a two dimensional image with a y axis of length 1:
image a := [2,1]: {
{1, 2}
}
MatrixPrint(a)
This outputs
{
{1, 2}
}
How would I in a similar fashion output this instead?
{123,45}
Additionally, if I had image of arbitrary shape (a, b), how can I slice it to extract a one dimensional image at a value n, either along the x or y axes? (Extracting a line profile along one of the image axes)
In your example you do define a 2D image, so you get a 2D output. If the image really would be 1D, your output would be 1D, i.e.
image a := [2]: {123, 45}
MatrixPrint(a)
So your second question actually is the answer to your first: You need to do a 1D slice of the data, which you can do with the command slice1() as follows:
image a := [2,1]: {
{123, 45}
}
MatrixPrint( a.slice1(0,0,0,0,2,1) )
Note some peculiarities of the command:
The command always assume the input is 3D, so the first 3 parameters are the start-index triplet x/y/z even if it is just 2D or 1D data.
the 2nd triplet specifies the sampling of the slice. First the dimensions index (0=x) then the number of sampling steps (2) and then the stepsize (1)
Similar slice commands exist for 2D slices, 3D slices and nD Slices from nD data.
The matrixPrint command only outputs to the results window. There is no way to reroute this to some string. However, you can easily make yourself a method that would do that (albeit not very fast for big data):
string VectorPrint( image img, string FormatStr, number maxNum )
{
if ( !img.ImageIsValid() ) return "{invalid}"
if ( 1 != img.ImageGetNumDimensions() ) return "{not 1D}"
string out = "{ "
number nx = img.ImageGetDimensionSize(0)
if (( nx <= maxNum ) || ( maxNum <= 2) )
{
for( number i=0; i<min(nx,maxNum); i++)
out += Format( sum(img[0,i]), FormatStr ) + ", "
out = out.left( out.len() - 2 )
}
else
{
for( number i=0; i<maxNum-1; i++)
out += Format( sum(img[0,i]), FormatStr ) + ", "
out = out.left( out.len() - 2 ) + ", ... , "
out += Format( sum(img[0,nx-1]), FormatStr )
}
out += " }"
return out
}
image a := [10,4]: {
{1,2,3,4,5,6,7,8,9,10},
{123, 45, 12.3, -12, 55, 1.2, 9999, 89.100, 1e-10, 0},
{0,0,0,0,0,0,0,0,0,0},
{1,2,3,4,5,6,7,8,9,10}
}
// Slice 2D image to 1D image at n'th line
number n = 1
image line := a.slice1(0,n,0,0,a.ImageGetDimensionSize(0),1)
// Printout with given number format and a maximum number of entries
string fStr = "%3.1f"
number maxN = 3
Result( "\n "+VectorPrint( line, fStr, maxN ) )

Variable Width String Padding

I am being passed a string value that could begin with 0-4 decimal digits and ends with a small, but unknown, amount of non-decimal text. I need to pad the leading decimal digits out to four digits with the "0" character. If I am passed "abcd", I would return "0000abcd". If I passed "0xyz", I would return "0000xyz". And so on...
I am using the following code to detect how much padding I need to do:
int padding = 0;
int strlen = [rawString length];
NSRange rng = [rawString rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]];
if (rng.length > 0 && rng.location < 4) // Characters were found at the end.
padding = 4 - rng.location;
else if (rng.length == 0 && strlen < 4) // Only numbers were found.
padding = 4 - strlen;
Now that I can accurately determine the padding my challenge is to add the padding in an efficient manner. I could do something like the following, but it just feels inefficient to me.
for (; padding > 0; padding--)
rawString = [#"0" stringByAppendingString:rawString];
Is there a better way to add a variable amount of padding to a string like the one I described?
EDIT: I considered chopping off the numerical portion, padding it, and then adding it back, but the number of corner cases seemed to indicate that an in situ solution would be best.
Since padding is between 0 and 4, you could do this:
rawString = [[#"0000" substringFromIndex:4-padding] stringByAppendingString:rawString];
The idea is to chop off the right number of zeros from a string containing four elements.

What is the best way to enforce certain values on message arguments in smalltalk?

I'm working on a simple board game in Pharo, and I've got a method on my Board that adds objects to a cell. Cells are simply a dictionary of Points on Objects.
As part of the method, I wanted to enforce that a Point should be greater than zero, but less than the width and height of the board, in other words, it should actually be on the board. What is the best way to do this?
My current attempt looks like this:
at: aPoint put: aCell
((((aPoint x > self numberOfRows)
or: [aPoint x <= 0])
or: [aPoint y > self numberOfColumns ])
or: [aPoint y <= 0])
ifTrue: [ self error:'The point must be inside the grid.' ].
self cells at: aPoint put: aCell .
Kind of lisp-y with all those parens! But I can't use the short-circuiting or: without closing off each expression so it evaluates as a boolean and not a block (or as the or:or:or:or: message). I could use the binary operator | instead and for-go short circuiting, but that doesn't seem right.
So what is the properly Smalltalk-ish way to handle this?
Typically the or: are nested like this:
(aPoint x > self numberOfRows
or: [ aPoint x <= 0
or: [ aPoint y > self numberOfColumns
or: [ aPoint y <= 0 ] ] ])
ifTrue: [ self error: 'The point must be inside the grid.' ].
Your nesting is short-circuting but less efficient because of repeated tests of the first argument (check the bytecode to see the difference).
Alternative you can use assert: or assert:description: that is defined on Object:
self
assert: (aPoint x > self numberOfRows
or: [ aPoint x <= 0
or: [ aPoint y > self numberOfColumns
or: [ aPoint y <= 0 ] ] ])
description: 'The point must be inside the grid.'
Any time things are that heavily nested, it's time to call another method.
isValidPoint: aPoint
aPoint x > self numberOfRows ifTrue: [^ false].
aPoint x <= 0 ifTrue: [^ false].
aPoint y > self numberOfColumns ifTrue: [^ false].
aPoint y <= 0 ifTrue: [^ false].
^ true.
In general, your methods should be relatively flat. If not, time to refactor.
You can simply prefill the 'cells' dictionary with all points which is valid within the range, i.e. somewhere in initialization you put:
1 to: numberOfRows do: [:y |
1 to: numberOfCols do: [:x |
cells at: x#y put: dummy "or nil " ] ]
then your method for adding a cell at given point will look as simple as:
at: aPoint put: aCell
self cells at: aPoint ifAbsent: [ self error: 'The point must be inside the grid.' ].
self cells at: aPoint put: aCell .
There's also a helper method #between:and: , which you can use to minimize the code clutter:
((aPoint x between: 1 and: self numCols) and: [
aPoint y between: 1 and: self numRows ]) ifFalse: [ ... bummer ... ]

How to format a number with padding in Erlang

I need to pad the output of an integer to a given length.
For example, with a length of 4 digits, the output of the integer 4 is "0004" instead of "4". How can I do this in Erlang?
adding a bit of explanation to Zed's answer:
Erlang Format specification is: ~F.P.PadModC.
"~4..0B~n" translates to:
~F. = ~4. (Field width of 4)
P. = . (no Precision specified)
Pad = 0 (Pad with zeroes)
Mod = (no control sequence Modifier specified)
C = B (Control sequence B = integer in default base 10)
and ~n is new line.
io:format("~4..0B~n", [Num]).
string:right(integer_to_list(4), 4, $0).
The problem with io:format is that if your integer doesn't fit, you get asterisks:
> io:format("~4..0B~n", [1234]).
1234
> io:format("~4..0B~n", [12345]).
****
The problem with string:right is that it throws away the characters that don't fit:
> string:right(integer_to_list(1234), 4, $0).
"1234"
> string:right(integer_to_list(12345), 4, $0).
"2345"
I haven't found a library module that behaves as I would expect (i.e. print my number even if it doesn't fit into the padding), so I wrote my own formatting function:
%%------------------------------------------------------------------------------
%% #doc Format an integer with a padding of zeroes
%% #end
%%------------------------------------------------------------------------------
-spec format_with_padding(Number :: integer(),
Padding :: integer()) -> iodata().
format_with_padding(Number, Padding) when Number < 0 ->
[$- | format_with_padding(-Number, Padding - 1)];
format_with_padding(Number, Padding) ->
NumberStr = integer_to_list(Number),
ZeroesNeeded = max(Padding - length(NumberStr), 0),
[lists:duplicate(ZeroesNeeded, $0), NumberStr].
(You can use iolist_to_binary/1 to convert the result to binary, or you can use lists:flatten(io_lib:format("~s", [Result])) to convert it to a list.)
Eshell V12.0.3 (abort with ^G)
1> F = fun(Max, I)-> case Max - length(integer_to_list(I)) of X when X > 0 -> string:chars($0, X) ++ integer_to_list(I); _ -> I end end.
#Fun<erl_eval.43.40011524>
2> F(10, 22).
"0000000022"
3> F(3, 22345).
22345