Display a linear combination

From Rosetta Code
Revision as of 01:52, 5 January 2018 by Robbie (talk | contribs) (Added D)
Display a linear combination is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.
Task

Display a finite linear combination in an infinite vector basis .

Write a function that, when given a finite list of scalars ,
creates a string representing the linear combination in an explicit format often used in mathematics, that is:

where



The output must comply to the following rules:

  •   don't show null terms, unless the whole combination is null.
e(1)     is fine,     e(1) + 0*e(3)     or     e(1) + 0     is wrong.
  •   don't show scalars when they are equal to one or minus one.
e(3)     is fine,     1*e(3)     is wrong.
  •   don't prefix by a minus sign if it follows a preceding term.   Instead you use subtraction.
e(4) - e(5)     is fine,     e(4) + -e(5)     is wrong.


Show here output for the following lists of scalars:

 1)    1,  2,  3
 2)    0,  1,  2,  3
 3)    1,  0,  3,  4
 4)    1,  2,  0
 5)    0,  0,  0
 6)    0
 7)    1,  1,  1
 8)   -1, -1, -1
 9)   -1, -2,  0, -3
10)   -1



C

Accepts vector coefficients from the command line, prints usage syntax if invoked with no arguments. This implementation can handle floating point values but displays integer values as integers. All test case results shown with invocation. A multiplication sign is not shown between a coefficient and the unit vector when a vector is written out by hand ( i.e. human readable) and is thus not shown here as well. <lang C> /*Abhishek Ghosh, 24th September 2017*/

  1. include<stdlib.h>
  2. include<stdio.h>
  3. include<math.h> /*Optional, but better if included as fabs, labs and abs functions are being used. */

int main(int argC, char* argV[]) {

int i,zeroCount= 0,firstNonZero = -1; double* vector;

if(argC == 1){ printf("Usage : %s <Vector component coefficients seperated by single space>",argV[0]); }

else{

printf("Vector for ["); for(i=1;i<argC;i++){ printf("%s,",argV[i]); } printf("\b] -> ");


vector = (double*)malloc((argC-1)*sizeof(double));

for(i=1;i<=argC;i++){ vector[i-1] = atof(argV[i]); if(vector[i-1]==0.0) zeroCount++; if(vector[i-1]!=0.0 && firstNonZero==-1) firstNonZero = i-1; }

if(zeroCount == argC){ printf("0"); }

else{ for(i=0;i<argC;i++){ if(i==firstNonZero && vector[i]==1) printf("e%d ",i+1); else if(i==firstNonZero && vector[i]==-1) printf("- e%d ",i+1); else if(i==firstNonZero && vector[i]<0 && fabs(vector[i])-abs(vector[i])>0.0) printf("- %lf e%d ",fabs(vector[i]),i+1); else if(i==firstNonZero && vector[i]<0 && fabs(vector[i])-abs(vector[i])==0.0) printf("- %ld e%d ",labs(vector[i]),i+1); else if(i==firstNonZero && vector[i]>0 && fabs(vector[i])-abs(vector[i])>0.0) printf("%lf e%d ",vector[i],i+1); else if(i==firstNonZero && vector[i]>0 && fabs(vector[i])-abs(vector[i])==0.0) printf("%ld e%d ",vector[i],i+1); else if(fabs(vector[i])==1.0 && i!=0) printf("%c e%d ",(vector[i]==-1)?'-':'+',i+1); else if(i!=0 && vector[i]!=0 && fabs(vector[i])-abs(vector[i])>0.0) printf("%c %lf e%d ",(vector[i]<0)?'-':'+',fabs(vector[i]),i+1); else if(i!=0 && vector[i]!=0 && fabs(vector[i])-abs(vector[i])==0.0) printf("%c %ld e%d ",(vector[i]<0)?'-':'+',labs(vector[i]),i+1); } } }

free(vector);

return 0; } </lang> Output:

