<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def smp_to_ins(smp_filename,ins_filename=None,use_generic_names=False, gwutils_compliant=False, datetime_format=None,prefix=''):
 """ create an instruction file for an smp file Parameters smp_filename : str existing smp file ins_filename: str instruction file to create. If None, create an instruction file using the smp filename with the ".ins" suffix use_generic_names : bool flag to force observations names to use a generic int counter instead of trying to use a datetime str gwutils_compliant : bool flag to use instruction set that is compliant with the pest gw utils (fixed format instructions). If false, use free format (with whitespace) instruction set datetime_format : str str to pass to datetime.strptime in the smp_to_dataframe() function prefix : str a prefix to add to the front of the obsnmes. Default is '' Returns ------- df : pandas.DataFrame dataframe instance of the smp file with the observation names and instruction lines as additional columns """

    if ins_filename is None:
        ins_filename = smp_filename+".ins"
    df = smp_to_dataframe(smp_filename,datetime_format=datetime_format)
    df.loc[:,"ins_strings"] = None
    df.loc[:,"observation_names"] = None
    name_groups = df.groupby("name").groups
    for name,idxs in name_groups.items():
        if not use_generic_names and len(name) <= 11:
            onames = df.loc[idxs,"datetime"].apply(lambda x: prefix+name+'_'+x.strftime("%d%m%Y")).values
        else:
            onames = [prefix+name+"_{0:d}".format(i) for i in range(len(idxs))]
        if False in (map(lambda x :len(x) <= 20,onames)):
            long_names = [oname for oname in onames if len(oname) > 20]
            raise Exception("observation names longer than 20 chars:\n{0}".format(str(long_names)))
        if gwutils_compliant:
            ins_strs = ["l1  ({0:s})39:46".format(on) for on in onames]
        else:
            ins_strs = ["l1 w w w  !{0:s}!".format(on) for on in onames]
        df.loc[idxs,"observation_names"] = onames
        df.loc[idxs,"ins_strings"] = ins_strs

    counts = df.observation_names.value_counts()
    dup_sites = [name for name in counts.index if counts[name] > 1]
    if len(dup_sites) > 0:
        raise Exception("duplicate observation names found:{0}"\
                        .format(','.join(dup_sites)))

    with open(ins_filename,'w') as f:
        f.write("pif ~\n")
        [f.write(ins_str+"\n") for ins_str in df.loc[:,"ins_strings"]]
    return df