Special Operators Definition in Mathematica - wolfram-mathematica

How do you define a special operator in Mathematica, for example a special type of additive or multiplicative operator? I did that in the past but I can't recall where I put the code.
I tried defining this filled small circle operator on two matrices :
A_\[FilledSmallCircle] B_ :=
Which[(MatrixQ[A] || VectorQ[A]) && (MatrixQ[B] || VectorQ[B]),
A.B, ! (MatrixQ[A] || VectorQ[A]) && (MatrixQ[B] || VectorQ[B]),
A#B, (MatrixQ[A] || VectorQ[A]) && ! (MatrixQ[B] || VectorQ[B]),
Transpose[B#Transpose[A]]];
But it does not work. What am I doing wrong?

So you are trying to make an operator with an infix action. If you compare it to the built-in infix operators +, *, **, \[CircleTimes], etc... you'' see that they are all interpreted into their FullForm: Plus, Times, NonCommutativeMultiply, CircleTimes, respectively.
You should probably try to create something similar. So start with
BigDot[A_, B_] := Which[
(MatrixQ[A] || VectorQ[A]) && (MatrixQ[B] || VectorQ[B]), A.B,
!(MatrixQ[A] || VectorQ[A]) && (MatrixQ[B] || VectorQ[B]), A#B,
(MatrixQ[A] || VectorQ[A]) && !(MatrixQ[B] || VectorQ[B]), Transpose[B#Transpose[A]],
True, HoldForm[BigDot[A, B]]];
Note that I added the last line as a catch-all for when neither A nor B are a matrix or a vector.
Then create the infix notation part. The hard way would be to make some MakeExpression and MakeBoxes definitions. The easy way is to use the NotationPackage
Needs["Notation`"]
InfixNotation[ParsedBoxWrapper["\[FilledSmallCircle]"], BigDot]

Try (just cut and paste this):
Needs["Notation`"]
Notation[ParsedBoxWrapper[
RowBox[{"A_", " ", "\[FilledSmallCircle]", " ",
"B_"}]] \[DoubleLongLeftRightArrow] ParsedBoxWrapper[
RowBox[{"Which", "[",
RowBox[{
RowBox[{
RowBox[{"(",
RowBox[{
RowBox[{"MatrixQ", "[", "A_", "]"}], "||",
RowBox[{"VectorQ", "[", "A_", "]"}]}], ")"}], "&&",
RowBox[{"(",
RowBox[{
RowBox[{"MatrixQ", "[", "B_", "]"}], "||",
RowBox[{"VectorQ", "[", "B_", "]"}]}], ")"}]}], ",",
RowBox[{"A_", " ", ".", "B_"}], ",",
RowBox[{
RowBox[{"!",
RowBox[{"(",
RowBox[{
RowBox[{"MatrixQ", "[", "A_", "]"}], "||",
RowBox[{"VectorQ", "[", "A_", "]"}]}], ")"}]}], "&&",
RowBox[{"(",
RowBox[{
RowBox[{"MatrixQ", "[", "B_", "]"}], "||",
RowBox[{"VectorQ", "[", "B_", "]"}]}], ")"}]}], ",",
RowBox[{"A_", "[", "B_", "]"}], ",",
RowBox[{
RowBox[{"(",
RowBox[{
RowBox[{"MatrixQ", "[", "A_", "]"}], "||",
RowBox[{"VectorQ", "[", "A_", "]"}]}], ")"}], "&&",
RowBox[{"!",
RowBox[{"(",
RowBox[{
RowBox[{"MatrixQ", "[", "B_", "]"}], "||",
RowBox[{"VectorQ", "[", "B_", "]"}]}], ")"}]}]}], ",",
RowBox[{"Transpose", "[",
RowBox[{"B_", "[",
RowBox[{"Transpose", "[", "A_", "]"}], "]"}], "]"}]}], "]"}]]]
Now I've entered this with the Notation palette, so actually it looks like this on screen:
(the palette inserts various boxes where necessary). It just looks horrible when I cut and paste due to the explicit string representation of everything.
EDIT: That is: type "Needs["Notation"]`, causing a palette to appear. Click on the first button, whereupon this
appears. Inside the first yellow box type A_ \[FilledSmallCircle] B_, and in the second,
Which[(MatrixQ[A_]||VectorQ[A_])&&(MatrixQ[B_]||VectorQ[B_]),A_ .B_,!(MatrixQ[A_]||VectorQ[A_])&&(MatrixQ[B_]||VectorQ[B_]),A_[B_],(MatrixQ[A_]||VectorQ[A_])&&!(MatrixQ[B_]||VectorQ[B_]),Transpose[B_[Transpose[A_]]]]
The result looks like this
and, when evaluated, defines what you want. Alternatively, after the Needs bit, just cut and paste what I gave above.

Mathematica has some operators without builtin definitions like CirclePlus and CircleTimes that you can define. I'm iPhoning now so I can't check, but I assume FilledSmallCircle is just a character and not an operator. It's less trivial to define that as an operator, but you might want to check the Notation package.

Related

.select undefined method for main:Object (NoMethodError) Ruby

Trying to create a method to remove single space elements from an array if there's a single space element next to it (no double spaces). When I run the below I get this error:
ex5.rb:5:in block in remove_double_spaces': undefined methodarray' for main:Object (NoMethodError)
Did you mean? Array
I'm guessing this is a variable scope issue? How can I call the array itself within the select method?
My logic attempted below (select all elements of the array unless it's a blank element and the next element is also a blank).
def remove_double_spaces(array)
# p array.index('w') works fine here.
array.select { |value| value unless (value == ' ') && (array(array.index(value) + 1) != ' ') }
end
remove_double_spaces([" ", " ", " ", "w", "h", "a", "t", " ", "s", " ", "m", "y", " ", " ", " ", " ", " ", "l", "i", "n", "e", " "])
You could do this instead.
array.map(&:squeeze)
To get rid of the error just replace array(array.index(value) + 1) with array[array.index(value) + 1].
However the solution will still be incorrect. The method index of an array returns the index of the first object in array such that the object is == to value. In case of duplicate elements in array there will be an error.
I'd recommend rewriting your method as
def remove_double_spaces(array)
array.join.squeeze(' ').split('')
end
remove_double_spaces([" ", " ", " ", "w", "h", "a", "t", " ", "s", " ", "m", "y", " ", " ", " ", " ", " ", "l", "i", "n", "e", " "])
# => [" ", "w", "h", "a", "t", " ", "s", " ", "m", "y", " ", "l", "i", "n", "e", " "]

gsub escaped double quote to an escaped single quote in string

I have the following input string:
string = "\"Newegg.com\" <Promo#email.newegg.com>"
I want to replace the \" with \'. I tried this:
string.gsub(/\"/) {|i| "\\'" }
# => "\\'Newegg.com\\' <Promo#email.newegg.com>"
string.gsub(/\"/,%q(\\\'))
# => "\\'Newegg.com\\' <Promo#email.newegg.com>"
In both ways, it actually has two instances of \, but I want only one. It seems to be an issue with the backslash and escaping b/c this works otherwise:
string.gsub(/\"/,%q('))
# => "'Newegg.com' <Promo#email.newegg.com>"
-- Update 1--
yes, puts does display the "correct" value
temp = string.gsub(/\"/,%q(\\\'))
# => "\\'Newegg.com\\' <Promo#email.newegg.com>"
puts temp
# >> \'Newegg.com\' <Promo#email.newegg.com>
but I want to store this exact value displayed on the last line.
Your actual string doesn't include \
puts "\"Newegg.com\" <Promo#email.newegg.com>"
> "Newegg.com" <Promo#email.newegg.com>
This will replace " with ' as you wished:
puts "\"Newegg.com\" <Promo#email.newegg.com>".gsub('"', "'")
> 'Newegg.com' <Promo#email.newegg.com>
If you really wanted \", try another escape character like:
puts "\\\"Newegg.com\\\" <Promo#email.newegg.com>"
> \"Newegg.com\" <Promo#email.newegg.com>
Same replace should work:
puts "\\\"Newegg.com\\\" <Promo#email.newegg.com>".gsub('"', "'")
> \'Newegg.com\' <Promo#email.newegg.com>
Looks like your getting a bit confused (understandably so) by the returned result.
Keep in mind that in irb, the last result is formatted using .inspect, which means that it wraps strings in double quotes, and then escapes characters (backslashes and double quotes)' that would need to be escaped in a double quoted string. This is to distinguish between strings and other values such as numbers, arrays, hashes, etc.
However, that is just the result of inspect. if you use puts to output the value, it will output it without any escaping - it is a more accurate representation of your value.The value displayed by puts is the real value, and what would be stored if you saved the value to a variable.
If you still can't tell what your string looks like, try this:
temp = string.gsub(/\"/,%q(\\\'))
temp.split('')
=> ["\\", "'", "N", "e", "w", "e", "g", "g", ".", "c", "o", "m", "\\", "'", " ", "<", "P", "r", "o", "m", "o", "#", "e", "m", "a", "i", "l", ".", "n", "e", "w", "e", "g", "g", ".", "c", "o", "m", ">"]
This explodes your string into an array of single characters, and can make it easier to see exactly what is in your string. Notice you have a \ character (displayed as "\\", but since each string is guaranteed to be exactly one character long, you know it is being displayed that way because of inspect) and a ' character at the beginning.

Ruby string scan returns different results for different string

irb(main):161:0> "Ready for your my next session?".scan(/[A-Za-z]+|\d+|. /)
=> ["Ready", "for", "your", "my", "next", "session"]
=> ["Ready", "for", "your", "my", "next", "session", "?"] #==> EXPECTED
irb(main):162:0> "yo mr. menon how are you? call at 9 a.m. \"okay\"".scan(/[A-Za-z]+|\d+|. /)
=> ["yo", "mr", ". ", "menon", "how", "are", "you", "? ", "call", "at", "9", "a", "m", ". ", "okay"]
=> ["yo", "mr", ". ", "menon", "how", "are", "you", "? ", "call", "at", "9", "a",".", "m", ".", "``", "okay", "''"] #==> EXPECTED
I am trying to use this scan(/[A-Za-z]+|\d+|. /) to tokenize the string and even the punctuations, even if there is an escaped quote in the string, \"
But it is behaving differently on different structure of a string? How to correct?
r = /
(?: # begin a non-capture group
\"? # optionally (?) match a double-quote
\p{alpha}+ # match one or more letters
\"? # optionally (?) match a double-quote
) # end non-capture group
| # or
\d+ # match one or more digits
| # or
[.,?!:;] # match a punctuation mark
/x # free-spacing regex definition mode
"yo mr. menon how are you? call at 9 a.m. \"okay\"".scan(r)
#=> ["yo", "mr", ".", "menon", "how", "are", "you", "?", "call", "at", "9",
# "a", ".", "m", ".", "\"okay\""]
puts "\"okay\""
# "okay"
The regular expression is conventionally written
/(?:\"?\p{alpha}+\"?)|\d+|[.,?!:;]/

Ruby split string and preserve separator

In Ruby, what's the easiest way to split a string in the following manner?
'abc+def' should split to ['abc', '+', 'def']
'abc\*def+eee' should split to ['abc', '\*', 'def', '+', 'eee']
'ab/cd*de+df' should split to ['ab', '/', 'cd', '*', 'de', '+', 'df']
The idea is to split the string about these symbols: ['-', '+', '*', '/'] and also save those symbols in the result at appropriate locations.
Option 1
/\b/ is a word boundary and it has zero-width, so it will not consume any characters
'abc+def'.split(/\b/)
# => ["abc", "+", "def"]
'abc*def+eee'.split(/\b/)
# => ["abc", "*", "def", "+", "eee"]
'ab/cd*de+df'.split(/\b/)
# => ["ab", "/", "cd", "*", "de", "+", "df"]
Option 2
If your string contains other word boundary characters and you only want to split on -, +, *, and /, then you can use capture groups. If a capture group is used, String#split will also include captured strings in the result. (Thanks for pointing this out #Jordan) (#Cary Swoveland sorry, I didn't see your answer when I made this edit)
'abc+def'.split /([+*\/-])/
# => ["abc", "+", "def"]
'abc*def+eee'.split /([+*\/-])/
# => ["abc", "*", "def", "+", "eee"]
'ab/cd*de+df'.split /([+*\/-])/
# => ["ab", "/", "cd", "*", "de", "+", "df"]
Option 3
Lastly, for those using a language that might not support string splitting with a capture group, you can use two lookarounds. Lookarounds are also zero-width matches, so they will not consume any characters
'abc+def'.split /(?=[+*\/-])|(?<=[+*\/-])/
# => ["abc", "+", "def"]
'abc*def+eee'.split /(?=[+*\/-])|(?<=[+*\/-])/
# => ["abc", "*", "def", "+", "eee"]
'ab/cd*de+df'.split /(?=[+*\/-])|(?<=[+*\/-])/
# => ["ab", "/", "cd", "*", "de", "+", "df"]
The idea here is to split on any character that is preceded by one of your separators, or any character that is followed by one of the separators. Let's do a little visual
ab ⍿ / ⍿ cd ⍿ * ⍿ de ⍿ + ⍿ df
The little ⍿ symbols are either preceded or followed by one of the separators. So this is where the string will get cut.
Option 4
Maybe your language doesn't have a string split function or sensible ways to interact with regular expressions. It's nice to know you don't have to sit around guessing if there's clever built-in procedures that magically solve your problems. There's almost always a way to solve your problem using basic instructions
class String
def head
self[0]
end
def tail
self[1..-1]
end
def reduce acc, &f
if empty?
acc
else
tail.reduce yield(acc, head), &f
end
end
def separate chars
res, acc = reduce [[], ''] do |(res, acc), char|
if chars.include? char
[res + [acc, char], '']
else
[res, acc + char]
end
end
res + [acc]
end
end
'abc+def'.separate %w(- + / *)
# => ["abc", "+", "def"]
'abc*def+eee'.separate %w(- + / *)
# => ["abc", "*", "def", "+", "eee"]
'ab/cd*de+df'.separate %w(- + / *)
# => ["ab", "/", "cd", "*", "de", "+", "df"]
I see this is close to part of #naomic's answer, but I'll leave it for the small differences.
splitters = ['-', '+', '*', '/']
r = /(#{ Regexp.union(splitters) })/
# => /((?-mix:\-|\+|\*|\/))/
'abc+def'.split r
#=> ["abc", "+", "def"]
"abc\*def+eee".split r
#=> ["abc", "*", "def", "+", "eee"]
'ab/cd*de+df'.split r
#=> ["ab", "/", "cd", "*", "de", "+", "df"]
Notes:
the regex places #{ Regexp.union(splitters) } in a capture group, causing String#split to include the strings that do the splitting (last sentence of the third paragraph).
the second example string must be in double quotes in order to escape *.

How do i concatinate some element of array and recreate array in ruby

I have a string. I need to split it and assign values to hash. But before assigning it, I need to modify the original array and concatenate some of its elements then recreate the array again. Please help me on how to do it in ruby.
Consider
array = ["unix", "2", "[", "ACC", "]", "STREAM", "LISTENING", "12459", "tmp/control"].
I need to concatenate "[", "ACC", "]".
Now the new Array should look like
array = ["unix", "2", "[ ACC ]", "STREAM", "LISTENING", "12459", "tmp/control"].
Please suggest.
array = ["unix", "2", "[", "ACC", "]", "STREAM", "LISTENING", "12459", "tmp/control"]
m,n = array.index('['),array.index(']')
array[m..n]=array[m..n].join(" ")
p array
# => ["unix", "2", "[ ACC ]", "STREAM", "LISTENING", "12459", "tmp/control"]
Posting this answer as 1: The accepted solution only works with one set of square brackets and 2: How often do you actually get to solve something using flip flop?
array = ["unix", "2", "[", "ACC", "]", "STREAM", "[", "some", "other", "]", "x"]
array = array.chunk{|x| (x=='['..x==']') ? true : false }
.map{|join, array| join ? array.join(' ') : array}
.flatten
p array #=> ["unix", "2", "[ ACC ]", "STREAM", "[ some other ]", "x"]

Resources