C:\rossetaCode>vectorDisplay.exe 1 2 3
Vector for [1,2,3] -> e1 + 2 e2 + 3 e3
C:\rossetaCode>vectorDisplay.exe 0 0 0
Vector for [0,0,0] -> 0
C:\rossetaCode>vectorDisplay.exe 0 1 2 3
Vector for [0,1,2,3] -> e2 + 2 e3 + 3 e4
C:\rossetaCode>vectorDisplay.exe 1 0 3 4
Vector for [1,0,3,4] -> e1 + 3 e3 + 4 e4
C:\rossetaCode>vectorDisplay.exe 1 2 0
Vector for [1,2,0] -> e1 + 2 e2
C:\rossetaCode>vectorDisplay.exe 0 0 0
Vector for [0,0,0] -> 0
C:\rossetaCode>vectorDisplay.exe 0
Vector for [0] -> 0
C:\rossetaCode>vectorDisplay.exe 1 1 1
Vector for [1,1,1] -> e1 + e2 + e3
C:\rossetaCode>vectorDisplay.exe -1 -1 -1
Vector for [-1,-1,-1] -> - e1 - e2 - e3
C:\rossetaCode>vectorDisplay.exe -1 -2 0 -3
Vector for [-1,-2,0,-3] -> - e1 - 2 e2 - 3 e4
C:\rossetaCode>vectorDisplay.exe -1
Vector for [-1] -> - e1

D

Translation of: Kotlin

<lang D>import std.array; import std.conv; import std.format; import std.math; import std.stdio;

string linearCombo(int[] c) {

   auto sb = appender!string;
   foreach (i, n; c) {
       if (n==0) continue;
       string op;
       if (n < 0) {
           if (sb.data.empty) {
               op = "-";
           } else {
               op = " - ";
           }
       } else if (n > 0) {
           if (!sb.data.empty) {
               op = " + ";
           }
       }
       auto av = abs(n);
       string coeff;
       if (av != 1) {
           coeff = to!string(av) ~ "*";
       }
       sb.formattedWrite("%s%se(%d)", op, coeff, i+1);
   }
   if (sb.data.empty) {
       return "0";
   }
   return sb.data;

}

void main() {

   auto combos = [
       [1, 2, 3],
       [0, 1, 2, 3],
       [1, 0, 3, 4],
       [1, 2, 0],
       [0, 0, 0],
       [0],
       [1, 1, 1],
       [-1, -1, -1],
       [-1, -2, 0, -3],
       [-1],
   ];
   foreach (c; combos) {
       auto arr = c.format!"%s";
       writefln("%-15s  ->  %s", arr, linearCombo(c));
   }

}</lang>

Output:
[1, 2, 3]        ->  e(1) + 2*e(2) + 3*e(3)
[0, 1, 2, 3]     ->  e(2) + 2*e(3) + 3*e(4)
[1, 0, 3, 4]     ->  e(1) + 3*e(3) + 4*e(4)
[1, 2, 0]        ->  e(1) + 2*e(2)
[0, 0, 0]        ->  0
[0]              ->  0
[1, 1, 1]        ->  e(1) + e(2) + e(3)
[-1, -1, -1]     ->  -e(1) - e(2) - e(3)
[-1, -2, 0, -3]  ->  -e(1) - 2*e(2) - 3*e(4)
[-1]             ->  -e(1)

EchoLisp

<lang scheme>

build an html string from list of coeffs

(define (linear->html coeffs)

   (define plus #f) 
   (or* 
   (for/fold (html "") ((a coeffs) (i (in-naturals 1)))
     (unless (zero? a)
		(set! plus (if plus "+" "")))
     (string-append html

(cond ((= a 1) (format "%a e%d " plus i)) ((= a -1) (format "- e%d " i)) ((> a 0) (format "%a %d*e%d " plus a i)) ((< a 0) (format "- %d*e%d " (abs a) i)) (else ""))))

    "0"))

(define linears '((1 2 3)

  (0 1 2 3)
  (1 0 3 4)
  (1 2 0)
  (0 0 0)
  (0)
  (1 1 1)
  (-1 -1 -1)
  (-1 -2 0 -3)
  (-1)))
  

