7
$\begingroup$

I have a list of expressions as follows:

as=Table[a[k],{k,1,500}]

I would like to append _?NumericQ to every element of this list and the result should look like this

{a[1]_?NumericQ,a[2]_?NumericQ,...,a[500]_?NumericQ}

Then I would like to transform this thing to

{a1_?NumericQ,a2_?NumericQ,...,a500_?NumericQ}

For this I need to be able to transform

as={a[1],...,a[500]}

to

bs={a1,...,a500}

This is needed when one needs to define functions with alot of variables such that hand typing them is not fiesable and symbolic computations are not desired.

Actually I only want to define a function with many variables as

obj[a1_?NumericQ,a2_?NumericQ,...,a500_?NumericQ]

That question is different than mine: there one has to type the variable still by hand.. I am looking for everything automized not only for $5$ elements.

$\endgroup$
3
  • $\begingroup$ @AccidentalFourierTransform maybe nothing but it doesnt solve my problem. Normally we use _?NumericQ to speed up the process just with numerical computations. If I have $500$ variables, say $a1,...,a500$, I have an objective function obj[a1_?NumericQ,a2_?NumericQ........] I want to defined this without writing $500$ terms over there... Is it possible to let the mathematica do this for me? $\endgroup$ Oct 22, 2018 at 14:49
  • $\begingroup$ I edited the question. $\endgroup$ Oct 22, 2018 at 14:59
  • $\begingroup$ Definitely check out the link in @MichaelE2's comment -- Szabolcs's answer should be a much cleaner solution. $\endgroup$
    – Chris K
    Oct 22, 2018 at 15:38

5 Answers 5

3
$\begingroup$

What about this?

With[{
 lhs = ReplacePart[
  Table[
   PatternTest[
    Pattern[Evaluate[Symbol["a" <> IntegerString[k]]], Blank[]], 
    NumericQ
    ],
   {k, 1, 500}
   ],
  0 -> obj
  ],
 rhs = 1
 },
SetDelayed[lhs, rhs]
]

The list of variables can be obtained with

Table[Symbol["a" <> IntegerString[k]], {k, 1, 500}]

But on the long run, a better strategy might be to define your function like so:

obj[a_?(VectorQ[#,NumericQ]&)] := ...

and to refer to the entries of a with Indexed[a,i] on the right hand side. (And yes, functions like FindMinimum and FindRoot can be convinced to work such functions.)

$\endgroup$
6
  • $\begingroup$ that seems great. I need to know two more things. 1. I need to get rid of the brackets of a list, because with the brackets obj[{}]:=definition does not work. 2. I also need the list {a1,a2,...,a500}. $\endgroup$ Oct 22, 2018 at 15:05
  • $\begingroup$ why is toexpression dangerous? the second one has : additionally. $\endgroup$ Oct 22, 2018 at 15:07
  • $\begingroup$ With ToExpression there is the possibility that some string with harmfull code can be injected. Notice that Mathematica has write access to your local files. For superfluous :, please see my edit. $\endgroup$ Oct 22, 2018 at 15:14
  • $\begingroup$ what is this code doing? It does not give any output. What is lhs and rhs btw? how to delete the brackets $\{$ and $\}$? $\endgroup$ Oct 22, 2018 at 15:20
  • $\begingroup$ This code defines your desired function obj. Check out ??obj. lhs is the pattern for which the rule is defined (the "function"), rhs is the expression that is supposed to be evaluated when the function is called. Here, I put rhs = 1. $\endgroup$ Oct 22, 2018 at 15:22
10
$\begingroup$

If you want to name your variables, but don't want to repeat the pattern test ?NumericQ for each variable, you can use PatternSequence:

f[PatternSequence[a1_, a2_, a3_, a4_, a5_]?NumericQ] := {a1, a1+a4, a2+a3, a5}

Check:

f[1,2,3,4,5]
f[1,2,a,4,5]

{1, 5, 5, 5}

f[1, 2, a, 4, 5]

$\endgroup$
4
$\begingroup$

Actually I only want to define a function with many variables as

obj[a1_?NumericQ,a2_?NumericQ,...,a500_?NumericQ]

In this case I think it would be much simpler to use something like

obj[vars__?NumericQ /; Length[{vars}] === 5] := Module[
    {a1, a2, a3, a4, a5},
    {a1, a2, a3, a4, a5} = {vars};
    (* do something useful here, like *)
    Total @ {a1, a2, a3, a4, a5}
] 

Now obj behave exactly as you want, but you don't have to do any voodoo with creating your definition.

In[11]:= obj[1, 2, 3, 4, 5]

Out[11]= 15

In[12]:= obj[1, 2, 3, a + 4, 5]

Out[12]= obj[1, 2, 3, 4 + a, 5]
$\endgroup$
2
$\begingroup$

To do what the OP "only wants" at the end of the question, there's this:

vs = ToExpression[
   Table["a" <> ToString[i], {i, 500}],
   StandardForm, 
   Function[v, v_?NumericQ, HoldAll]];

ClearAll[obj];
Evaluate[obj @@ vs] := a3 + 4 a450; (* substitute function body *)

obj @@ Range[500]
(*  1803  *)
$\endgroup$
1
$\begingroup$
ClearAll[f]
f[Array[With[{v = Symbol["a"<>ToString[#]]}, v_?NumericQ] &, 7, 1, Sequence]] := {a1, a5}

f @@ Range[7]

{1, 5}

f @@ (Log @ Range @ 7)

{0, Log[5]}

f @@ Range[5]

f[1, 2, 3, 4, 5]

f[foo, 2, 3, 4, 5, 6, 7]

f[foo, 2, 3, 4, 5, 6, 7]

$\endgroup$

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