Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I want to create a newcommand \vecty to create a vector which will take 3 parameters like \vecty{1}{2}{3} and this should display as $\hat{i}+2\hat{j}+3\hat{k}$ and if I give \vecty{0}{3}{-3} then it should show $3\hat{j}-3\hat{k}.

I am using LaTeX. I would appreciate any guidance that comes how to get through it. I did try \ifthenelse code but it turned to be quite hefty. You can have a look at the code.

But I know that the code is too bad. Hence wanted to understand if there are other ways to implement it. Kindly help I m a newbie.

share|improve this question
    
in my opinion, it is more beautiful if a vector is made in bold face rather than with a hat (in printed version). –  Please don't touch Sep 27 '12 at 7:48
    
Would you please specify the range of numbers that can appear in the arguments? Do you expect decimal numbers and fractions, for instance? –  egreg Sep 27 '12 at 10:06
    
Yes there are going to be fractional numbers that might be passed as 1/2, 2/3 or 3.4 etc. Also there might be values like \vecty{0}{1}{0} which i expect to get me just \hat{j} –  nichas Sep 27 '12 at 11:05
add comment

3 Answers

Here is one way you can do this:

enter image description here

Notes:

  • This updated version properly handles integer and decimal coefficients of zero (+0, 0.00) or one with leading + signs, spurious spaces, and non-numbers in the input (as per the second section of the table above).
  • newtoggle from the etoolbox package was used as I prefer that syntax versus the \newif syntax. But if you don't want to include an additional package it should be pretty straightforward to adapt this to use \newif or some other conditional methods. This toggle keeps track if a term has already been printed to ensure that a leading positive term does not have a +.
  • I used the xstring package to determine if the number had a leading minus sign, or was zero, but again, this could easily be adapted to not use that package as well.
  • I would recommend that you use this macro as $\vecty$ - that is you explicitly enter math mode, as used below. If however, you wish to use it without having to enter math mode as per your original question, you should not surround it with dollar signs, but instead use

    \ensuremath{\LeadingSign #1 #2}

    as then it will be useable inside or outside of math mode. To repeat, I am not recommending this as this is clearly a math mode macro. Please see When not to use \ensuremath for math macro? if you disagree.

Further Enhancements:

  • Should \vecty be required to typeset more than three components, one can easily add additional calls to \Display{}{} for each of the components -- no other changes should be required. Note that this has not been tested.
  • This does not remove the coefficient equal to one, nor eliminate the term if the coefficient is zero for the case of non numerical input: For example \vecty{-1x}{+0y}{1z}.
  • Could use pgf math to do numerical processing of the input so that basic expressions in the coefficients could be simplified. The pgf math functions could also be used to convert -0.5 to -\frac{1}{2}.

Code:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xstring}
\usepackage{etoolbox}

\newcommand*{\LeadingSign}{}%
\newcommand*{\CleanedCoefficientWithNoSpaces}{}% coefficient with spaces & "+" removed
\newcommand*{\CleanedCoefficient}{}% digit "1" removed if coefficient is 1, or -1

\newcommand*{\Display}[2]{%
    % #1 = coefficient (may not be a number)
    % #2 = paramater
    %
    % ---------------------------------------------------------------- Clean input
    \StrSubstitute{#1}{ }{}[\CoefficientWithNoSpaces]% eliminate any spaces
    \IfBeginWith{\CoefficientWithNoSpaces}{+}{% eliminate any leading + sign
        \StrSubstitute{\CoefficientWithNoSpaces}{+}{}[\CleanedCoefficientWithNoSpaces]%
    }{%
        \renewcommand*{\CleanedCoefficientWithNoSpaces}{\CoefficientWithNoSpaces}%
    }%
    % ---------------------------------------------------------------- 1, +1, -1 issue
    % If the coefficient is 1, +1, or -1, we need to supress the digit
    \IfEq{\CleanedCoefficientWithNoSpaces}{1}{% coefficient equivalent to +1
        \renewcommand*{\CleanedCoefficient}{}%  eliminate the digit
    }{%
        \IfEq{\CoefficientWithNoSpaces}{-1}{% coefficient equivalent to -1
            \renewcommand*{\CleanedCoefficient}{-}% eliminate the digit (leave sign)
        }{%
            % This is the case of the coefficient not being +1, or -1, so use as is
            \renewcommand*{\CleanedCoefficient}{\CleanedCoefficientWithNoSpaces}% 
            %
            % The issue of the leading sign is dealt with below.  Could have moved the
            % leading sign handling here (with some adjustments above), but that would 
            % have made the code a little harder to read. There is already enough  
            % illiteracy in the world. :-)
        }%
    }%
    % ----------------------------------------------------------------  Leading sign
    % We don't want a + sign for the very first term printed.
    \renewcommand*{\LeadingSign}{}% initalize
    \IfBeginWith{\CleanedCoefficientWithNoSpaces}{-}{%
        % use default empty value (sign is part of number)
        % or for the case of -1, this has already been set above
    }{%
        \iftoggle{PrintedFirstTerm}{%
            \renewcommand*{\LeadingSign}{+}%
        }{%
            % Since a leading term of this vector has not yet been printed 
            % we do not add a + sign
        }%
    }%
    % ----------------------------------------------------------------  Print
    \IfEq{#1}{0}{}{%
        \LeadingSign \CleanedCoefficient #2%
        \global\toggletrue{PrintedFirstTerm}% so next term can have + sign
    }%
}%