(define (task linears)

   (html-print ;; send string to stdout
   (for/string ((linear linears))
     (format "%a -> %a 
" linear (linear->html linear)))))

</lang>

Output:

(1 2 3) -> e1 + 2*e2 + 3*e3
(0 1 2 3) -> e2 + 2*e3 + 3*e4
(1 0 3 4) -> e1 + 3*e3 + 4*e4
(1 2 0) -> e1 + 2*e2
(0 0 0) -> 0
(0) -> 0
(1 1 1) -> e1 + e2 + e3
(-1 -1 -1) -> - e1 - e2 - e3
(-1 -2 0 -3) -> - e1 - 2*e2 - 3*e4
(-1) -> - e1

Elixir

Works with: Elixir version 1.3

<lang elixir>defmodule Linear_combination do

 def display(coeff) do
   Enum.with_index(coeff)
   |> Enum.map_join(fn {n,i} ->
        {m,s} = if n<0, do: {-n,"-"}, else: {n,"+"}
        case {m,i} do
          {0,_} -> ""
          {1,i} -> "#{s}e(#{i+1})"
          {n,i} -> "#{s}#{n}*e(#{i+1})"
        end
      end)
   |> String.trim_leading("+")
   |> case do
        ""  -> IO.puts "0"
        str -> IO.puts str
      end
 end

end

coeffs =

 [ [1, 2, 3],
   [0, 1, 2, 3],
   [1, 0, 3, 4],
   [1, 2, 0],
   [0, 0, 0],
   [0],
   [1, 1, 1],
   [-1, -1, -1],
   [-1, -2, 0, -3],
   [-1]
 ]

Enum.each(coeffs, &Linear_combination.display(&1))</lang>

Output:
e(1)+2*e(2)+3*e(3)
e(2)+2*e(3)+3*e(4)
e(1)+3*e(3)+4*e(4)
e(1)+2*e(2)
0
0
e(1)+e(2)+e(3)
-e(1)-e(2)-e(3)
-e(1)-2*e(2)-3*e(4)
-e(1)

J

Implementation:

<lang J>fourbanger=:3 :0

 e=. ('e(',')',~])@":&.> 1+i.#y
 firstpos=. 0< {.y-.0
 if. */0=y do. '0' else. firstpos}.;y gluedto e end.

)

gluedto=:4 :0 each

 pfx=. '+-' {~ x<0
 select. |x
   case. 0 do. 
   case. 1 do. pfx,y
   case.   do. pfx,(":|x),'*',y
 end.

)</lang>

Example use:

<lang J> fourbanger 1 2 3 e(1)+2*e(2)+3*e(3)

  fourbanger 0 1 2 3

e(2)+2*e(3)+3*e(4)

  fourbanger 1 0 3 4

e(1)+3*e(3)+4*e(4)

  fourbanger 0 0 0

0

  fourbanger 0

0

  fourbanger 1 1 1

e(1)+e(2)+e(3)

  fourbanger _1 _1 _1

-e(1)-e(2)-e(3)

  fourbanger _1 _2 0 _3

-e(1)-2*e(2)-3*e(4)

  fourbanger _1

-e(1)</lang>

Julia

<lang julia># v0.6

linearcombination(coef::Array) = join(collect("$c * e($i)" for (i, c) in enumerate(coef) if c != 0), " + ")

for c in [[1, 2, 3], [0, 1, 2, 3], [1, 0, 3, 4], [1, 2, 0], [0, 0, 0], [0], [1, 1, 1],

   [-1, -1, -1], [-1, -2, 0, -3], [-1]]
   @printf("%20s -> %s\n", c, linearcombination(c))

end</lang>

Output:
           [1, 2, 3] -> 1 * e(1) + 2 * e(2) + 3 * e(3)
        [0, 1, 2, 3] -> 1 * e(2) + 2 * e(3) + 3 * e(4)
        [1, 0, 3, 4] -> 1 * e(1) + 3 * e(3) + 4 * e(4)
           [1, 2, 0] -> 1 * e(1) + 2 * e(2)
           [0, 0, 0] -> 
                 [0] -> 
           [1, 1, 1] -> 1 * e(1) + 1 * e(2) + 1 * e(3)
        [-1, -1, -1] -> -1 * e(1) + -1 * e(2) + -1 * e(3)
     [-1, -2, 0, -3] -> -1 * e(1) + -2 * e(2) + -3 * e(4)
                [-1] -> -1 * e(1)

Kotlin

<lang scala>// version 1.1.2

fun linearCombo(c: IntArray): String {

   val sb = StringBuilder()
   for ((i, n) in c.withIndex()) {
       if (n == 0) continue
       val op = when {
           n < 0 && sb.isEmpty() -> "-"
           n < 0                 -> " - "
           n > 0 && sb.isEmpty() -> ""
           else                  -> " + "
       }
       val av = Math.abs(n)
       val coeff = if (av == 1) "" else "$av*"
       sb.append("$op${coeff}e(${i + 1})")
   }
   return if(sb.isEmpty()) "0" else sb.toString()

}

fun main(args: Array<String>) {

   val combos = arrayOf(
       intArrayOf(1, 2, 3),
       intArrayOf(0, 1, 2, 3),
       intArrayOf(1, 0, 3, 4),
       intArrayOf(1, 2, 0),
       intArrayOf(0, 0, 0),
       intArrayOf(0),
       intArrayOf(1, 1, 1),
       intArrayOf(-1, -1, -1),
       intArrayOf(-1, -2, 0, -3),
       intArrayOf(-1)
   )
   for (c in combos) {
       println("${c.contentToString().padEnd(15)}  ->  ${linearCombo(c)}")
   }

}</lang>

Output:
[1, 2, 3]        ->  e(1) + 2*e(2) + 3*e(3)
[0, 1, 2, 3]     ->  e(2) + 2*e(3) + 3*e(4)
[1, 0, 3, 4]     ->  e(1) + 3*e(3) + 4*e(4)
[1, 2, 0]        ->  e(1) + 2*e(2)
[0, 0, 0]        ->  0
[0]              ->  0
[1, 1, 1]        ->  e(1) + e(2) + e(3)
[-1, -1, -1]     ->  -e(1) - e(2) - e(3)
[-1, -2, 0, -3]  ->  -e(1) - 2*e(2) - 3*e(4)
[-1]             ->  -e(1)

Perl 6

<lang perl6>sub linear-combination(@coeff) {

   (@coeff Z=> map { "e($_)" }, 1 .. *)
   .grep(+*.key)
   .map({ .key ~ '*' ~ .value })
   .join(' + ')
   .subst('+ -', '- ', :g)
   .subst(/<|w>1\*/, , :g)
       || '0'

}

say linear-combination($_) for [1, 2, 3], [0, 1, 2, 3], [1, 0, 3, 4], [1, 2, 0], [0, 0, 0], [0], [1, 1, 1], [-1, -1, -1], [-1, -2, 0, -3], [-1 ]

</lang>
Output:
e(1) + 2*e(2) + 3*e(3)
e(2) + 2*e(3) + 3*e(4)
e(1) + 3*e(3) + 4*e(4)
e(1) + 2*e(2)
0
0
e(1) + e(2) + e(3)
-e(1) - e(2) - e(3)
-e(1) - 2*e(2) - 3*e(4)
-e(1)

Python

<lang python> def linear(x):

   return ' + '.join(['{}e({})'.format('-' if v == -1 else  if v == 1 else str(v) + '*', i + 1)
       for i, v in enumerate(x) if v] or ['0']).replace(' + -', ' - ')

list(map(lambda x: print(linear(x)), [[1, 2, 3], [0, 1, 2, 3], [1, 0, 3, 4], [1, 2, 0],

       [0, 0, 0], [0], [1, 1, 1], [-1, -1, -1], [-1, -2, 0, 3], [-1]]))

</lang>

Output:
e(1) + 2*e(2) + 3*e(3)
e(2) + 2*e(3) + 3*e(4)
e(1) + 3*e(3) + 4*e(4)
e(1) + 2*e(2)
0
0
e(1) + e(2) + e(3)
-e(1) - e(2) - e(3)
-e(1) - 2*e(2) + 3*e(4)
-e(1)

Racket

<lang racket>#lang racket/base (require racket/match racket/string)

(define (linear-combination->string es)

 (let inr ((es es) (i 1) (rv ""))
   (match* (es rv)
     [((list) "") "0"]
     [((list) rv) rv]
     [((list (? zero?) t ...) rv)
      (inr t (add1 i) rv)]
     [((list n t ...) rv)
      (define ±n
        (match* (n rv)
          ;; zero is handled above
          [(1 "") ""]
          [(1 _) "+"]
          [(-1 _) "-"]
          [((? positive? n) (not "")) (format "+~a*" n)]
          [(n _) (format "~a*" n)]))
      (inr t (add1 i) (string-append rv ±n "e("(number->string i)")"))])))

(for-each

(compose displayln linear-combination->string)
'((1 2 3)
  (0 1 2 3)
  (1 0 3 4)
  (1 2 0)
  (0 0 0)
  (0)
  (1 1 1)
  (-1 -1 -1)
  (-1 -2 0 -3)
  (-1)))

</lang>

Output:
e(1)+2*e(2)+3*e(3)
e(2)+2*e(3)+3*e(4)
e(1)+3*e(3)+4*e(4)
e(1)+2*e(2)
0
0
e(1)+e(2)+e(3)
-e(1)-e(2)-e(3)
-e(1)-2*e(2)-3*e(4)
-e(1)

REXX

<lang rexx>/*REXX program displays a finite liner combination in an infinite vector basis. */ @.=.; @.1 = '1, 2, 3'

                                 @.2  =   '0, 1, 2, 3'
                                 @.3  =   '1, 0, 3, 4'
                                 @.4  =   '1, 2, 0'
                                 @.5  =   '0, 0, 0'
                                 @.6  =    0
                                 @.7  =   '1, 1, 1'
                                 @.8  =  '-1, -1, -1'
                                 @.9  =  '-1, -2, 0, -3'
                                 @.10 =   -1
 do j=1  while  @.j\==.;             n=0        /*process each vector; zero element cnt*/
 y=space( translate(@.j, ,',') )                /*elide commas and superfluous blanks. */
 $=                                             /*nullify  output  (liner combination).*/
     do k=1  for words(y);   #=word(y, k)       /* ◄───── process each of the elements.*/
     if #=0  then iterate;   a=abs(# / 1)       /*if the value is zero, then ignore it.*/
     s='+ ';      if #<0  then s='- '           /*define the sign:  plus(+) or minus(-)*/
     n=n+1;       if n==1 then s=strip(s)       /*if the 1st element used, remove plus.*/
     if a\==1             then s=s || a'*'      /*if multiplier is unity, then ignore #*/
     $=$  s'e('k")"                             /*construct a liner combination element*/
     end   /*k*/
 $=strip( strip($), 'L', "+")                   /*strip leading plus sign (1st element)*/
 if $==  then $=0                             /*handle special case of no elements.  */
 say right( space(@.j), 20)  ' ──► '   strip($) /*align the output for presentation.   */
 end      /*j*/
                                                /*stick a fork in it,  we're all done. */</lang>

output   when using the default inputs:

             1, 2, 3  ──►  e(1) + 2*e(2) + 3*e(3)
          0, 1, 2, 3  ──►  e(2) + 2*e(3) + 3*e(4)
          1, 0, 3, 4  ──►  e(1) + 3*e(3) + 4*e(4)
             1, 2, 0  ──►  e(1) + 2*e(2)
             0, 0, 0  ──►  0
                   0  ──►  0
             1, 1, 1  ──►  e(1) + e(2) + e(3)
          -1, -1, -1  ──►  -e(1) - e(2) - e(3)
       -1, -2, 0, -3  ──►  -e(1) - 2*e(2) - 3*e(4)
                  -1  ──►  -e(1)

Ring

<lang ring>

  1. Project : Display a linear combination
  2. Date  : 2017/09/22
  3. Author  : Gal Zsolt (~ CalmoSoft ~)
  4. Email  : <calmosoft@gmail.com>

scalars = [[1, 2, 3], [0, 1, 2, 3], [1, 0, 3, 4], [1, 2, 0], [0, 0, 0], [0], [1, 1, 1], [-1, -1, -1], [-1, -2, 0, -3], [-1]] for n=1 to len(scalars)

   str = ""
   for m=1 to len(scalars[n])
       scalar = scalars[n] [m]
       if scalar != "0"
          if scalar = 1
             str = str + "+e" + m
          elseif  scalar = -1
             str = str + "" + "-e" + m
          else
             if scalar > 0
                str = str + char(43) + scalar + "*e" + m
             else
                str = str + "" + scalar + "*e" + m
             ok
          ok
       ok   
   next
   if str = ""
      str = "0"
   ok
   if left(str, 1) = "+"
      str = right(str, len(str)-1)
   ok
   see str + nl

next </lang> Output:

e1+2*e2+3*e3
e2+2*e3+3*e4
e1+3*e3+4*e4
e1+2*e2
0
0
e1+e2+e3
-e1-e2-e3
-e1-2*e2-3*e4
-e1

Sidef

Translation of: Tcl

<lang ruby>func linear_combination(coeffs) {

   var res = ""
   for e,f in (coeffs.kv) {
       given(f) {
           when (1) {
               res += "+e(#{e+1})"
           }
           when (-1) {
               res += "-e(#{e+1})"
           }
           case (.> 0) {
               res += "+#{f}*e(#{e+1})"
           }
           case (.< 0) {
               res += "#{f}*e(#{e+1})"
           }
       }
   }
   res -= /^\+/
   res || 0

}

var tests = [

   %n{1 2 3},
   %n{0 1 2 3},
   %n{1 0 3 4},
   %n{1 2 0},
   %n{0 0 0},
   %n{0},
   %n{1 1 1},
   %n{-1 -1 -1},
   %n{-1 -2 0 -3},
   %n{-1},

]

tests.each { |t|

   printf("%10s -> %-10s\n", t.join(' '), linear_combination(t))

}</lang>

Output:
     1 2 3 -> e(1)+2*e(2)+3*e(3)
   0 1 2 3 -> e(2)+2*e(3)+3*e(4)
   1 0 3 4 -> e(1)+3*e(3)+4*e(4)
     1 2 0 -> e(1)+2*e(2)
     0 0 0 -> 0         
         0 -> 0         
     1 1 1 -> e(1)+e(2)+e(3)
  -1 -1 -1 -> -e(1)-e(2)-e(3)
-1 -2 0 -3 -> -e(1)-2*e(2)-3*e(4)
        -1 -> -e(1)     

Tcl

This solution strives for legibility rather than golf.

<lang Tcl>proc lincom {factors} {

   set exp 0
   set res ""
   foreach f $factors {
       incr exp
       if {$f == 0} {
           continue
       } elseif {$f == 1} {
           append res "+e($exp)"
       } elseif {$f == -1} {
           append res "-e($exp)"
       } elseif {$f > 0} {
           append res "+$f*e($exp)"
       } else {
           append res "$f*e($exp)"
       }
   }
   if {$res eq ""} {set res 0}
   regsub {^\+} $res {} res
   return $res

}

foreach test {

   {1 2 3}
   {0 1 2 3}
   {1 0 3 4}
   {1 2 0}
   {0 0 0}
   {0}
   {1 1 1}
   {-1 -1 -1}
   {-1 -2 0 -3}
   {-1}

} {

   puts [format "%10s -> %-10s" $test [lincom $test]]

}</lang>

Output:
     1 2 3 -> e(1)+2*e(2)+3*e(3)
   0 1 2 3 -> e(2)+2*e(3)+3*e(4)
   1 0 3 4 -> e(1)+3*e(3)+4*e(4)
     1 2 0 -> e(1)+2*e(2)
     0 0 0 -> 0         
         0 -> 0         
     1 1 1 -> e(1)+e(2)+e(3)
  -1 -1 -1 -> -e(1)-e(2)-e(3)
-1 -2 0 -3 -> -e(1)-2*e(2)-3*e(4)
        -1 -> -e(1)     

zkl

Translation of: Perl 6

<lang zkl>fcn linearCombination(coeffs){

  [1..].zipWith(fcn(n,c){ if(c==0) "" else "%s*e(%s)".fmt(c,n) },coeffs)
     .filter().concat("+").replace("+-","-").replace("1*","")
  or 0

}</lang> <lang zkl>T(T(1,2,3),T(0,1,2,3),T(1,0,3,4),T(1,2,0),T(0,0,0),T(0),T(1,1,1),T(-1,-1,-1),

 T(-1,-2,0,-3),T(-1),T)

.pump(Console.println,linearCombination);</lang>

Output:
e(1)+2*e(2)+3*e(3)
e(2)+2*e(3)+3*e(4)
e(1)+3*e(3)+4*e(4)
e(1)+2*e(2)
0
0
e(1)+e(2)+e(3)
-e(1)-e(2)-e(3)
-e(1)-2*e(2)-3*e(4)
-e(1)
0