\newtoggle{PrintedFirstTerm}
\newcommand*{\vecty}[3]{%
    \global\togglefalse{PrintedFirstTerm}%
    \Display{#1}{\hat{i}} %
    \Display{#2}{\hat{j}}%
    \Display{#3}{\hat{k}}%
    \iftoggle{PrintedFirstTerm}{}{\mathbf{0}}% could also use \vec{0} here
}%

\begin{document}
\[
\begin{array}{ll}
  \verb|$\vecty{1}{2}{3}$|        & \vecty{1}{2}{3}  \\
  \verb|$\vecty{0}{3}{-3}$|       & \vecty{0}{3}{-3} \\
  \verb|$\vecty{0}{0}{0}$|        & \vecty{0}{0}{0}  \\
  \verb|$\vecty{0}{0}{3}$|        & \vecty{0}{0}{3}  \\
  \verb|$\vecty{1}{2}{0}$|        & \vecty{1}{2}{0}  \\
  \verb|$\vecty{0}{3}{3}$|        & \vecty{0}{3}{3}  \\
  \verb|$\vecty{3}{0}{0}$|        & \vecty{3}{0}{0}  \\
  \verb|$\vecty{-1}{1}{0}$|       & \vecty{-1}{1}{0} \\[1.5ex]
  \verb|$\vecty{- 1}{ - 1}{+ 0}$| & \vecty{- 1}{ - 1}{+ 0}\\
  \verb|$\vecty{-1}{-1.0}{+2}$|   & \vecty{-1}{-1.0}{+2}\\
  \verb|$\vecty{-0.0}{+0}{0}$|    & \vecty{-0.0}{+0}{0}\\
  \verb|$\vecty{-0}{+x}{y}$|      & \vecty{-0}{+x}{y}\\
  \verb|$\vecty{-x}{+7}{y}$|      & \vecty{-x}{+7}{y}\\
\end{array}
\]
\end{document}
share|improve this answer
    
A null vector must be written as \vec{0} to differentiate it from the scalar one 0. What do you think? –  Please don't touch Sep 27 '12 at 8:19
    
@ガベージコレクタ: Good point. Have added a comment in the code, and changed the 0 vector to be in bold. –  Peter Grill Sep 27 '12 at 8:28
    
This is great but what I was trying was something more than you have given me (I appreciate) If I pass the parameter \vecty{1}{-1}{2} then I expect the outcome to look something like this \hat{i}-\hat{j}+2\hat{k}. I dont want the 1 or -1 to be there in the outcome beside i cap and j cap –  nichas Sep 27 '12 at 11:12
    
@nichas: Have corrected that case. –  Peter Grill Sep 27 '12 at 20:29
add comment

\ifcase catches the 0 \or 1 \else and \ifnum >0 the +/- case

\documentclass[12pt]{article}
\newcommand\vecty[3]{\ensuremath{%
  \edef\TEMPnum{#1#2#3}\def\TEMPzero{000}%  
  \ifx\TEMPnum\TEMPzero 0\else%  to make Gonzalo happy :-)
    \ifcase#1 \or\hat{i}\ifnum#2>0 +\fi
    \else#1\hat{i}\ifnum#2>0 +\fi\fi
    \ifcase#2 \or\hat{j}\ifnum#3>0 +\fi
    \else#2\hat{j} \ifnum#3>0 +\fi\fi
    \ifcase#3 \or\hat{k}
    \else#3\hat{k}\fi%
  \fi}}

\begin{document}

\vecty{1}{2}{3} and this should display as $\hat{i}+2\hat{j}+3\hat{k}$

\vecty{0}{3}{-3} then it should show $3\hat{j}-3\hat{k}$

\vecty{0}{0}{0} then it should show $0$

\end{document}

enter image description here

share|improve this answer
    
Perhaps a little modification so that \vecty{0}{0}{0} produces 0? –  Gonzalo Medina Sep 27 '12 at 7:22
    
Refering to the question it should do nothing for \vecty{0}{0}{0}, which my solution already does. However, it can easily be modified if you want a 0 –  Herbert Sep 27 '12 at 7:27
    
Do as you please; I only mentioned to handle that case as a suggestion based on the mathematical meaning. –  Gonzalo Medina Sep 27 '12 at 7:31
1  
@ガベージコレクタ Yes you can, just use \hat{\imath} and \hat{\jmath}. –  tohecz Sep 27 '12 at 8:07
2  
@ガベージコレクタ: I suppose that it is not too difficult for you to replace 0 by \vec{0} ... –  Herbert Sep 27 '12 at 9:16
show 7 more comments

Here's a solution using lua, it doesn't offer any advantages over Peter's solution above, so I'm simply posting it for comparisons sake (and because I wanted to get some practice with lua). Compile with lualatex.

\documentclass{article}
\usepackage{luacode}

%\begin{filecontents*}{vectyfunc.lua}
\begin{luacode*}
function vecty_make (x,y,z)
    local basis = {"\\hat{\\mathrm{i}}","\\hat{j}","\\hat{k}"}
    local coeffs = {x,y,z}
    local str = ""
    local num = 0
    for i = 1,3 do
        coeffs[i] = string.gsub(coeffs[i]," ","")
        -- if not empty
        if coeffs[i]~="" then
            -- and if not zero
            if tonumber(coeffs[i])~=0 then
                num = num + 1
                -- then put a + if missing a sign
                if tonumber(coeffs[i]) == 1 then coeffs[i] = "" end
                if tonumber(coeffs[i]) == -1 then coeffs[i] = "-" end
                if string.find(coeffs[i],"^[+-]") == nil then
                        coeffs[i]="+"..coeffs[i]
                end
            -- and append to str
            str = str..coeffs[i]..basis[i]
            end
        end
    end

    if num == 0 then
        tex.sprint("\\vec{0}")
    else
        -- remove first sign if a +
        if string.sub(str,1,1) == "+" then
            str = string.sub(str,2)
        end
    tex.sprint(str)
    end

end
\end{luacode*}
%\end{filecontents*}

%\directlua{dofile("vectyfunc.lua")}

\newcommand{\vecty}[3]{
        \directlua{vecty_make("#1","#2","#3")}
}

\begin{document}
\[
\begin{array}{ll}
\verb|$\vecty{1}{2}{3}$|        & \vecty{1}{2}{3}  \\
\verb|$\vecty{0}{3}{-3}$|       & \vecty{0}{3}{-3} \\
\verb|$\vecty{0}{0}{0}$|        & \vecty{0}{0}{0}  \\
\verb|$\vecty{0}{0}{3}$|        & \vecty{0}{0}{3}  \\
\verb|$\vecty{1}{2}{0}$|        & \vecty{1}{2}{0}  \\
\verb|$\vecty{0}{3}{3}$|        & \vecty{0}{3}{3}  \\
\verb|$\vecty{3}{0}{0}$|        & \vecty{3}{0}{0}  \\
\verb|$\vecty{-1}{1}{0}$|       & \vecty{-1}{1}{0} \\
\verb|$\vecty{- 1}{ - 1}{+ 0}$| & \vecty{- 1}{ - 1}{+ 0}\\
\verb|$\vecty{-1}{-1.0}{+2}$|      & \vecty{-1}{-1.0}{+2}\\
\verb|$\vecty{-0.0}{+0}{0}$|      & \vecty{-0.0}{+0}{0}\\
\verb|$\vecty{-0}{+x}{y}$|      & \vecty{-0}{+x}{y}\\
\verb|$\vecty{-x}{+7}{y}$|      & \vecty{-x}{+7}{y}\\
\end{array}
\]
\end{document}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.